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

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

Comments

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).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.