방법: CComPtr 및 CComQIPtr 인스턴스 만들기 및 사용

클래식 Windows 프로그래밍에서 라이브러리는 종종 COM 개체(보다 정확하게는 COM 서버)로 구현됩니다. 많은 Windows 운영 체제 구성 요소가 COM 서버로 구현되므로 많은 참가자가 이 형식의 라이브러리를 제공합니다. COM의 기본 사항에 대한 자세한 내용은 Component Object Model (COM)을 참조하세요.

COM(구성 요소 개체 모델) 개체를 인스턴스화할 때 소멸자에서 AddRefRelease 에 대한 호출을 사용하여 참조 계산을 수행하는 COM 스마트 포인터에 인터페이스 포인터를 저장합니다. ATL(액티브 템플릿 라이브러리) 또는 MFC 라이브러리를 사용하는 경우 CComPtr 스마트 포인터를 사용합니다. ATL 또는 MFC를 사용하지 않는 경우에는 _com_ptr_t를 사용합니다. std::unique_ptr에 해당하는 COM이 없기 때문에 단일 소유자 시나리오와 여러 소유자 시나리오 모두에 이러한 스마트 포인터를 사용합니다. CComPtrComQIPtr 둘 다 rvalue 참조가 있는 이동 작업을 지원합니다.

예: CComPtr

다음 예제에서는 CComPtr 을 사용하여 COM 개체를 인스턴스화하고 해당 인터페이스에 대한 포인터를 가져오는 방법을 보여 줍니다. CComPtr::CoCreateInstance 멤버 함수는 이름이 같은 Win32 함수 대신 COM 개체를 만드는 데 사용됩니다.

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은 COM 개체를 쿼리하여 추가 인터페이스를 검색할 수 있도록 보다 간단한 구문이 있는 CComQIPtr을 제공합니다. 그러나 CComPtr 에서 수행할 수 있는 모든 작업을 수행하고 원시 COM 인터페이스 포인터와 의미 체계가 보다 일치하므로 CComQIPtr 을 사용하는 것이 좋습니다. CComPtr 를 사용하여 인터페이스를 쿼리하는 경우 out 매개 변수에 새 인터페이스 포인터가 배치됩니다. 호출에 실패한 경우 일반적인 COM 패턴인 HRESULT가 반환됩니다. 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*/ }

예: IDispatch

CComPtr 은 COM 자동화 구성 요소에 대한 포인터를 저장하고 런타임에 바인딩을 사용하여 인터페이스에서 메서드를 호출할 수 있도록 하는 IDispatch 특수화를 제공합니다. CComDispatchDriver 는 암시적으로 CComQIPtr<IDispatch, &IIDIDispatch>로 변환할 수 있는 CComPtr<IDispatch>에 대한 typedef입니다. 따라서 이 세 가지 이름 중 하나가 코드에 표시되면 이는 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++)