Using custom type in Powershell 5.0 class [duplicate]

两盒软妹~` 提交于 2020-07-23 04:39:18

问题


Here is example code that is causing me lots of headaches at the moment.

if (("Win32.NativeMethods" -as [type]) -eq $null){
    Add-Type -MemberDefinition '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
        ' -name NativeMethods -namespace Win32
}

class AppInstance 
{    
    [string]$App = 'Notepad.exe'
    [IntPtr]$hWnd = 0
    [System.Object]$process

    AppInstance () {
        Start-Process $this.App
        $this.process = get-process ($this.App.split('.'))[0]
        start-sleep -Milliseconds 100
        $this.hWnd = $this.process.MainWindowHandle    
    }

    [void] Show () {
        [Win32.NativeMethods]::ShowWindowAsync($this.hWnd, 3)
    }

    [void] Hide () {
        [Win32.NativeMethods]::ShowWindowAsync($this.hWnd, 2)
    }
}

This class can be used like so

$notepad = [AppInstance]::new()
$notepad.Hide()
$notepad.Show()

Basically, what I'm trying to do is to import a function from user32.dll as type [Win32.NativeMethods] and then use this type in a class.

If I execute the Add-Type statement separately in Powershell_ISE the type gets created and subsequently the script works just fine.

However, when I try to execute the whole script before creating the type manually, I get the following Powershell parser error

At C:\class.ps1:26 char:10
+         [Win32.NativeMethods]::ShowWindowAsync($this.hWnd, 3)
+          ~~~~~~~~~~~~~~~~~~~
Unable to find type [Win32.NativeMethods].
At C:\Uclass.ps1:31 char:10
+         [Win32.NativeMethods]::ShowWindowAsync($this.hWnd, 2)
+          ~~~~~~~~~~~~~~~~~~~
Unable to find type [Win32.NativeMethods].
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : TypeNotFound

Looks like the parser is ignoring the Add-Type statement and exiting before execution.

Is there any way to overcome this issue? Maybe with a using statement? Or, is there any way to tell the parser that the type is dynamically created?

EDIT 1:

I have read the answer to Using .Net Objects within a Powershell (V5) Class and the accepted answer is not an answer to my question. Splitting a simple script into multiple files is not really an answer.

What I'm asking is weather there is a way to tell the parser that the type is dynamically created.

EDIT 2:

To clarify this a little further here is code equivalent to the one above, but implemented using functions instead of classes.

if (("Win32.NativeMethods" -as [type]) -eq $null){
    Add-Type -MemberDefinition '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
        ' -name NativeMethods -namespace Win32
}

[string]$script:App = 'Notepad.exe'

$process = Start-Process $App -PassThru


function Show () {
    [Win32.NativeMethods]::ShowWindowAsync($process.MainWindowHandle, 3)
}

function Hide () {
    [Win32.NativeMethods]::ShowWindowAsync($process.MainWindowHandle, 2)
}

This code will parse and execute perfectly fine. Are classes handled by the parser in a different way to rest of the script?


回答1:


As you've found out yourself, when defining functions the parser is not nearly as strict as when it comes to classes - the simple reason is that function definitions need no compilation, so the parser only checks for syntax not type resolution.

You can use this observation to work around your problem - simply define a function outside the Class definition that wraps the call to [Win32.NativeMethods]::ShowWindowAsync() and then call that function from inside your class method:

function __ShowWindowAsync
{
    param([IntPtr]$WindowHandle,[int]$ShowState)

    if (("Win32.NativeMethods" -as [type]) -eq $null){
        Add-Type -MemberDefinition '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);' -Name NativeMethods -namespace Win32
    }

    [Win32.NativeMethods]::ShowWindowAsync($this.hWnd, $ShowState)
}

class AppInstance 
{    
    [string]$App = 'Notepad.exe'
    [IntPtr]$hWnd = 0
    [System.Object]$process

    AppInstance () {
        # this is way more reliable than running Get-Process subsequently
        $this.process = Start-Process $this.App -PassThru
        start-sleep -Milliseconds 100
        $this.hWnd = $this.process.MainWindowHandle
    }

    [void] Show () {
        $Maximized = 3
        __ShowWindowAsync -WindowHandle $this.hWnd -ShowState $Maximized
    }

    [void] Hide () {
        $Minimized = 2
        __ShowWindowAsync -WindowHandle $this.hWnd -ShowState $Minimized
    }
}


来源:https://stackoverflow.com/questions/35215295/using-custom-type-in-powershell-5-0-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!