You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

咨询问题

  1. 为什么GetWindow函数无法找到已打开的Edge窗口?
  2. 有没有更可靠的方法确保窗口能被正确找到并操控?

问题解答

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 16:00:54