【问题标题】:Why System.Windows.Forms.Control MousePosition property can be read, but Location not?为什么可以读取 System.Windows.Forms.Control MousePosition 属性,但不能读取 Location?
【发布时间】:2016-04-16 16:04:46
【问题描述】:

我从某个站点复制了这个 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 class documentation 并发现了几个属性是 MousePosition 的“姐妹”(如底部、边界、左侧、位置、右侧或顶部),其中包含有关“控制”的度量(以像素为单位),所以我尝试也可以通过这种方式报告Location property 值:

[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

但是此代码不起作用:未报告错误,但未显示 Location 值:

MousePosition: 368 431
Location:

为什么可以正确访问 MousePosition 属性,但不能正确访问 Location?

此代码的目的是获取运行 PowerShell 脚本的 cmd.exe 窗口的尺寸和位置(以像素为单位)。 在 PowerShell 中获取这些值的正确方法是什么?

【问题讨论】:

  • MousePosition 是静态的,Location 不是(因为它是每个控件实例)。如果你想要它的位置,你必须从窗口句柄实例化一个 Control 对象

标签: .net winforms powershell


【解决方案1】:

此代码的目的是获取运行 PowerShell 脚本的 cmd.exe 窗口的尺寸和位置(以像素为单位)。在 PowerShell 中获取这些值的正确方法是什么?

如果是这样,System.Windows.Forms.Control 不是您想要的 - 控制台主机不是 Windows 窗体控件。

您可以使用 GetWindowRect function 从 Win32 API (user32.dll) 获取这些值:

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

$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
  • 在这种情况下,您需要获取 进程(即 cmd.exe 进程)的MainWindowHandle,而不是当前正在运行的 PowerShell 实例
  • 最简单的事情就是(Get-Process -Id (Get-WmiObject Win32_Process -Filter "ProcessId=$PID").ParentProcessId).MainWindowHandle
  • 现在可以使用了!非常感谢!最后一个问题:为了在一行中写出第一个定义,我需要做哪些更改?我试过这个模组,但它在@'[DllImport... 部分标记了一个错误。我还尝试删除撇号和 at 符号,但正如我之前所说:我是 PoSh 新手用户,真的不知道该怎么做......
  • 只需删除换行符,@'s - @ 仅适用于此处字符串(多行字符串)