将HBITMAP句柄从非托管代码传递到托管代码的安全性,以便创建System.Drawing.Bitmap
我是托管/非托管互操作的新手,所以我希望得到一些意见,了解以下过程如何安全地从非托管C ++到托管C#获取位图。 基本思路是:
- C#调用一个互操作函数
FetchImage
,它位于非托管C ++中。 它通过一个out int
param。FetchImage
有一个相应的long *
param。 - 在C ++中,
FetchImage
创建一个安全的CBitmap
,即不是本地的,在其上绘制内容,使用HandleToLong()
将位图的HBITMAP
句柄转换为long
,将其存储在C#的参数中,然后返回。 - 回到C#,
out int
param转换为IntPtr
并使用System.Drawing.Image.FromHbitmap
复制数据并生成System.Drawing.Bitmap
对象。 - 然后C#调用另一个互操作函数
ReleaseImage
。 - 在C ++中,
ReleaseImage
释放与之前创建的CBitmap
相关联的资源。
这是不耐烦的要点。 下面是更具体的代码示例。
函数的C ++互操作定义:
namespace { std::unique_ptr bitty; } HRESULT __stdcall Helper::FetchImage( /*[out]*/ long * hBitmap ) { bitty.reset( new CBitmap ); // call CreateBitmap and then draw something, // ensure it's not selected into a DC when done *hBitmap = HandleToLong( bitty->GetSafeHandle() ); return S_OK; } HRESULT __stdcall Helper::ReleaseImage() { bitty.reset(); return S_OK; }
用于互操作函数的IDL原型,它们包装在C#中的辅助类中:
[id(1)] HRESULT FetchImage( long * hBitmap ); [id(2)] HRESULT ReleaseImage();
在helper类中生成这些C#原型:
void FetchImage( out int hBitmap ); void ReleaseImage();
调用它们的C#看起来像这样:
int ret; helper.FetchImage( out ret ); Bitmap b = Image.FromHbitmap( (IntPtr)ret ); helper.ReleaseImage(); // do anything I want with b
我自己提出的唯一问题是从其他地方调用FetchImage
或ReleaseImage
使得事情不同步。 所以我可能会有一个CBitmap
列表而不是一个,然后将句柄传递给ReleaseImage
这样它只会破坏匹配的FetchImage
调用中的一个。
有没有我不知道的陷阱? 我确实有这个工作,我只是想确保我没有做一些危险的事情因为我不知道更好。
您可以声明调用者有责任释放HBITMAP。 这将简化您的C ++代码,因为您可以删除ReleaseImage方法。 例:
HRESULT __stdcall Helper::FetchImage( /*[out]*/ HBITMAP * hBitmap ) { *hBitmap = NULL; // assume failure unique_ptr bmp(new CBitmap); // call CreateBitmap and then draw something, // ensure it's not selected into a DC when done *hBitmap = (HBITMAP)bmp->Detach(); return S_OK; } // Delete ReleaseImage and all supporting global variables... // C# example: IntPtr ret; helper.FetchImage( out ret ); try { Bitmap b = Image.FromHbitmap( ret ); } finally { DeleteObject(ret); // pinvoke call into GDI }
或者,您可以考虑使用OleCreatePictureIndirect返回IPicture 。 这提供了一些优点:
- 调用者使用标准COM引用计数释放返回的图像。 这通常使调用者不必担心释放返回的图像(除非调用者是另一个需要手动调用IUnknown :: Release的C ++程序)。
- 与其他支持COM的语言(如VBA / VB6)的兼容性更好。 IPicture是在COM中传递图片的标准方式。
- 使用指针参数(WCT)从C#调用C ++方法
- C ++ dll的C#包装器; “运行时检查失败#0 – ESP的值未在函数调用中正确保存。”错误
- 如何在Windows Phone 8.1 / Windows 8.1中为http客户端请求操作设置超时
- 如何检查Windows 10移动模拟器的独立存储?
- 如何将带有unsigned char *的struct从C#传递给C ++?
- 将日期参数传递给对MVC操作的ajax调用的安全方法
- 在onclientclick中将变量传递给javascript
- 如何在Windows Phone 7中检查3G,wifi,EDGE,蜂窝网络?
- BackgroundTask UWP Windows 10 TimeTriggeredTask示例已注册但从未激活