将HBITMAP句柄从非托管代码传递到托管代码的安全性创建了一个System.Drawing.Bitmap [英] Safety of passing HBITMAP handle from unmanaged to managed code for created a System.Drawing.Bitmap
问题描述
我对管理/非托管互操作是新的,所以我想得到一些意见,如何安全的以下程序是从非托管C ++到管理C#的位图。基本思想是:
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#. The basic idea is:
- 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
。 - ,
ReleaseImage
可释放与之前创建的CBitmap
相关联的资源。
- C# calls an interop function,
FetchImage
, which is in the unmanaged C++. It passes anout int
param.FetchImage
has a correspondinglong *
param. - In C++,
FetchImage
creates aCBitmap
somewhere safe, ie not local, draws something on it, usesHandleToLong()
to convert the bitmap'sHBITMAP
handle to along
, stores it in the param for the C#, and returns. - Back in C#, the
out int
param is converted to anIntPtr
and usesSystem.Drawing.Image.FromHbitmap
to copy the data and produce aSystem.Drawing.Bitmap
object. - C# then calls another interop function,
ReleaseImage
. - In C++,
ReleaseImage
frees the resources associated with theCBitmap
it created earlier.
这是不耐烦的要点。以下是更具体的代码示例。
That's the gist for the impatient. More specific code examples below.
函数的C ++互操作定义:
C++ interop definitions for the functions:
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;
}
Interp函数的IDL原型,它们被包装在C# :
IDL prototypes for the interop functions, which are wrapped in a helper class in C#:
[id(1)] HRESULT FetchImage( long * hBitmap );
[id(2)] HRESULT ReleaseImage();
在辅助类中生成这些C#原型:
Produces these C# prototypes in the helper class:
void FetchImage( out int hBitmap );
void ReleaseImage();
调用它们的C#看起来像这样:
And the C# that calls them looks kind of like this:
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
调用中销毁一个。
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. 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.
有没有任何陷阱我不知道的?我确实有这个工作,我只是想确保我不做危险的事情,因为我不知道更好。
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.
推荐答案
您可以只声明呼叫者有责任释放HBITMAP。这将简化你的C ++代码,因为你可以删除ReleaseImage方法。示例:
You could just declare that it is the caller's responsibility to free the HBITMAP. That would simplify your C++ code since you could remove the ReleaseImage method. 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
}
或者,您可以查看返回 IPicture 使用 OleCreatePictureIndirect 。这提供了一些优点:
Alternatively, you could look into returning an IPicture using OleCreatePictureIndirect. That provides some advantages:
- 调用者使用标准COM引用计数释放返回的图像。这通常使调用者不必担心释放返回的图像(除非调用者是另一个需要手动调用IUnknown :: Release的C ++程序)。
- 与其他支持COM的语言,像VBA / VB6。 IPicture是在COM中传递图片的标准方式。
这篇关于将HBITMAP句柄从非托管代码传递到托管代码的安全性创建了一个System.Drawing.Bitmap的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!