Windows API 根据进程 ID 查找窗口的 HWND

在 Windows API 中,从进程 ID (PID) 获取窗口句柄 (HWND) 并没有一个直接的单一步骤函数(如 GetWindowByPid),因为一个进程可能拥有多个顶级窗口,也可能完全没有窗口。

通常的做法是枚举系统中的所有顶级窗口,并检查每个窗口所属的进程 ID 是否与目标 PID 匹配。

核心实现逻辑

最标准且高效的方法是使用 EnumWindows 函数。

  1. 定义一个结构体:用于在回调函数中存储目标 PID 和返回的 HWND。
  2. 调用 EnumWindows:该函数会遍历屏幕上的所有顶级窗口。
  3. 编写回调函数
    • 使用 GetWindowThreadProcessId 获取当前枚举窗口的 PID。
    • 对比该 PID 与目标 PID。
    • 如果匹配,检查是否是主窗口(通常通过 IsWindowVisibleGetWindow(hwnd, GW_OWNER) 进一步筛选)。
    • 保存 HWND 并停止枚举。

C++ 代码示例

1#include <windows.h>
2#include <iostream>
3
4// 用于传递数据给回调函数的结构体
5struct EnumData {
6    DWORD targetPid;
7    HWND hWnd;
8};
9
10// EnumWindows 的回调函数
11BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) {
12    EnumData* data = (EnumData*)lParam;
13    DWORD windowPid = 0;
14
15    // 获取该窗口所属的进程 ID
16    GetWindowThreadProcessId(hWnd, &windowPid);
17
18    // 如果 PID 匹配 且 是主窗口(没有所有者)
19    if (windowPid == data->targetPid && GetWindow(hWnd, GW_OWNER) == NULL && IsWindowVisible(hWnd)) {
20        data->hWnd = hWnd;
21        return FALSE; // 找到目标,停止枚举
22    }
23
24    return TRUE; // 继续枚举
25}
26
27HWND GetHwndByPid(DWORD pid) {
28    EnumData data;
29    data.targetPid = pid;
30    data.hWnd = NULL;
31
32    EnumWindows(EnumWindowsProc, (LPARAM)&data);
33
34    return data.hWnd;
35}
36
37int main() {
38    DWORD pid = 1234; // 替换为你的目标 PID
39    HWND hWnd = GetHwndByPid(pid);
40
41    if (hWnd) {
42        std::cout << "找到窗口句柄: " << hWnd << std::endl;
43    } else {
44        std::cout << "未找到该进程的窗口。" << std::endl;
45    }
46    return 0;
47}
48

关键函数说明

函数作用
EnumWindows枚举屏幕上所有的顶级窗口,每发现一个窗口就调用一次回调函数。
GetWindowThreadProcessId获取创建指定窗口的线程 ID,并通过输出参数返回进程 ID
IsWindowVisible确保你找到的是用户能看到的窗口,而不是进程创建的隐藏辅助窗口。
GetWindow(hWnd, GW_OWNER)检查窗口是否有所有者。通常“主窗口”没有所有者(返回 NULL)。