如何:创建和使用CComPtr和CComQIPtr实例
在传统 Windows 编程中,库通常实现为 COM 对象 (或更确切地说,作为 COM 服务器)。许多 Windows 操作系统组件作为 COM 服务器和多个参与者提供此窗体中的库。COM 的基本信息,请参阅Component Object Model (COM)。
当实例化组件对象模型 (COM) 对象时,将接口指针存储在 COM 智能指针,它执行引用计数通过调用AddRef和Release在析构函数中。如果您使用活动模板库 (ATL) 或 Microsoft 基础类库 (MFC),然后使用CComPtr智能指针。如果您不使用 ATL 或 MFC,则请使用**_com_ptr_t**。因为没有任何 COM 等效于std::unique_ptr,单所有者和多个所有者方案中使用这些智能指针。两个CComPtr和ComQIPtr支持移动具有 rvalue 引用的操作。
示例
下面的示例演示如何使用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为查询接口时,新的接口指针放在输出参数中。如果调用失败,则返回 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();
}