将HBITMAP句柄从非托管代码传递到托管代码的安全性创建了一个System.Drawing.Bitmap [英] Safety of passing HBITMAP handle from unmanaged to managed code for created a System.Drawing.Bitmap

查看:222
本文介绍了将HBITMAP句柄从非托管代码传递到托管代码的安全性创建了一个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:


  1. C#调用互操作函数 FetchImage 在非托管C ++。它传递 out int param。 FetchImage 有一个相应的 long * param。

  2. 在C ++中, FetchImage 创建一个 CBitmap 某处安全,即不是本地,绘制东西,使用 HandleToLong 将位图的 HBITMAP 句柄转换为 long ,将其存储在 c#返回。

  3. 回到C#, out int param被转换为 IntPtr 并使用 System.Drawing.Image.FromHbitmap 复制数据并生成 System.Drawing.Bitmap 对象。

  4. C#然后调用另一个互操作函数 ReleaseImage

  5. ReleaseImage 可释放与之前创建的 CBitmap 相关联的资源。

  1. C# calls an interop function, FetchImage, which is in the unmanaged C++. It passes an out int param. FetchImage has a corresponding long * param.
  2. In C++, 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.
  3. Back in C#, the 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.
  4. C# then calls another interop function, ReleaseImage.
  5. In C++, ReleaseImage frees the resources associated with the CBitmap 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 CBitmaps 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆