【发布时间】:2011-09-02 14:51:02
【问题描述】:
我对托管/非托管互操作非常陌生,因此我希望就以下过程从非托管 C++ 到托管 C# 获取位图的安全性获得一些意见。基本思路是:
- C# 调用非托管 C++ 中的互操作函数
FetchImage。它传递了一个out int参数。FetchImage有一个对应的long *参数。 - 在 C++ 中,
FetchImage在安全的地方(即非本地)创建一个CBitmap,在其上绘制一些东西,使用HandleToLong()将位图的HBITMAP句柄转换为long,将其存储在参数中C#,然后返回。 - 回到 C# 中,
out int参数转换为IntPtr并使用System.Drawing.Image.FromHbitmap复制数据并生成System.Drawing.Bitmap对象。 - C# 然后调用另一个互操作函数
ReleaseImage。 - 在 C++ 中,
ReleaseImage释放与它之前创建的CBitmap关联的资源。
对于不耐烦的人来说,这就是要点。下面是更具体的代码示例。
函数的 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 原型,它们被包装在 C# 的帮助器类中:
[id(1)] HRESULT FetchImage( long * hBitmap );
[id(2)] HRESULT ReleaseImage();
在帮助类中生成这些 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 导致事情不同步。所以我可能会有一个CBitmaps 的列表,而不仅仅是一个,然后将句柄传回给ReleaseImage,这样它只会从匹配的FetchImage 调用中销毁那个。
有什么我不知道的问题吗?我确实有这个工作,我只是想确保我没有做危险的事情,因为我不知道更好。
【问题讨论】:
-
参数类型错误,应该是 IntPtr 和 HANDLE。您可以立即释放 CBitmap,FromHbitmap 会制作副本,因此不需要痛苦和冒险的 ReleaseImage()。
-
@Hans 除了 CBitmap 是在非托管 C++ 代码中创建的。除非被告知,否则该代码如何知道释放它?
-
你说得对,在 FromHbitmap() 执行之前不能这样做。
标签: c# c++ interop marshalling