1

此代码在运行 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大小没有帮助。

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

4

1 回答 1

3

问题是这一行:

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

这适用于 32 位版本,因为结构的对齐方式没有填充。但在 64 位版本上,指针前有 4 个字节的填充。cbBuffer短 4 个字节也是如此。

那就是问题所在。解决方案是停止自己计算尺寸并使用Marshal.SizeOf()专为此目的设计的尺寸。

于 2013-04-11T14:34:19.227 回答