简体   繁体   English

将HBITMAP句柄从非托管代码传递到托管代码的安全性,以创建System.Drawing.Bitmap

[英]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: 基本思想是:

  1. C# calls an interop function, 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 *参数。
  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. 在C ++中, FetchImage在安全的地方(即不在本地)创建一个CBitmap ,在其上绘制一些东西,使用HandleToLong()将位图的HBITMAP句柄转换为long ,将其存储在C#的参数中,然后返回。
  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. 回到C#中,将out int参数转换为IntPtr并使用System.Drawing.Image.FromHbitmap复制数据并生成System.Drawing.Bitmap对象。
  4. C# then calls another interop function, ReleaseImage . 然后,C#调用另一个互操作函数ReleaseImage
  5. In C++, 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. 我自己想到的唯一问题是从其他地方调用FetchImageReleaseImage情况不同步的情况。 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: 这提供了一些优点:

  • Caller frees the returned image using standard COM reference counting. 呼叫者使用标准COM参考计数释放返回的图像。 That generally frees the caller from worrying about freeing the returned image (unless the caller is another C++ program that needs to manually call IUnknown::Release). 通常,这使调用者不必担心释放返回的图像(除非调用者是另一个需要手动调用IUnknown :: Release的C ++程序)。
  • Better compatibility with other COM-enabled languages, like VBA / VB6. 与其他启用COM的语言(例如VBA / VB6)更好的兼容性。 IPicture is the standard way of passing around a picture in COM. IPicture是在COM中传递图片的标准方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM