superstator
superstator

Reputation: 3208

Correct length for WINDOWPLACEMENT struct

I am working on an app which needs to get/set Win32 window placement information. I am using .NET Core 3.1, and Windows 10 1909. I have added a P/Invoke method and structs for GetWindowPlacement:

[DllImport("USER32.DLL")]
public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);


[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public long left;
    public long top;
    public long right;
    public long bottom;
}

[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPLACEMENT
{
    public uint length;
    public uint flags;
    public uint showCmd;
    public POINT ptMinPosition;
    public POINT ptMaxPosition;
    public RECT rcNormalPosition;
    public RECT rcDevice;
}

[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
    public long x;
    public long y;
}

I then call it like this:

var placement = new WINDOWPLACEMENT();
placement.length = (uint)Marshal.SizeOf(placement);
if (GetWindowPlacement(hWnd, ref placement))
{
    // do something with placement info
}

Marshall.SizeOf returns a length of 108 bytes, and the call appears to succeed, but afterwards the placement struct always has it's length value set to 44, and the RECT values are all 0. flags, showCmd, and the POINT values come through fine. I've tried hard-coding the length to other values like 112 or 120 bytes, or 0 bytes, but I always get the struct back with length = 44 and no rectangles.

What am I missing?

Upvotes: 2

Views: 827

Answers (1)

Alex Guteniev
Alex Guteniev

Reputation: 13679

In <Windows.h> the structure is defined as follows:

typedef struct tagWINDOWPLACEMENT {
    UINT  length;
    UINT  flags;
    UINT  showCmd;
    POINT ptMinPosition;
    POINT ptMaxPosition;
    RECT  rcNormalPosition;
#ifdef _MAC
    RECT  rcDevice;
#endif
} WINDOWPLACEMENT;
typedef WINDOWPLACEMENT *PWINDOWPLACEMENT, *LPWINDOWPLACEMENT;

So its size is 3*sizeof(UINT)+2*sizeof(POINT)+1*sizeof(RECT) without _MAC defined, and plus one more RECT with _MAC defined.

So it is 44, and 60 on _MAC (see What's with "#ifdef _MAC" in Windows header files?)

So you should define it without RECT rcDevice

Another mistake is that C# long is 8 bytes, you need int in POINT and RECT.

Fix both, and you'll have 44.

Upvotes: 4

Related Questions