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)
可以使用ComPtr的As或CopyTo函数来获取新接口,这里以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
可以使用ComPtr的Reset()函数
或者直接设置为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