Como: criar e usar CComPtr e instâncias de CComQIPtr
Na programação clássica do Windows, bibliotecas geralmente são implementadas como objetos COM (ou mais precisamente, como servidores COM).Muitos componentes do sistema operacional Windows são implementados como servidores COM e muitos colaboradores fornecem bibliotecas neste formulário.Para informações sobre os fundamentos de COM, consulte Component Object Model (COM).
Ao instanciar um objeto de modelo de objeto componente (COM), armazenar o ponteiro de interface em um ponteiro inteligente COM, realiza a referência de contagem usando chamadas para AddRef e Release no destruidor.Se você estiver usando o Active Template Library (ATL) ou o Microsoft Foundation Class Library (MFC), use o CComPtr ponteiro inteligente.Se você não estiver usando ATL ou MFC, use _com_ptr_t.Porque não há nenhum COM equivalente a std::unique_ptr, use esses ponteiros inteligentes para único proprietário e o proprietário de vários cenários.Ambos CComPtr e ComQIPtr suporte mover operações têm referências de rvalue.
Exemplo
O exemplo a seguir mostra como usar CComPtr para instanciar um objeto COM e obter ponteiros para interfaces.Observe que o CComPtr::CoCreateInstance função de membro é usada para criar o objeto COM, em vez da função 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.
}
CComPtre seus parentes fazem parte do ATL e são definidos no atlcomcli.h._com_ptr_té declarado em comip.h.O compilador cria especializações de _com_ptr_t quando ele gera classes de wrapper de bibliotecas de tipo.
ATL também oferece CComQIPtr, que tem uma sintaxe simples para consultar um objeto COM uma interface adicional de recuperar.No entanto, recomendamos CComPtr porque ele faz tudo que CComQIPtr pode fazer e é semanticamente mais consistente com ponteiros de interface COM raw.Se você usar um CComPtr para consultar uma interface, o novo ponteiro de interface é colocado em um parâmetro de saída.Se a chamada falhar, um HRESULT é retornado, o que é o padrão típico de COM.Com CComQIPtr, o valor de retorno é o ponteiro de si mesmo e se a chamada falhar, o valor de retorno HRESULT interno não pode ser acessado.As duas seguintes linhas mostrar como mecanismos de manipulação de erros CComPtr e 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*/ }
CComPtrFornece uma especialização de IDispatch permite armazenar ponteiros para os componentes de automação COM e chamar métodos na interface usando ligação tardia.CComDispatchDriveré um typedef para CComQIPtr<IDispatch, &IIDIDispatch>, que é implicitamente conversível no CComPtr<IDispatch>.Portanto, quando qualquer um desses três nomes aparece 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 um 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();
}