如何:创建和使用 CComPtr 和 CComQIPtr 实例

在经典编程中,库实现通常,当 COM 对象 (或精确,作为 COM 服务器)。 很多 Windows 操作系统组件中实现的 COM 服务器,因此,许多参与者提供库以此形式。 有关如何安装 Component Object Model (COM) 的信息,请参见 。

在实例化组件对象模型 (COM) 对象时 (COM) 中,存储在用户的指针的 COM 接口的指针,请在析构函数执行计数来调用的引用。AddRefRelease。 如果使用活动模板库 (ATL) (ATL) 或 Microsoft 基础类库 (MFC),请使用 CComPtr、聪明指针。 如果不使用 MFC 或 ATL,请使用 _com_ptr_t。 由于 COM 不等效于 std::unique_ptr,对于单所有者和多个所有者方案中使用这些智能的指针。 CComPtrComQIPtr 支持移动具有 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,内部返回值无法访问。 以下两行显示在 CComPtrCComQIPtr 中的错误处理机制之间的差异。

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

请参见

概念

智能指针(现代 C++)