方法: CComPtr および CComQIPtr インスタンスを作成して使用する

従来の Windows プログラミングでは、ライブラリは、多くの場合、COM オブジェクトとして (厳密には COM サーバーとして) 実装されます。 多くの Windows オペレーティング システム コンポーネントは COM サーバーとして実装されており、多くの共同作成者からこの形式のライブラリが提供されています。 COM の詳細については、「 Component Object Model (COM)」を参照してください。

コンポーネント オブジェクト モデル (COM) オブジェクトをインスタンス化するときは、デストラクターの AddRefRelease の呼び出しを使用して参照のカウントを実行する COM スマート ポインターにインターフェイス ポインターを格納します。 Active Template Library (ATL) または Microsoft Foundation Class ライブラリ (MFC) を使用している場合は、 CComPtr スマート ポインターを使用します。 ATL または MFC を使用していない場合は、 _com_ptr_tを使用します。 COM には std::unique_ptrに相当するものがないため、これらのスマート ポインターを単一所有者のシナリオと複数所有者のシナリオの両方に使用します。 CComPtrComQIPtr のどちらも、右辺値参照が含まれる移動操作をサポートしています。

例: CComPtr

次の例は、 CComPtr を使用して COM オブジェクトをインスタンス化し、そのインターフェイスへのポインターを取得する方法を示しています。 COM オブジェクトを作成するために CComPtr::CoCreateInstance メンバー関数が使用されている点に注意してください (同じ名前を持つ 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 の特殊化を作成します。

例: CComQIPt

ATL では、よりシンプルな構文を持つ CComQIPtrも提供されます。これを使用して COM オブジェクトに対するクエリを実行して、追加のインターフェイスを取得できます。 ただし、 CComPtr で実行できることのすべてを実行可能であるうえ、未加工の COM インターフェイス ポインターとセマンティクス的により整合性の高い CComQIPtr をお勧めします。 CComPtr を使用してインターフェイスを照会すると、新しいインターフェイス ポインターが出力パラメーターに配置されます。 呼び出しが失敗した場合、HRESULT が返されます。これは、COM の一般的なパターンです。 CComQIPtrの場合、戻り値はポインター自体です。呼び出しが失敗した場合、内部 HRESULT 戻り値にはアクセスできません。 次の 2 つの行から、 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*/ }

例: IDispatch

CComPtr では、IDispatch の特殊化を提供して、COM オートメーション コンポーネントへのポインターを格納し、遅延バインディングを使用してインターフェイスのメソッドを呼び出すことができるようにしています。 CComDispatchDriverCComQIPtr<IDispatch, &IIDIDispatch>の typedef であり、 CComPtr<IDispatch>に暗黙的に変換可能です。 したがって、これらの 3 つの名前のいずれかがコードに使用されている場合、そのコードは 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();
}

関連項目

スマート ポインター (Modern C++)