1

这是目前让我很头疼的示例代码。

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

这个类可以像这样使用

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

基本上,我要做的是从user32.dllas 类型导入一个函数[Win32.NativeMethods],然后在class.

如果我在创建类型中单独执行Add-Type语句Powershell_ISE,然后脚本就可以正常工作。

但是,当我在手动创建类型之前尝试执行整个脚本时,我收到以下 Powershell 解析器错误

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

看起来解析器忽略了Add-Type语句并在执行前退出。

有没有办法克服这个问题?也许有一个using声明?或者,有没有办法告诉解析器该类型是动态创建的?

编辑1:

我已阅读在Powershell (V5) 类中使用 .Net 对象的答案,并且接受的答案不是我的问题的答案。将一个简单的脚本拆分为多个文件并不是真正的答案。

我要问的是天气有一种方法可以告诉解析器该类型是动态创建的。

编辑2:

为了进一步澄清这一点,这里的代码等效于上面的代码,但使用functions而不是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)
}

这段代码将完美地解析和执行。解析器是否classes以与脚本的其余部分不同的方式处理?

4

1 回答 1

7

正如您自己发现的那样,在定义函数时,解析器并不像在涉及类时那样严格 - 简单的原因是函数定义不需要编译,因此解析器只检查语法而不是类型解析。

您可以使用此观察来解决您的问题 - 只需在 Class 定义之外定义一个函数,该函数包装调用[Win32.NativeMethods]::ShowWindowAsync(),然后从您的类方法内部调用该函数:

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
    }
}
于 2016-02-05T09:06:03.317 回答