Как вы обнаружили, .MainWindowHandle
не является статическим свойством (из связанных документов; выделение добавлено):
Главное окно - это окно, открытое процессом, который в настоящее время имеет фокус [...]
Таким образом, значение свойства .MainWindowHandle
текущего процесса изменяется с дескриптора console-window на окно WinForms во время отображения формы. [1]
Кэширование дескриптора окна консоли до отображение формы, безусловно, является вариантом, но есть более простой способ, учитывая, что вы уже используете Add-Member
с объявлениями WinAPI P / Invoke: GetConsoleWindow()
Функция WinAPI всегда возвращает дескриптор окна консоли текущего процесса.
Кроме того, ваш экземпляр формы $Forms
имеет свойство .Handle
, которое напрямую возвращает дескриптор окна формы - не требуется вызов (Get-Process -Id $pid).MainWindowHandle
.
Следовательно, следующее решение не требует глобальных переменных или переменных уровня скрипта и ограничивает запрос дескрипторов окна обработчиком события нажатия кнопки:
# P/Invoke signatures - note the addition of GetConsoleWindow():
$sig = '
[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")] public static extern int SetForegroundWindow(IntPtr hwnd);
[DllImport("kernel32.dll")] public static extern IntPtr GetConsoleWindow();'
$type = Add-Type -MemberDefinition $sig -Name WindowAPI -PassThru
Add-Type -AssemblyName System.Windows.Forms
$Form = New-Object system.Windows.Forms.Form -Property @{
ClientSize = '446,266'
text = "Form"
}
$Button1 = New-Object system.Windows.Forms.Button -Property @{
text = "Test"
location = New-Object System.Drawing.Point(75, 29)
}
$Button1.Add_Click({
# Get this form's window handle.
$handleForm = $Form.Handle # More generically: $this.FindForm().Handle
# Get the console window's handle.
$handleConsole = $type::GetConsoleWindow()
# Activate the console window and prompt the user.
$null = $type::ShowWindowAsync($handleConsole, 4); $null = $type::SetForegroundWindow($handleConsole)
Read-Host -Prompt "Please Enter a Value"
# Reactivate this form.
$null = $type::ShowWindowAsync($handleForm, 4); $null = $type::SetForegroundWindow($handleForm)
})
$Form.controls.AddRange(@($Button1))
$null = $Form.ShowDialog()
[1] Обратите внимание, что объект процесса cached не динамически обновляет свое значение .MainWindowHandle
; Вы должны позвонить .Refresh()
вручную.
Поскольку решение iRon кэширует объект текущего процесса до отображения формы, все равно случается, что он отражает дескриптор окна консоли внутри обработчика нажатия кнопки.