假设我从本机 Windows 函数中获得了 HBITMAP 对象/句柄。我可以使用Bitmap.FromHbitmap(nativeHBitmap)将其转换为托管位图,但如果本机图像具有透明度信息(alpha 通道),则此转换会丢失它。
Stack Overflow 上有几个关于这个问题的问题。使用这个问题的第一个答案(如何使用 GDI+ 绘制 ARGB 位图?)中的信息,我编写了一段我尝试过的代码并且它可以工作。
它基本上使用GetObject和BITMAP结构获取本机 HBitmap 的宽度、高度和指向像素数据位置的指针,然后调用托管的 Bitmap 构造函数:
Bitmap managedBitmap = new Bitmap(bitmapStruct.bmWidth, bitmapStruct.bmHeight,
bitmapStruct.bmWidth * 4, PixelFormat.Format32bppArgb, bitmapStruct.bmBits);
据我了解(如果我错了,请纠正我),这不会将实际像素数据从本机 HBitmap 复制到托管位图,它只是将托管位图指向来自本机 HBitmap 的像素数据。
而且我不会在另一个图形(DC)或另一个位图上绘制位图,以避免不必要的内存复制,特别是对于大位图。
我可以简单地将这个位图分配给 PictureBox 控件或 Form BackgroundImage 属性。它工作正常,位图正确显示,使用透明度。
当我不再使用位图时,我确保 BackgroundImage 属性不再指向该位图,并且我同时处置托管位图和本机 HBitmap。
问题:你能告诉我这个推理和代码是否正确。我希望我不会得到一些意想不到的行为或错误。我希望我能正确释放所有内存和对象。
private void Example()
{
IntPtr nativeHBitmap = IntPtr.Zero;
/* Get the native HBitmap object from a Windows function here */
// Create the BITMAP structure and get info from our nativeHBitmap
NativeMethods.BITMAP bitmapStruct = new NativeMethods.BITMAP();
NativeMethods.GetObjectBitmap(nativeHBitmap, Marshal.SizeOf(bitmapStruct), ref bitmapStruct);
// Create the managed bitmap using the pointer to the pixel data of the native HBitmap
Bitmap managedBitmap = new Bitmap(
bitmapStruct.bmWidth, bitmapStruct.bmHeight, bitmapStruct.bmWidth * 4, PixelFormat.Format32bppArgb, bitmapStruct.bmBits);
// Show the bitmap
this.BackgroundImage = managedBitmap;
/* Run the program, use the image */
MessageBox.Show("running...");
// When the image is no longer needed, dispose both the managed Bitmap object and the native HBitmap
this.BackgroundImage = null;
managedBitmap.Dispose();
NativeMethods.DeleteObject(nativeHBitmap);
}
internal static class NativeMethods
{
[StructLayout(LayoutKind.Sequential)]
public struct BITMAP
{
public int bmType;
public int bmWidth;
public int bmHeight;
public int bmWidthBytes;
public ushort bmPlanes;
public ushort bmBitsPixel;
public IntPtr bmBits;
}
[DllImport("gdi32", CharSet = CharSet.Auto, EntryPoint = "GetObject")]
public static extern int GetObjectBitmap(IntPtr hObject, int nCount, ref BITMAP lpObject);
[DllImport("gdi32.dll")]
internal static extern bool DeleteObject(IntPtr hObject);
}