[英]Safety of passing HBITMAP handle from unmanaged to managed code for created a System.Drawing.Bitmap
I'm pretty new to managed/unmanaged interop, so I'm looking to get some opinions on how safe the following procedure is for getting a bitmap from unmanaged C++ to managed C#. 我对托管/非托管互操作还很陌生,因此我希望就以下过程将位图从非托管C ++转换为托管C#的安全性获得一些意见。 The basic idea is: 基本思想是:
FetchImage
, which is in the unmanaged C++. C#调用非托管C ++中的互操作函数FetchImage
。 It passes an out int
param. 它传递out int
参数。 FetchImage
has a corresponding long *
param. FetchImage
具有相应的long *
参数。 FetchImage
creates a CBitmap
somewhere safe, ie not local, draws something on it, uses HandleToLong()
to convert the bitmap's HBITMAP
handle to a long
, stores it in the param for the C#, and returns. 在C ++中, FetchImage
在安全的地方(即不在本地)创建一个CBitmap
,在其上绘制一些东西,使用HandleToLong()
将位图的HBITMAP
句柄转换为long
,将其存储在C#的参数中,然后返回。 out int
param is converted to an IntPtr
and uses System.Drawing.Image.FromHbitmap
to copy the data and produce a System.Drawing.Bitmap
object. 回到C#中,将out int
参数转换为IntPtr
并使用System.Drawing.Image.FromHbitmap
复制数据并生成System.Drawing.Bitmap
对象。 ReleaseImage
. 然后,C#调用另一个互操作函数ReleaseImage
。 ReleaseImage
frees the resources associated with the CBitmap
it created earlier. 在C ++中, ReleaseImage
释放与其早先创建的CBitmap
关联的资源。 That's the gist for the impatient. 那是不耐烦的要旨。 More specific code examples below. 下面是更具体的代码示例。
C++ interop definitions for the functions: 函数的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;
}
IDL prototypes for the interop functions, which are wrapped in a helper class in C#: 用于互操作函数的IDL原型,包装在C#的帮助器类中:
[id(1)] HRESULT FetchImage( long * hBitmap );
[id(2)] HRESULT ReleaseImage();
Produces these C# prototypes in the helper class: 在助手类中生成以下C#原型:
void FetchImage( out int hBitmap );
void ReleaseImage();
And the C# that calls them looks kind of like this: 调用它们的C#看起来像这样:
int ret;
helper.FetchImage( out ret );
Bitmap b = Image.FromHbitmap( (IntPtr)ret );
helper.ReleaseImage();
// do anything I want with b
The only issue I've come up with on my own is the case of a call to FetchImage
or ReleaseImage
from somewhere else getting things out of sync. 我自己想到的唯一问题是从其他地方调用FetchImage
或ReleaseImage
情况不同步的情况。 So I'll probably have a list of CBitmap
s instead of just one, then pass the handle back to ReleaseImage
so it'll only destroy the one from the matching FetchImage
call. 因此,我可能会有一个CBitmap
列表,而不是一个列表,然后将句柄传递回ReleaseImage
这样它只会从匹配的FetchImage
调用中销毁一个。
Are there any gotchas I'm not aware of? 有我不知道的陷阱吗? I do have this working, I just wanted to make sure I'm not doing something dangerous because I don't know any better. 我确实有这项工作,我只是想确保自己没有做任何危险的事情,因为我不知道更好。
You could just declare that it is the caller's responsibility to free the HBITMAP. 您可以只声明释放HBITMAP是呼叫者的责任。 That would simplify your C++ code since you could remove the ReleaseImage method. 这样可以简化C ++代码,因为您可以删除ReleaseImage方法。 Example: 例:
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
}
Alternatively, you could look into returning an IPicture using OleCreatePictureIndirect . 另外,您可以考虑使用OleCreatePictureIndirect返回IPicture 。 That provides some advantages: 这提供了一些优点:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.