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();
}