2

I am trying to add a POINT struct to powershell to use in winapi GetCursorPos function. This is what i have try:

$MethodDefinition=@'
[StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;

        public POINT(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
    }
[DllImport("user32.dll")]public static extern Int32 GetCursorPos(out POINT lpPoint);
'@;Add-Type -MemberDefinition $MethodDefinition -Name 'Win32' -NameSpace '' -PassThru

When I delete GetCursorPos definition it gives me a yellow: WARNING: The generated type defines no public methods or properties.
I don't know how do I use a struct in powershell, I only find informations on how to create one.
See:
https://www.pinvoke.net/default.aspx/Structures/POINT.html
How do I create a custom type in PowerShell for my scripts to use?
https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.layoutkind?view=net-5.0

Edit:
I have added a struct but still don't know how to construct it:

$StructDefinition=@'
public struct POINT{public int X;public int Y;public POINT(int x, int y){this.X=x;this.Y=y;}}
'@;Add-Type -TypeDefinition $StructDefinition -PassThru
Julian
  • 134
  • 11

2 Answers2

4

I solved the problem, Member definition:

$MethodDefinition = @'
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
  public Int32 x;
  public Int32 y;

  public POINT(Int32 X, Int32 Y)
  {
    this.x = X;
    this.y = Y;
  }
}

[DllImport("user32.dll")]
public static extern Int32 GetCursorPos(out POINT lpPoint);
'@

$WinApiVariable = Add-Type -MemberDefinition $MethodDefinition -Name 'Win32' -NameSpace '' -PassThru

Displaying cursor position:

$cursorPos = New-Object -TypeName 'Win32+POINT' -ArgumentList 0,0
[Win32]::GetCursorPos([ref]$cursorPos)
Write-Host "$($cursorPos.x),$($cursorPos.y)"

With this weird + sign syntax Win32+POINT, I am able to access struct definition inside member definition, New-Object creates a struct and [ref] is to reference a struct.

Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
Julian
  • 134
  • 11
2

Let me propose simplifications to your own, helpful answer:

If you define a wrapper method, you can let it return a POINT instance directly - no need for constructing one ahead of time and pass it as a [ref] / out parameter:

Add-Type -Namespace '' -Name Win32 -MemberDefinition  @'
  [StructLayout(LayoutKind.Sequential)]
  public struct POINT
  {
    public Int32 x;
    public Int32 y;
  }

  // Define the WinAPI method privately.
  [DllImport("user32.dll", EntryPoint="GetCursorPos")]
  private static extern Int32 GetCursorPosWinApi(out POINT lpPoint);

  // Wrapper method that directly returns a POINT instance.
  public static POINT GetCursorPos() {
    var pt = new POINT(); 
    GetCursorPosWinApi(out pt);
    return pt;
  }
'@

[Win32]::GetCursorPos()

Sample output (a POINT instance representing the current cursor position):

  x   y
  -   -
556 123

This is not only more convenient, but relieves you of the need to know the full type name of the POINT instance (which is Win32+POINT, as you've discovered, with the + indicating that POINT is nested inside the Win32 class - see this answer for more information about this notation, which - while also used by PowerShell with enclosing [...] for type literals - is defined by .NET APIs).

mklement0
  • 382,024
  • 64
  • 607
  • 775