0

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);
}
  • When doing P/Invoke, the pinvoke.net site is your friend. Start here: https://www.pinvoke.net/default.aspx/user32.SystemParametersInfo – Flydog57 Sep 07 '22 at 03:23

2 Answers2

1

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);
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
1

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);
}
Charlieface
  • 52,284
  • 6
  • 19
  • 43
  • Have you tried this? Does it really work? `SPI_GETWORKAREA` does not allocate a `RECT` and return it. Did you mean to use `ref` instead of `out`? – Remy Lebeau Sep 07 '22 at 18:40
  • No I did mean `out`, which also implies `[Out]`. The difference between `out` and `ref` for structs is purely in compile-time semantics of initialization. Specifying `[Out]` or implying it also changes the copy semantics if there is any marshalling done. The memory is allocated either way and passed in as a pointer. See https://stackoverflow.com/a/8593413/14868997 and https://stackoverflow.com/a/26653492/14868997 – Charlieface Sep 07 '22 at 19:11
  • i forgot to come here to give feedback but thank u guys it works perfectly – Nairel Prandini Nov 09 '22 at 19:40