3

Environment: Win 10 64 bit, PS version 7.1

I had a module and I decided to move everything into class based. To use the assembly I need to load the .dll etc via the workaround psd1 file.

After look at the thread: Powershell: Unable to find type when using PS 5 classes

**Per comment from @mklement0 the .dll can't be loaded as the same way as the assmebly 'System.Windows.Forms'

updated per suggestion from @mklement0 but it still didn't work This is what it looks like after the update:

H:\PowerShell\Modules\TestUtils

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---           2/26/2021  6:25 AM           4168 TestUtils.psd1
-a---           2/26/2021  6:22 AM            449 TestUtils.psm1

and TestUtils.psd1 was created by command:

New-ModuleManifest TestUtils.psd1 -RootModule TestUtils.psm1 The content in .psm1 is as below:

Add-Type -name NativeMethods -namespace Win32 -MemberDefinition @'
    [DllImport("user32.dll")]
    public static extern void mouse_event(int flags, int dx, int dy, int cButtons, int info);
    [DllImport("user32.dll")]
    public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
'@  

Class MyWinUtils
{
    
    Static [Void] ClickLeftMouse([int]$x,[int]$y)
    {
      [Win32.NativeMethods]::mouse_event(6,0,0,0,0) 
    }
}

When I load the module the error popped up:

using module TestUtils
InvalidOperation: At TestUtils.psm1:15 char:5
+       [Win32.NativeMethods]::mouse_event(6,0,0,0,0)
+        ~~~~~~~~~~~~~~~~~~~
Unable to find type [Win32.NativeMethods].

Thanks

Ginger_Chacha
  • 317
  • 1
  • 11
  • FWIW in PS 5.1 I have psm1 files with classes in them and they are loaded fine when you use `using module` syntax instead of `Import-Module`. – Rno Feb 24 '21 at 21:45
  • I always add Win32 types using Add-Type -TypeDefinition . I also saw that the C# code is missing the required using statements to use PInvoke (System.Runtime.InteropServices is required for DllImport.) – bluuf Feb 26 '21 at 11:58
  • 1
    @bluuf, _not_ having to add these `using` statements and _not_ having to define an enclosing class explicitly is the convenience that `-MemberDefinition` affords - its primary use is to facilitate exposing P/Invoke-based methods. – mklement0 Feb 26 '21 at 13:35

1 Answers1

4

You can't require user32.dll as an assembly, because it isn't one: it is an unmanaged DLL, unrelated to .NET.

Instead:

  • Use only RequiredAssemblies = 'System.Windows.Forms', 'System.Drawing' to ensure that these managed DLLs (assemblies) are loaded.

  • Also add a *.psm1 file to your module directory, using the same name as the module directory as the base name.

  • Reference that *.psm1 file - by file name only - from the module manifest's RootModule property.

  • Place the Add-Type -MemberDefinition call directly in the top-level scope of the *.psm1 file.

    • The C# code passed to that call is capable of locating the unmanaged user32.dll DLL due its being located in the standard SYSTEM32 directory.

Then, when your module is imported, the Add-Type -MemberDefinition command is executed and adds the [Win32.NativeMethod] class with its static mouse_event() and ShowWindowAsync() methods to your session.


The update to your question reveals an additional, unrelated problem:

  • You're trying to use the Add-Type-added .NET type in the context of a PowerShell custom class defined in the same file.

  • However, PowerShell parses class definitions at parse time rather than at runtime, which means that it requires types being referenced in a class definition to have been loaded into the session beforehand.

Workaround:

  • Place the Add-Type -MemberDefinition call in a separate *.psm1 file inside your module directory, say helper.psm1, and reference that file from the NestedModules property in the manifest (NestedModules = @('helper')).

Nested modules are processed before the main (root) module (RootModule property), so by the time the MyWinUtils class definition is parsed, the [Win32.NativeMethods] type has already been loaded.

mklement0
  • 382,024
  • 64
  • 607
  • 775