在 Powershell 5.0 中使用自定义类型 class
Using custom type in Powershell 5.0 class
这是目前让我很头疼的示例代码。
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)
}
}
这个class可以这么用
$notepad = [AppInstance]::new()
$notepad.Hide()
$notepad.Show()
基本上,我要做的是从 user32.dll
中导入一个函数作为 [Win32.NativeMethods]
类型,然后在 class
.
中使用该类型
如果我在 Powershell_ISE
中单独执行 Add-Type
语句,则会创建类型,随后脚本工作正常。
但是,当我尝试在手动创建类型之前执行整个脚本时,出现以下 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:
我已阅读 的答案,接受的答案不是我的问题的答案。将一个简单的脚本拆分成多个文件并不是真正的答案。
我想问的是有没有办法告诉解析器类型是动态创建的。
编辑 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
是否由解析器以不同于脚本其余部分的方式处理?
正如您自己发现的那样,当定义函数时,解析器并不像 classes 那样严格——原因很简单,函数定义不需要编译,所以解析器只检查语法而不是类型解析。
您可以使用此观察来解决您的问题 - 只需在 Class 定义之外定义一个函数来包装对 [Win32.NativeMethods]::ShowWindowAsync()
的调用,然后从 class 内部调用该函数] 方法:
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
}
}
这是目前让我很头疼的示例代码。
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)
}
}
这个class可以这么用
$notepad = [AppInstance]::new()
$notepad.Hide()
$notepad.Show()
基本上,我要做的是从 user32.dll
中导入一个函数作为 [Win32.NativeMethods]
类型,然后在 class
.
如果我在 Powershell_ISE
中单独执行 Add-Type
语句,则会创建类型,随后脚本工作正常。
但是,当我尝试在手动创建类型之前执行整个脚本时,出现以下 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:
我已阅读
我想问的是有没有办法告诉解析器类型是动态创建的。
编辑 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
是否由解析器以不同于脚本其余部分的方式处理?
正如您自己发现的那样,当定义函数时,解析器并不像 classes 那样严格——原因很简单,函数定义不需要编译,所以解析器只检查语法而不是类型解析。
您可以使用此观察来解决您的问题 - 只需在 Class 定义之外定义一个函数来包装对 [Win32.NativeMethods]::ShowWindowAsync()
的调用,然后从 class 内部调用该函数] 方法:
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
}
}