GetWindow 是 Windows API (Application Programming Interface) 的一部分,而不是 C 语言标准库(如 stdio.h, stdlib.h)中的函数。

(图片来源网络,侵删)
这意味着,你只能在 Windows 操作系统上,使用支持 Windows 编程的 C 编译器(如 Visual Studio, MinGW)来使用它,它的作用是获取与指定窗口有特定关系的另一个窗口的句柄。
函数原型
GetWindow 函数在 winuser.h 头文件中声明,其原型如下:
HWND GetWindow( HWND hWnd, // 要查询的窗口句柄 UINT uCmd // 查询命令 );
参数详解
-
hWnd(HWND):- 类型:
HWND(Handle to a Window),即窗口句柄。 - 含义: 你想以其为基准进行查询的那个窗口的句柄,你可以通过其他函数(如
FindWindow,GetForegroundWindow)来获取这个句柄。 - 值: 如果此参数为
NULL,函数的行为取决于uCmd的值(见下文)。
- 类型:
-
uCmd(UINT):
(图片来源网络,侵删)- 类型:
UINT(Unsigned Integer),一个无符号整数。 - 含义: 指定你想获取哪种关系的窗口,这是一个预定义的常量,定义在
winuser.h中,以下是几个最常用的命令:
- 类型:
| 命令常量 | 值 | 含义 |
|---|---|---|
GW_HWNDFIRST |
0 | �回指定窗口所在Z序(Z-order)的第一个窗口(顶层窗口)。hWnd 是 NULL,则返回桌面窗口的顶层子窗口(通常是“Program Manager”)。 |
GW_HWNDLAST |
1 | 返回指定窗口所在Z序的最后一个窗口(底层窗口)。 |
GW_HWNDNEXT |
2 | 返回Z序中下一个窗口(在指定窗口之上的窗口)。 |
GW_HWNDPREV |
3 | 返回Z序中上一个窗口(在指定窗口之下的窗口)。 |
GW_OWNER |
4 | 返回指定窗口的所有者窗口。 |
GW_CHILD |
5 | 返回指定窗口的第一个子窗口。 |
GW_ENABLEDPOPUP |
6 | 返回指定窗口的已启用的弹出式窗口,如果没有已启用的弹出窗口,则返回 NULL。 |
返回值
- 成功: 返回满足条件的窗口的句柄 (
HWND)。 - 失败: 返回
NULL,你可以调用GetLastError()函数来获取更详细的错误信息。
工作原理:Z-Order (窗口顺序)
GetWindow 的核心功能之一是沿着 Z-Order(窗口的堆叠顺序)进行导航。
- Z-Order 决定了窗口在屏幕上的显示层次,Z-Order 最顶层的窗口会覆盖在其他窗口之上。
- 当你打开多个窗口时,你点击的窗口会自动被置于 Z-Order 的最顶层。
GW_HWNDNEXT和GW_HWNDPREV就是用来在这个“窗口堆栈”中向上或向下移动的。
代码示例
下面是一个完整的 C 语言示例,演示如何使用 GetWindow,这个程序会获取当前活动窗口的句柄,然后找到它的下一个窗口(Z-Order 中在它上面的那个)并打印其标题。
编译环境: Visual Studio 或 MinGW (gcc)。
#include <windows.h>
#include <stdio.h> // 用于 printf
int main() {
// 1. 获取当前活动窗口的句柄
HWND hWndForeground = GetForegroundWindow();
if (hWndForeground == NULL) {
printf("无法获取前台窗口句柄,错误代码: %lu\n", GetLastError());
return 1;
}
// 2. 获取前台窗口的标题
char windowTitle[256];
if (GetWindowTextA(hWndForeground, windowTitle, sizeof(windowTitle)) == 0) {
printf("无法获取窗口标题,错误代码: %lu\n", GetLastError());
// 窗口可能没有标题,所以我们继续执行
strcpy_s(windowTitle, sizeof(windowTitle), "[无标题]");
}
printf("当前活动窗口: %s (句柄: %p)\n", windowTitle, (void*)hWndForeground);
// 3. 使用 GetWindow 获取 Z-Order 中的下一个窗口
HWND hWndNext = GetWindow(hWndForeground, GW_HWNDNEXT);
if (hWndNext == NULL) {
printf("当前窗口已经是顶层窗口,没有下一个窗口了,\n");
} else {
// 获取下一个窗口的标题
char nextWindowTitle[256];
if (GetWindowTextA(hWndNext, nextWindowTitle, sizeof(nextWindowTitle)) == 0) {
strcpy_s(nextWindowTitle, sizeof(nextWindowTitle), "[无标题]");
}
printf("它的下一个窗口是: %s (句柄: %p)\n", nextWindowTitle, (void*)hWndNext);
}
// 4. 另一个例子:获取窗口的所有者
HWND hWndOwner = GetWindow(hWndForeground, GW_OWNER);
if (hWndOwner == NULL) {
printf("该窗口没有所有者,\n");
} else {
char ownerWindowTitle[256];
if (GetWindowTextA(hWndOwner, ownerWindowTitle, sizeof(ownerWindowTitle)) == 0) {
strcpy_s(ownerWindowTitle, sizeof(ownerWindowTitle), "[无标题]");
}
printf("该窗口的所有者是: %s (句柄: %p)\n", ownerWindowTitle, (void*)hWndOwner);
}
return 0;
}
如何运行和测试这个示例
- 将代码保存为
getwindow_example.c。 - 使用 Visual Studio 创建一个“控制台应用”项目,并将此代码添加进去。
- 或者,使用 MinGW (gcc) 命令行编译:
gcc getwindow_example.c -o getwindow_example.exe
- 运行生成的
.exe文件。 - 测试: 在运行程序后,用鼠标点击不同的窗口(记事本、浏览器、命令行窗口本身),然后观察程序输出的变化,你会发现
GetForegroundWindow()总是返回你当前点击的窗口。
重要注意事项和替代方案
注意事项
- 已废弃: 微软官方文档将
GetWindow标记为“已废弃”(deprecated),这意味着它可能在未来的 Windows 版本中被移除或行为发生改变。强烈建议使用替代函数。 - 不可靠性:
GetWindow在某些复杂窗口结构(如多文档界面 MDI)中可能表现不正确,因为它只查找直接相邻的窗口,而不考虑窗口的父子或所有者关系。 - 性能: 在循环中频繁调用
GetWindow可能会影响性能。
推荐的替代方案
微软推荐使用更精确、更可靠的函数来替代 GetWindow。
| 原始命令 | 推荐替代方案 | 说明 |
|---|---|---|
GW_HWNDNEXT / GW_HWNDPREV |
EnumChildWindows / EnumThreadWindows |
这两个回调函数可以枚举指定窗口的子窗口或指定线程的所有窗口,提供了更强大的控制能力。 |
GW_OWNER |
GetWindowLongPtr(hWnd, GWLP_HWNDPARENT) |
这是获取窗口父窗口(所有者)的标准方法。 |
GW_CHILD |
GetWindowLongPtr(hWnd, GWLP_HWNDPARENT) (不适用) |
对于获取子窗口,没有直接的替代品。GetWindow 的 GW_CHILD 在简单情况下仍然可用,但对于复杂场景,EnumChildWindows 是更好的选择。 |
GW_HWNDFIRST / GW_HWNDLAST |
GetTopWindow / GetWindow (谨慎使用) |
GetTopWindow(hWnd) 可以获取指定窗口的顶层子窗口。GetWindow 的这两个命令是特定于 Z-Order 的,没有完美的 1:1 替代。 |
虽然你可以使用 GetWindow,并且在很多简单场景下它能工作,但为了代码的健壮性和未来的兼容性,你应该优先学习和使用微软推荐的替代函数。GetWindow 更多地被视为一种遗留工具。
