Como criar e usar instâncias CComPtr e CComQIPtr
No windows clássicas de programação, as bibliotecas são implementadas frequentemente como objetos COM (ou mais precisamente, como servidores COM). Muitos componentes do sistema operacional Windows são implementados como servidores COM, e muitos contribuinte fornecem bibliotecas neste formulário. Para obter informações sobre os fundamentos do, consulte Component Object Model (COM).
Quando você cria uma instância de um objeto do Component Object Model (COM), armazene o ponteiro de interface em um ponteiro inteligente COM, que executa a contagem de referência usando chamadas a AddRef e a Release em destruidor. Se você estiver usando a biblioteca ativa (ATL) do modelo ou da biblioteca de classes do Microsoft (MFC), use o ponteiro de CComPtr inteligente. Se você não estiver usando ATL ou MFC, use _com_ptr_t. Como não há nenhum equivalente de COM a std::unique_ptr, use esses ponteiros inteligente para cenários de proprietário único e de vários proprietário. CComPtr e o suporte de ComQIPtr move as operações que têm referências de rvalue.
Exemplo
O exemplo a seguir mostra como usar CComPtr para criar uma instância de um objeto COM e para obter ponteiros para suas interfaces. Observe que a função de membro de CComPtr::CoCreateInstance é usada para criar o objeto COM, em vez da função do Win32 que tem o mesmo nome.
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 e seus parentes fazem parte do ATL e são definidos em atlcomcli.h. _com_ptr_t for declarado em comip.h. O compilador cria especializações de _com_ptr_t quando gerencia classes wrapper para bibliotecas do tipo.
ATL também fornece CComQIPtr, que tem uma sintaxe mais simples para consultar um objeto COM para recuperar uma interface adicional. No entanto, recomendamos CComPtr porque torna tudo que CComQIPtr pode fazer e é semanticamente mais consistente com os ponteiros brutos da interface COM. Se você usar CComPtr para consultar uma interface, o ponteiro da interface é colocado em um parâmetro de saída. Se houver falha na chamada, um HRESULT será retornado, que é típico COM o padrão de. Com CComQIPtr, o valor de retorno é o ponteiro próprio, e se houver falha na chamada, o valor de retorno de HRESULT interno não pode ser acessado. As duas linhas seguintes mostram como os mecanismos de tratamento de erros em CComPtr e em CComQIPtr diferem.
// 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 fornece uma especialização para IDispatch que a habilita para armazenar ponteiros para os componentes de automação COM e para invocar os métodos da interface usando a associação tardia. CComDispatchDriver é um typedef para CComQIPtr<IDispatch, &IIDIDispatch>, que é convertido implicitamente em CComPtr<IDispatch>. Em virtude disso, quando algum desses três nomes aparecerão no código, é equivalente a CComPtr<IDispatch>. O exemplo a seguir mostra como obter um ponteiro para o modelo de objeto do Microsoft Word usando 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();
}