我是托管/非托管互操作的新手,所以我希望得到一些意见,了解以下过程对于从非托管C ++到托管C#获取位图的安全性。基本思路是:
FetchImage
,它位于非托管C ++中。它传递out int
参数。 FetchImage
有相应的long *
参数。FetchImage
创建一个安全的CBitmap
,即不是本地的,在其上绘制内容,使用HandleToLong()
将位图的HBITMAP
句柄转换为{{ 1}},将其存储在C#的参数中,然后返回。long
参数转换为out int
并使用IntPtr
复制数据并生成System.Drawing.Image.FromHbitmap
个对象。System.Drawing.Bitmap
。ReleaseImage
释放与之前创建的ReleaseImage
相关联的资源。这是不耐烦的要点。下面是更具体的代码示例。
函数的C ++互操作定义:
CBitmap
interop函数的IDL原型,它们包装在C#中的辅助类中:
namespace {
std::unique_ptr< CBitmap > 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;
}
在帮助程序类中生成这些C#原型:
[id(1)] HRESULT FetchImage( long * hBitmap );
[id(2)] HRESULT ReleaseImage();
调用它们的C#看起来像这样:
void FetchImage( out int hBitmap );
void ReleaseImage();
我自己提出的唯一问题是来自其他地方的int ret;
helper.FetchImage( out ret );
Bitmap b = Image.FromHbitmap( (IntPtr)ret );
helper.ReleaseImage();
// do anything I want with b
或FetchImage
来电,导致事情不同步。所以我可能会有一个ReleaseImage
的列表而不是一个,然后将句柄传递回CBitmap
,这样它只会破坏匹配的ReleaseImage
调用中的一个。{ / p>
有没有我不知道的陷阱?我确实有这个工作,我只是想确保我没有做一些危险的事情,因为我不知道更好。
答案 0 :(得分:1)
您可以声明释放HBITMAP是调用者的责任。这将简化您的C ++代码,因为您可以删除ReleaseImage方法。例如:
HRESULT __stdcall Helper::FetchImage( /*[out]*/ HBITMAP * hBitmap )
{
*hBitmap = NULL; // assume failure
unique_ptr<CBitmap> 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
}
或者,您可以尝试使用IPicture返回OleCreatePictureIndirect。这提供了一些优势: