为什么可以读取System.Windows.Forms.Control MousePosition属性,但无法读取Location属性?

4

我从某个网站复制了这段PowerShell代码,它可以显示鼠标当前位置:

[Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms') | Out-Null
$control = [System.Windows.Forms.Control]
$mouseX = $control::MousePosition.X
$mouseY = $control::MousePosition.Y
Write-Host 'MousePosition:' $mouseX $mouseY

我查看了System.Windows.Forms.Control类文档,发现有几个与MousePosition类似的属性(如Bottom、Bounds、Left、Location、Right或Top),它们包含关于像素中的“控件”的度量,因此我尝试以同样的方式报告Location属性的值:
[Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms') | Out-Null
$control = [System.Windows.Forms.Control]
$mouseX = $control::MousePosition.X
$mouseY = $control::MousePosition.Y
Write-Host 'MousePosition:' $mouseX $mouseY
$locationX = $control::Location.X
$locationY = $control::Location.Y
Write-Host 'Location:' $locationX $locationY

然而,这段代码无法正常工作:没有报错,但位置值不会显示:
MousePosition: 368 431
Location:

为什么可以正确访问MousePosition属性,但无法访问Location属性?
此代码的目的是获取PowerShell脚本运行的cmd.exe窗口的尺寸和像素位置。在PowerShell中获取这些值的正确方法是什么?

3
MousePosition是静态的,而Location不是(因为它是控件实例化后的属性)。如果想获取控件位置,需要使用窗口句柄实例化一个Control对象。 - Mathias R. Jessen
1个回答

3
这段代码的目的是获取PowerShell脚本运行时cmd.exe窗口的像素尺寸和位置。在PowerShell中正确获取这些值的方法是什么?
如果是这样,那么System.Windows.Forms.Control并不是你想要的 - 控制台主机不是Windows Forms控件。
你可以使用Win32 API (user32.dll)的GetWindowRect函数来获取这些值:
$WindowFunction,$RectangleStruct = Add-Type -MemberDefinition @'
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}
'@ -Name "type$([guid]::NewGuid() -replace '-')" -PassThru

$MyWindowHandle = Get-Process -Id $PID |Select -ExpandProperty MainWindowHandle
$WindowRect = New-Object -TypeName $RectangleStruct.FullName
$null = $WindowFunction::GetWindowRect($MyWindowHandle,[ref]$WindowRect)
< p > $WindowRect 变量现在具有窗口的位置坐标:

PS C:\> $WindowRect.Top
45

非常感谢您的迅速回答!我将您的代码复制并粘贴到了 test.ps1 文件中,然后只需在结尾添加了 Write-Host 'Left,Top,Right,Bottom:' $WindowRect.Left $WindowRect.Top $WindowRect.Right $WindowRect.Bottom 一行代码。我使用以下命令从命令行执行它:powershell Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process; .\test.ps1; 输出结果为:Left,Top,Right,Bottom: 0 0 0 0 - Aacini
在这种情况下,您需要获取进程(即cmd.exe进程)的MainWindowHandle,而不是当前运行的PowerShell实例。 - Mathias R. Jessen
最简单的方法就是像这样:(Get-Process -Id (Get-WmiObject Win32_Process -Filter "ProcessId=$PID").ParentProcessId).MainWindowHandle - Mathias R. Jessen
现在它可以工作了!非常感谢!最后一个问题:为了将第一个定义写成一行,我需要做哪些更改?我尝试了这个修改,但是在@'[DllImport...部分标记了一个错误。我还尝试删除撇号和at符号,但正如我之前所说的那样:我是一个PoSh新手用户,真的不知道该怎么办... - Aacini
只需删除换行符和 @ 符号 - @ 仅用于多行字符串。 - Mathias R. Jessen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接