Reputation: 2179
This code works fine when running 32-bit. But when I switch to 64-bit the GetObject
method does not work and BITMAP
struct is empty.
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);
The native method implementation:
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.
);
}
The BITMAP structure implementation (removed documentation to keep code compact):
[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;
}
The idea behind this code is fully described in this question.
At first I thought that the issue is caused by different size of IntPtr
resulting in different size of cbBuffer
, but it seems that this is not the case as changing cbBuffer
size did not help.
What is the correct way to use GDI's GetObject
method on 64-bit system?
Upvotes: 1
Views: 1407
Reputation: 612794
The problem is this line:
cbBuffer = sizeof(Int32) * 4 + sizeof(UInt16) * 2 + IntPtr.Size;
That works on the 32 bit version because the alignment of the struct has no padding. But on the 64 bit version, there are 4 bytes of padding before the pointer. So cbBuffer
is 4 bytes short.
That's the problem. The solution is to stop calculating the size yourself and use Marshal.SizeOf()
which is designed for this very purpose.
Upvotes: 3