PowerShell脚本调用FindWindow无法定位Edge窗口的问题咨询
PowerShell Edge窗口定位与操控问题解决
问题描述
我正在编写PowerShell脚本,自动打开多个带指定URL的Microsoft Edge窗口,目标是打开五个网站后轮换视图。脚本能成功打开所有窗口,但GetWindow函数始终无法找到窗口。尝试记录进程ID后,依然无法定位对应窗口。
原脚本代码
$URLs = @( "https://www.youtube.com", "https://google.de", "https://heise.de", "https://amazon.de", "https://f-i.de" ) $FensterTitel = @( "YouTube - Profil 1 - Microsoft Edge", "Google - Profil 1 - Microsoft Edge", "heise online - IT-News, Nachrichten und Hintergründe | heise online - Profil 1 - Microsoft Edge", "Amazon.de: Günstige Preise für Elektronik & Foto, Filme, Musik, Bücher, Games, Spielzeug & mehr - Profil 1 - Microsoft Edge", "Startseite | Finanz Infomatik - Profil 1 - Microsoft Edge" ) $global:RotationAktiv = $true $EdgeProzesse = @() for ($i = 0; $i -lt 5; $i++) { Write-Host "Öffne Edge-Fenster $($i + 1) mit URL: $($URLs[$i])" Start-Process -FilePath $EdgePfad -ArgumentList "--new-window", $URLs[$i] } Start-Sleep -Seconds 10 Write-Host "Alle Edge-Fenster wurden erfolgreich gestartet." Add-Type @" using System; using System.Runtime.InteropServices; public class WinAPI { [DllImport("user32.dll")] public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); } "@ function GetWindow { param ( [string]$fensterTitel ) $hWnd = [WinAPI]::FindWindow([NullString]::Value, $fensterTitel) if ($hWnd -ne [IntPtr]::Zero) { Write-Host "Fenster gefunden: $fensterTitel" Write-Host "Fenster-Handle: $hWnd" } else { Write-Host "Fenster mit Titel '$fensterTitel' nicht gefunden." } return $hWnd } function Ansicht1 { $hWnd = GetWindow ($FensterTitel[1]) if ($hWnd -ne [IntPtr]::Zero) { [WinAPI]::MoveWindow($hWnd, 0, 0, 1920, 1080, $true) #Vollbild } } function Ansicht2 { $hWnd = GetWindow($FensterTitel[2]) if ($hWnd -ne [IntPtr]::Zero) { [WinAPI]::MoveWindow($hWnd, 0, 0, 1920, 1080, $true) #Vollbild } } while ($true) { if ($global:RotationAktiv) { Write-Host "Wechsle zu Ansicht 1." Ansicht1 Start-Sleep -Seconds 10 Write-Host "Wechsle zu Ansicht 2." Ansicht2 Start-Sleep -Seconds 8 } else { Start-Sleep -Seconds 1 Write-Host "Pausiert" } } [void]$form.ShowDialog()
尝试过的代码片段
$process = Start-Process -FilePath "msedge.exe" -ArgumentList "--new-window", $URLs[$i] -PassThru $EdgeProcessIds += $process.Id # Store the process ID
咨询问题
- 为什么
GetWindow函数无法找到已打开的Edge窗口? - 有没有更可靠的方法确保窗口能被正确找到并操控?
问题解答
1. 无法找到Edge窗口的核心原因
- 标题完全匹配失败:Edge窗口的实际标题可能和你预设的
$FensterTitel不一致——网页加载后标题可能动态变化(比如Amazon的标题会加入实时推荐内容),或存在本地化差异、拼写误差。 FindWindow的局限性:FindWindow要求完全匹配标题字符串,且Edge采用多进程架构,你启动的进程是子进程,主窗口的进程ID与启动进程ID不一致,导致通过进程ID也无法直接关联到窗口。- 未指定窗口类名:调用
FindWindow时传入[NullString]::Value作为类名,会扩大匹配范围,其他应用的相似标题窗口可能干扰结果。Edge主窗口的类名是Chrome_WidgetWin_1,不指定会降低匹配精度。
2. 可靠的窗口定位与操控方案
方案一:通过进程ID枚举关联窗口
利用Windows API枚举所有窗口,匹配进程ID获取对应窗口句柄,避开标题匹配的问题:
Add-Type @" using System; using System.Collections.Generic; using System.Runtime.InteropServices; public class WindowFinder { private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); [DllImport("user32.dll")] private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam); [DllImport("user32.dll")] private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); [DllImport("user32.dll")] private static extern bool IsWindowVisible(IntPtr hWnd); private static List<IntPtr> _windowHandles = new List<IntPtr>(); private static uint _targetProcessId; public static List<IntPtr> GetWindowsByProcessId(uint processId) { _windowHandles.Clear(); _targetProcessId = processId; EnumWindows(new EnumWindowsProc(EnumWindowsCallback), IntPtr.Zero); return _windowHandles; } private static bool EnumWindowsCallback(IntPtr hWnd, IntPtr lParam) { uint processId; GetWindowThreadProcessId(hWnd, out processId); if (processId == _targetProcessId && IsWindowVisible(hWnd)) { _windowHandles.Add(hWnd); } return true; } } "@ # 启动Edge并保存进程信息 $EdgeProcesses = @() $URLs = @("https://www.youtube.com", "https://google.de", "https://heise.de", "https://amazon.de", "https://f-i.de") for ($i = 0; $i -lt $URLs.Count; $i++) { Write-Host "Öffne Edge-Fenster $($i + 1) mit URL: $($URLs[$i])" $proc = Start-Process -FilePath "msedge.exe" -ArgumentList "--new-window", $URLs[$i] -PassThru $EdgeProcesses += $proc } Start-Sleep -Seconds 10 # 获取每个进程对应的窗口句柄并操控 foreach ($proc in $EdgeProcesses) { $windowHandles = [WindowFinder]::GetWindowsByProcessId($proc.Id) if ($windowHandles.Count -gt 0) { Write-Host "Fenster für Prozess ID $($proc.Id) gefunden: $windowHandles" # 调整窗口位置和大小 [WinAPI]::MoveWindow($windowHandles[0], 0, 0, 1920, 1080, $true) } else { Write-Host "Kein sichtbares Fenster für Prozess ID $($proc.Id) gefunden." } }
方案二:类名+标题模糊匹配
指定Edge窗口类名Chrome_WidgetWin_1,并通过模糊匹配标题定位窗口,避免完全匹配的限制:
Add-Type @" using System; using System.Runtime.InteropServices; public class WinAPI { [DllImport("user32.dll")] public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); [DllImport("user32.dll")] public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); [DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder text, int count); [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr hWnd); } "@ function GetEdgeWindowByTitlePart { param ( [string]$titlePart ) $hWnd = [IntPtr]::Zero do { $hWnd = [WinAPI]::FindWindowEx([IntPtr]::Zero, $hWnd, "Chrome_WidgetWin_1", $null) if ($hWnd -ne [IntPtr]::Zero -and [WinAPI]::IsWindowVisible($hWnd)) { $titleBuilder = New-Object System.Text.StringBuilder(256) [WinAPI]::GetWindowText($hWnd, $titleBuilder, 256) $windowTitle = $titleBuilder.ToString() if ($windowTitle -like "*$titlePart*") { return $hWnd } } } while ($hWnd -ne [IntPtr]::Zero) return [IntPtr]::Zero } # 使用示例:查找包含"Google - Profil 1"的Edge窗口 $hWnd = GetEdgeWindowByTitlePart "Google - Profil 1" if ($hWnd -ne [IntPtr]::Zero) { [WinAPI]::MoveWindow($hWnd, 0, 0, 1920, 1080, $true) }
方案三:自定义窗口标题启动
使用Edge的--app和--window-title参数,以应用窗口模式打开网页并自定义标题,后续可直接通过标题精准匹配:
$URLs = @("https://www.youtube.com", "https://google.de", "https://heise.de", "https://amazon.de", "https://f-i.de") # 启动时自定义窗口标题 for ($i = 0; $i -lt $URLs.Count; $i++) { $customTitle = "Edge-View-$($i+1)" Write-Host "Öffne Edge-Fenster $($i + 1) mit URL: $($URLs[$i]) und Titel: $customTitle" Start-Process -FilePath "msedge.exe" -ArgumentList "--app=$($URLs[$i])", "--window-title=$customTitle" } # 后续通过自定义标题查找窗口 Add-Type @" using System; using System.Runtime.InteropServices; public class WinAPI { [DllImport("user32.dll")] public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); [DllImport("user32.dll")] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); } "@ $hWnd = [WinAPI]::FindWindow("Chrome_WidgetWin_1", "Edge-View-1") if ($hWnd -ne [IntPtr]::Zero) { [WinAPI]::MoveWindow($hWnd, 0, 0, 1920, 1080, $true) }
内容的提问来源于stack exchange,提问作者KilianJATO
相关产品推荐
相关产品推荐

