Nairel Prandini
Nairel Prandini

Reputation: 83

Using Win32 API to get desktop work area rectangle

I Want SystemParametersInfoA to return a System.Drawing.Rectangle but i have no idea how to proceed.

Here is my code so far:

[DllImport("user32.dll")]
static extern bool SystemParametersInfo(uint uiAction, uint uiParam, out IntPtr pvParam, uint fWinIni);
const uint SPI_GETWORKAREA = 0x0030;

void GetRect()
{
    IntPtr WorkAreaRect;
    SystemParametersInfo(SPI_GETWORKAREA, 0, out WorkAreaRect, 0);
}

Upvotes: 1

Views: 1280

Answers (2)

Charlieface
Charlieface

Reputation: 71364

As mentioned, you need to pass a buffer variable in.

But you don't need to manually allocate it. You can just use an out variable.

[DllImport("user32.dll", SetLastError = true)]
static extern bool SystemParametersInfo(uint uiAction, uint uiParam, out RECT pvParam, uint fWinIni);
const uint SPI_GETWORKAREA = 0x0030;

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int Left, Top, Right, Bottom;
}

Rectangle GetRect()
{
    if(!SystemParametersInfo(SPI_GETWORKAREA, 0, out var r, 0))
        throw new Win32Exception(Marshal.GetLastWin32Error());
    return new Rectangle(r.Left, r.Top, r.Width, r.Height);
}

Upvotes: 2

Remy Lebeau
Remy Lebeau

Reputation: 595792

Per the SPI_GETWORKAREA documentation:

The pvParam parameter must point to a RECT structure that receives the coordinates of the work area, expressed in physical pixel size.

The pointer in question is not an out value. It is an in value. You are supposed to pass in your own pointer to an existing RECT instance, which SPI_GETWORKAREA will then simply fill in.

You can use Marshal.AllocHGlobal() to allocate memory for a RECT, and then use Marshal.PtrToStructure() to extract the populated RECT from the memory.

Try this:

[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni);
const uint SPI_GETWORKAREA = 0x0030;

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int Left, Top, Right, Bottom;
}

void GetRect()
{
    IntPtr mem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(RECT)));
    SystemParametersInfo(SPI_GETWORKAREA, 0, mem, 0);
    RECT r = new RECT;
    Marshal.PtrToStructure(mem, r);
    Rectangle WorkAreaRect = new Rectangle(r.Left, r.Top, r.Width, r.Height);
    Marshal.FreeHGlobal(mem);
}

Upvotes: 1

Related Questions