COM智能指针ComPtr的介绍以及使用

ComPtr介绍

ComPtr是为COM而设计的智能指针。它支持WindowsRT,也支持传统Win32。相比ATL里的CComPtr类,它有了一些提升。ComPtr会自动维护基础接口指针的引用计数,并在参考计数为零时释放接口,从而消除内存泄漏。

ComPtr包含在Windows 8.x SDK and Windows 10 SDK,

如果是Windows7系统,需要下载Windows7.1 SDK

下载地址

https://www.microsoft.com/en-us/download/details.aspx?id=8442

 

头文件和命名空间

需要包含 <wrl/client.h>

引用 using Microsoft::WRL::ComPtr;

 

如何使用

这里以IFileOpenDialog为例进行演示

ComPtr提供一个Get()函数,可以检索指向与此 ComPtr 相关联的接口。

 1 HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED |
 2     COINIT_DISABLE_OLE1DDE);
 3 
 4 Microsoft::WRL::ComPtr<IFileOpenDialog> m_pFileDialog;
 5 hr = CoCreateInstance(
 6     __uuidof(FileOpenDialog),
 7     NULL,
 8     CLSCTX_INPROC_SERVER,
 9     IID_PPV_ARGS(&m_pFileDialog)
10 );
11 auto rt = m_pFileDialog.Get();
12 rt->Show(NULL);

使用智能指针后,不需要再调用Release()进行释放,关于详细的引用计数,可以访问文末参考资料里的链接进行了解。

 

获取新接口(QueryInterface)

可以使用ComPtrAsCopyTo函数来获取新接口,这里以WIC组件为例进行演示

 1 #include <iostream>
 2 #include<Windows.h>
 3 #include<ShlObj_core.h>
 4 #include<wrl/client.h>
 5 #include<atlbase.h>
 6 #include<wincodec.h>
 7 
 8 int main()
 9 {
10 
11     HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED |
12         COINIT_DISABLE_OLE1DDE);
13 
14     Microsoft::WRL::ComPtr<IWICImagingFactory> m_pIWICFactory;
15 
16     hr = CoCreateInstance(
17         CLSID_WICImagingFactory,
18         NULL,
19         CLSCTX_INPROC_SERVER,
20         IID_PPV_ARGS(&m_pIWICFactory)
21     );
22 
23     if (FAILED(hr))
24         return 0;
25 
26     Microsoft::WRL::ComPtr<IWICBitmapDecoder> pDecoder;
27 
28     hr = m_pIWICFactory->CreateDecoderFromFilename(
29         L"explorer_back.png",            // Image to be decoded
30         NULL,                            // Do not prefer a particular vendor
31         GENERIC_READ,                    // Desired read access to the file
32         WICDecodeMetadataCacheOnDemand,  // Cache metadata when needed
33         &pDecoder                        // Pointer to the decoder
34     );
35 
36     Microsoft::WRL::ComPtr<IWICBitmapFrameDecode> pFrame;
37 
38     // Retrieve the first frame of the image from the decoder
39     if (SUCCEEDED(hr))
40     {
41         hr = pDecoder->GetFrame(0, &pFrame);
42     }
43 
44     Microsoft::WRL::ComPtr<IWICBitmapSource> m_pOriginalBitmapSource;
45     // Retrieve IWICBitmapSource from the frame
46     if (SUCCEEDED(hr))
47     {
48         //ComPtr provides a much simpler syntax for doing QueryInterface calls on COM Objects
49         //You can also use CopyTo to perform similar operations to As.     
50         hr = pFrame.As(&m_pOriginalBitmapSource);
51 
52         //QueryInterface
53         /*
54         *  hr = pFrame->QueryInterface(
55         *        IID_IWICBitmapSource, 
56         *        reinterpret_cast<void **>(&m_pOriginalBitmapSource));
57         */
58 
59         //...
60     }
61     return 0;
62 }

 

 

清空ComPtr

可以使用ComPtrReset()函数

或者直接设置为nullptr

如下所示

1  //Clearing
2  m_pFileDialog.Reset(); //or m_pFileDialog = nullptr;

 

判断是否为空

与许多智能指针一样,ComPtr有一个运算符bool重载,可以很方便检查ComPtr当前是否设置为null,如下所示:

 1 ComPtr<ID3D11Debug> d3dDebug;
 2 
 3 ...
 4 
 5 if ( !d3dDebug )
 6     {
 7         d3dDebug is null
 8     }
 9 ...
10 assert( d3dDebug ); // trigger error if d3dDebug is null

 

其它注意事项

1、在C++/WinRT 项目中,应该使用winrt::com_ptr 而不是 Microsoft::WRL:ComPtr,可以查看Microsoft Docs.

2、开启了/clr支持的托管C++是不能使用WRL的,这时候可以使用ATL里面的CComPtr,原理和ComPtr一样,使用方法有一点小区别,可以查看Microsoft Docs.

3、本文只介绍了ComPtr的基础使用,如果想了解得更深入一点,可以访问参考链接里的文章。

 

示例代码

 

参考链接:

ComPtr wiki

https://github.com/Microsoft/DirectXTK/wiki/ComPtr

https://learn.microsoft.com/en-us/cpp/cppcx/wrl/comptr-class?view=msvc-170

why-dont-modern-smart-pointers-implicitly-convert-to

https://herbsutter.com/2012/06/21/reader-qa-why-dont-modern-smart-pointers-implicitly-convert-to/

ComPtrExamples

https://cpp.hotexamples.com/examples/microsoft.wrl/ComPtr/-/cpp-comptr-class-examples.html

ComSmartPointer

https://learn.microsoft.com/en-us/windows/win32/LearnWin32/com-coding-practices#com-smart-pointers

posted @ 2019-09-02 18:24  zhaotianff  阅读(2333)  评论(0编辑  收藏  举报