How to: 建立和使用 CComPtr 和 CComQIPtr 執行個體
在傳統 Windows 程式設計中,為 COM 物件 (或函數,為 COM 伺服器),通常會實作程式庫。許多 Windows 作業系統元件會實作為 COM 伺服器,並且許多參與者提供這種形式的文件庫。COM 的基本概念的相關資訊,請參閱Component Object Model (COM)。
當您具現化元件物件模型 (COM) 物件時,可將介面指標儲存在 COM 智慧型指標,會執行參考計數藉由呼叫AddRef和Release解構函式中。如果您正在使用使用中的樣板程式庫 (ATL) 或程式庫 (MFC),則請使用CComPtr的智慧型指標。如果您不使用 ATL 或 MFC,則請使用**_com_ptr_t**。因為沒有任何 COM 相當於std::unique_ptr,單一擁有者和多個擁有者的情況下使用這些智慧型指標。兩者都CComPtr和ComQIPtr支援移動有右值參考的作業。
範例
下列範例示範如何使用CComPtr ,COM 物件具現化,並取得其介面指標。請注意, CComPtr::CoCreateInstance成員函式用來建立 COM 物件,而非 Win32 函式具有相同的名稱。
void CComPtrDemo()
{
HRESULT hr = CoInitialize(NULL);
// Declare the smart pointer.
CComPtr<IGraphBuilder> pGraph;
// Use its member function CoCreateInstance to
// create the COM object and obtain the IGraphBuilder pointer.
hr = pGraph.CoCreateInstance(CLSID_FilterGraph);
if(FAILED(hr)){ /*... handle hr error*/ }
// Use the overloaded -> operator to call the interface methods.
hr = pGraph->RenderFile(L"C:\\Users\\Public\\Music\\Sample Music\\Sleep Away.mp3", NULL);
if(FAILED(hr)){ /*... handle hr error*/ }
// Declare a second smart pointer and use it to
// obtain another interface from the object.
CComPtr<IMediaControl> pControl;
hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl));
if(FAILED(hr)){ /*... handle hr error*/ }
// Obtain a third interface.
CComPtr<IMediaEvent> pEvent;
hr = pGraph->QueryInterface(IID_PPV_ARGS(&pEvent));
if(FAILED(hr)){ /*... handle hr error*/ }
// Use the second interface.
hr = pControl->Run();
if(FAILED(hr)){ /*... handle hr error*/ }
// Use the third interface.
long evCode = 0;
pEvent->WaitForCompletion(INFINITE, &evCode);
CoUninitialize();
// Let the smart pointers do all reference counting.
}
CComPtr及其親戚屬於 ATL 和 atlcomcli.h 中所定義。_com_ptr_t在 comip.h 中宣告。編譯器會建立特製化的**_com_ptr_t**就會產生型別程式庫的包裝函式類別。
ATL 也提供CComQIPtr,其中有更簡單的查詢抓取其他介面的 COM 物件的語法。然而,我們建議您CComPtr但並非所有項目,因為CComQIPtr辦得到,並使用一般 COM 介面指標語意上更具一致性。如果您使用CComPtr來查詢介面時,新的介面指標置於 out 參數。如果呼叫失敗,便會傳回 HRESULT,也就是典型的 COM 模式。與CComQIPtr、 傳回值是指標本身,以及如果呼叫失敗,無法存取內部的 HRESULT 傳回值。以下兩個線條的顯示方式的錯誤處理機制,在CComPtr和CComQIPtr不同。
// CComPtr with error handling:
CComPtr<IMediaControl> pControl;
hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl));
if(FAILED(hr)){ /*... handle hr error*/ }
// CComQIPtr with error handling
CComQIPtr<IMediaEvent> pEvent = pControl;
if(!pEvent){ /*... handle NULL pointer error*/ }
// Use the second interface.
hr = pControl->Run();
if(FAILED(hr)){ /*... handle hr error*/ }
CComPtr提供特製化 IDispatch,讓它可以儲存指標 COM 自動化元件,並使用晚期繫結來叫用的介面上的方法。CComDispatchDriver是的 typedef CComQIPtr<IDispatch, &IIDIDispatch>,也就是隱含轉換成CComPtr<IDispatch>。因此,當任何這些三個名稱出現在程式碼,它相當於CComPtr<IDispatch>。下列範例顯示如何取得變數的指標,Microsoft Word 物件模型使用CComPtr<IDispatch>。
void COMAutomationSmartPointerDemo()
{
CComPtr<IDispatch> pWord;
CComQIPtr<IDispatch, &IID_IDispatch> pqi = pWord;
CComDispatchDriver pDriver = pqi;
HRESULT hr;
_variant_t pOutVal;
CoInitialize(NULL);
hr = pWord.CoCreateInstance(L"Word.Application", NULL, CLSCTX_LOCAL_SERVER);
if(FAILED(hr)){ /*... handle hr error*/ }
// Make Word visible.
hr = pWord.PutPropertyByName(_bstr_t("Visible"), &_variant_t(1));
if(FAILED(hr)){ /*... handle hr error*/ }
// Get the Documents collection and store it in new CComPtr
hr = pWord.GetPropertyByName(_bstr_t("Documents"), &pOutVal);
if(FAILED(hr)){ /*... handle hr error*/ }
CComPtr<IDispatch> pDocuments = pOutVal.pdispVal;
// Use Documents to open a document
hr = pDocuments.Invoke1 (_bstr_t("Open"), &_variant_t("c:\\users\\public\\documents\\sometext.txt"),&pOutVal);
if(FAILED(hr)){ /*... handle hr error*/ }
CoUninitialize();
}