如何:建立和使用 CComPtr 和 CComQIPtr 執行個體
在傳統的 Windows 程式設計,程式庫通常是實作為 COM 物件 (或更明確地說,為 COM 伺服器)。 許多 Windows 作業系統元件會實作為 COM 伺服器,因此,許多參與者提供這種形式的程式庫。 如需有關基礎 COM 的資訊,請參閱 Component Object Model (COM)。
當您具現化元件物件模型 (COM) 物件時,請將介面指標存放於 COM 智慧型指標,它使用 AddRef 和 Release 呼叫在解構函式執行參考計算。 如果您使用 Active Template Library (ATL) 或 MFC 程式庫,則使用 CComPtr 智慧型指標。 如果您不使用 ATL 或 MFC,則使用 _com_ptr_t。 由於沒有 COM 相當於 std::unique_ptr,為單一擁有者和多擁有者案例中使用這些智慧型指標。 CComPtr 和 ComQIPtr 對有右值的參考支援 MOVE 作業。
範例
下列範例示範如何使用 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 提供能夠儲存指標到 COM Automation 元件並藉由使用晚期繫結 (Late Binding) 叫用方法的特製化 IDispatch。 CComDispatchDriver 是 **CComQIPtr<IDispatch, &IIDIDispatch>**的 typedef,它可以隱含地轉換為 CComPtr<IDispatch>。 因此,當這三個任何一方出現在程式碼中,它相當於 CComPtr<IDispatch>。 下列範例顯示如何使用 CComPtr<IDispatch> 取得指標到 Microsoft Word 物件模型。
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();
}