gdi32.GetObject在运行64位时不起作用

本文关键字:不起作用 64位 运行 GetObject gdi32 | 更新日期: 2023-09-27 18:08:44

此代码在运行32位时运行良好。但是当我切换到64位时,GetObject方法不起作用,BITMAP结构为空。

IntPtr hBmp = ObtainValidBitmapHandleFromSystem();
BITMAP bmpData = new BITMAP();
/* BITMAP consists of four 32bit ints,
 * two 16 bit uints and one IntPtr */
 * 4 + sizeof(UInt16) * 2 + IntPtr.Size;
int cbBuffer = sizeof(Int32) * 4 + sizeof(UInt16) * 2 + IntPtr.Size;
NativeMethods.GetObject(hBmp, cbBuffer, out bmpData);
Bitmap bmp = new Bitmap(bmpData.Width, bmpData.Height, PixelFormat.Format32bppPArgb);

本机方法实现:

private static class NativeMethods
{
    [DllImport("gdi32", CharSet = CharSet.Auto)]
    internal extern static int GetObject(
        IntPtr hgdiobj,     // handle to graphics object
        int cbBuffer,       // size of buffer for object information
        out BITMAP lpvObject    // Should be IntPtr, but we know we will use it only for BITMAP.
    );
}

BITMAP结构实现(删除文档以保持代码紧凑):

[StructLayoutAttribute(LayoutKind.Sequential)]
private struct BITMAP
{
    public Int32 Type;
    public Int32 Width;
    public Int32 Height;
    public Int32 WidthBytes;
    public UInt16 Planes;
    public UInt16 BitsPixel;
    public IntPtr Bits;
}

这段代码背后的思想在这个问题中有完整的描述。

起初我认为问题是由于IntPtr的大小不同导致cbBuffer的大小不同,但似乎不是这样,因为改变cbBuffer的大小并没有帮助。

在64位系统上正确使用GDI的GetObject方法是什么?

gdi32.GetObject在运行64位时不起作用

问题出在这一行:

cbBuffer = sizeof(Int32) * 4 + sizeof(UInt16) * 2 + IntPtr.Size;

这适用于32位版本,因为结构体的对齐没有填充。但在64位版本中,指针前有4个字节的填充。所以cbBuffer是4字节短。

这就是问题所在。解决方案是停止自己计算大小,并使用Marshal.SizeOf(),这是专门为这个目的而设计的。