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

PowerShell如何区分同进程的两个记事本窗口并分别设置位置

问题原因

核心原因:Windows 10 1903及以上版本的默认记事本采用单进程多窗口架构,多个打开的记事本窗口会共享同一个进程ID,你按照PID筛选进程后调用Set-Window时,会默认操作该进程下所有可见窗口,因此两次调用会把所有窗口都设置为最后一次指定的位置。

解决方案

方案1:修改记事本配置(最简单,可复用原有代码)

操作步骤:

  • 打开任意记事本窗口,点击顶部「设置」按钮(齿轮图标)
  • 在「常规」选项卡下找到「启动」分类
  • 勾选「在单独的进程中打开每个窗口」
  • 重启所有记事本窗口,之后每个记事本窗口都会对应独立的PID,你最初的按PID调用Set-Window的代码即可正常运行。

方案2:不改配置,按窗口句柄区分操作

不需要修改记事本设置,直接通过Win32 API枚举同一进程下的所有独立窗口,用唯一的窗口句柄(HWnd)区分不同窗口进行定位:
首先粘贴以下代码导入所需的Win32 API:

Add-Type @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
    public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool IsWindowVisible(IntPtr hWnd);
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder text, int count);
    [DllImport("user32.dll")]
    public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
}
"@

然后运行以下代码获取所有记事本窗口对象:

$notepadList = Get-Process notepad
$allNotepadWindows = @()

foreach ($proc in $notepadList) {
    [Win32]::EnumWindows({
        param($hWnd, $lParam)
        if ([Win32]::IsWindowVisible($hWnd)) {
            $pidOut = 0
            [Win32]::GetWindowThreadProcessId($hWnd, [ref]$pidOut)
            if ($pidOut -eq $proc.Id) {
                $titleBuilder = New-Object System.Text.StringBuilder 256
                [Win32]::GetWindowText($hWnd, $titleBuilder, $titleBuilder.Capacity) | Out-Null
                $allNotepadWindows += [PSCustomObject]@{
                    HWnd = $hWnd
                    Title = $titleBuilder.ToString()
                    ProcessId = $pidOut
                }
            }
        }
        return $true
    }, [IntPtr]::Zero)
}

运行后输入$allNotepadWindows即可看到所有记事本窗口,每个窗口都有唯一的HWnd属性,根据标题区分你要移动的两个窗口后,直接调用MoveWindow API设置位置即可:

# 第一个窗口放左侧
[Win32]::MoveWindow($allNotepadWindows[0].HWnd, -8, 0, 976, 1038, $true)
# 第二个窗口放右侧
[Win32]::MoveWindow($allNotepadWindows[1].HWnd, 952, 0, 976, 1038, $true)
原代码失效说明

你使用Start-Job的方案无效,是因为后台任务中获取到的记事本进程和前台是同一个,没有做窗口区分,调用Set-Window时仍然会操作该进程下的所有窗口,相当于覆盖了前一次的位置设置。

内容的提问来源于stack exchange,提问作者ArthurR

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 15:15:04