FindWindow 是 Windows API(应用程序编程接口)中的一个函数,它不属于标准 C 语言库(如 stdio.h, stdlib.h 等),要在 C 语言中使用它,你需要包含 Windows 的头文件,并链接相应的库。

FindWindow 是什么?
FindWindow 函数用于查找顶层窗口的窗口句柄,它的核心作用是根据窗口类名或来找到一个已经存在的窗口。
函数原型:
HWND FindWindowW( [in, optional] LPCWSTR lpClassName, [in, optional] LPCWSTR lpWindowName );
或者其 ANSI 版本(在旧系统或不使用 Unicode 的项目中更常见):
HWND FindWindowA( [in, optional] LPCSTR lpClassName, [in, optional] LPCSTR lpWindowName );
参数说明:

-
lpClassName(窗口类名):- 一个以 null 结尾的字符串,指定了窗口的类名。
- 你可以使用像 Spy++ (Visual Studio 自带工具) 或 AutoIt v3 这样的工具来获取其他应用程序的窗口类名。
- 如果此参数为
NULL,则函数会忽略类名,只根据窗口标题进行匹配。
-
lpWindowName(窗口标题):- 一个以 null 结尾的字符串,指定了窗口的标题(也就是你通常在窗口标题栏看到的文字)。
- 如果此参数为
NULL,则函数会忽略窗口标题,只根据类名进行匹配。
-
返回值:
- 如果找到匹配的窗口,函数返回该窗口的句柄,这是一个
HWND类型的值,可以理解为窗口的“身份证号”。 - 如果没有找到匹配的窗口,函数返回
NULL。
- 如果找到匹配的窗口,函数返回该窗口的句柄,这是一个
重要提示:Unicode 和 ANSI
在 Windows 中,为了支持多语言字符(如中文、日文、韩文等),引入了 Unicode 字符集(宽字符 wchar_t),现代 C/C++ 项目默认使用 Unicode。
FindWindowW是 Unicode 版本,使用LPCWSTR(宽字符字符串)。FindWindowA是 ANSI 版本,使用LPCSTR(单字节/多字节字符字符串)。
在 Visual Studio 中,当你包含 windows.h 时,预定义宏会使得 FindWindow 这个名字自动指向 FindWindowW 或 FindWindowA。强烈建议使用 Unicode 版本 (FindWindowW),因为它能更好地处理非英文字符。
如何在 C 语言中使用 FindWindow
基本步骤
- 包含头文件: 包含
windows.h,它定义了所有 Windows API 的数据类型、函数和常量。 - 链接库:
FindWindow函数位于user32.dll中,包含windows.h后,链接器会自动为你链接这个库,无需手动操作。 - 调用函数: 使用你已知的窗口类名或窗口标题调用
FindWindow。 - 检查返回值: 检查返回的
HWND是否为NULL,以判断是否成功找到窗口。 - 使用句柄: 如果找到窗口,就可以用这个
HWND句柄进行后续操作,例如发送消息、激活窗口、关闭窗口等。
代码示例
下面是一个完整的 C 语言控制台程序示例,它会尝试查找“记事本”窗口。
场景:
- 目标窗口: 记事本 (Notepad.exe)
- : 通常为“无标题 - 记事本”(如果你还没保存文件)。
- 窗口类名: 可以通过 Spy++ 工具查到,记事本的类名通常是
"Notepad"。
示例 1:通过窗口标题查找
这是最简单直接的方式。
#include <windows.h>
#include <stdio.h> // 用于 printf
int main() {
// 1. 定义要查找的窗口标题
LPCWSTR windowTitle = L"无标题 - 记事本"; // 使用 L 前缀表示宽字符字符串
// 2. 调用 FindWindow 函数
// 第一个参数为 NULL,表示我们不关心窗口类名
HWND hWnd = FindWindow(NULL, windowTitle);
// 3. 检查是否找到窗口
if (hWnd != NULL) {
// 找到窗口
wprintf(L"成功找到窗口!句柄为: %p\n", hWnd);
// 在这里可以对这个窗口进行其他操作...
} else {
// 未找到窗口
wprintf(L"未找到标题为 \"%s\" 的窗口,\n", windowTitle);
wprintf(L"请确保记事本已经打开并且标题匹配,\n");
}
return 0;
}
如何编译和运行 (在 Visual Studio 中):
- 创建一个新的“控制台应用”项目。
- 将上面的代码复制到
main.c文件中。 - 先手动打开一个记事本窗口,确保它的标题是“无标题 - 记事本”。
- 按 F5 运行程序。
如何编译和运行 (使用 MinGW/g++ 命令行):
# 编译 gcc main.c -o find_window_example # 运行 (先确保记事本已打开) ./find_window_example
示例 2:通过窗口类名查找
这种方式更可靠,因为用户可能修改了记事本的标题,但类名通常是固定的。
#include <windows.h>
#include <stdio.h>
int main() {
// 1. 定义要查找的窗口类名
LPCWSTR className = L"Notepad";
// 2. 调用 FindWindow 函数
// 第二个参数为 NULL,表示我们不关心窗口标题
HWND hWnd = FindWindow(className, NULL);
// 3. 检查是否找到窗口
if (hWnd != NULL) {
wprintf(L"成功找到类名为 \"%s\" 的窗口!句柄为: %p\n", className, hWnd);
} else {
wprintf(L"未找到类名为 \"%s\" 的窗口,\n", className);
wprintf(L"请确保记事本已经打开,\n");
}
return 0;
}
示例 3:同时使用类名和标题查找(最精确)
#include <windows.h>
#include <stdio.h>
int main() {
LPCWSTR className = L"Notepad";
LPCWSTR windowTitle = L"无标题 - 记事本";
// 同时提供类名和标题进行精确查找
HWND hWnd = FindWindow(className, windowTitle);
if (hWnd != NULL) {
wprintf(L"成功同时匹配类名和标题找到窗口!句柄为: %p\n", hWnd);
} else {
wprintf(L"未找到同时匹配类名 \"%s\" 和标题 \"%s\" 的窗口,\n", className, windowTitle);
}
return 0;
}
常见问题与注意事项
-
找不到窗口怎么办?
- 确认窗口已打开: 确保你要查找的程序实例正在运行。
- /类名正确: 使用 Spy++ 或类似工具 100% 确认类名和标题,标题可能会变(记事本保存文件后标题会变成文件名)。
- 大小写敏感:
FindWindow的匹配是不区分大小写的,但最好还是保持一致。 - 权限问题: 某些系统级别的窗口可能需要管理员权限才能访问。
-
FindWindow的局限性- 只能查找顶层窗口: 它不能查找对话框内的按钮、编辑框等子窗口,要查找子窗口,需要使用
FindWindowEx函数。 - 效率问题: 如果系统窗口非常多,遍历所有窗口可能会稍微慢一点。
- 只能查找顶层窗口: 它不能查找对话框内的按钮、编辑框等子窗口,要查找子窗口,需要使用
-
现代应用程序 (UWP/WinUI) 对于现代的 UWP 应用(如 Microsoft Store 里的应用),它们的窗口机制与传统 Win32 应用不同,
FindWindow可能无法正常工作,这些应用通常使用“Application Frame Host”作为顶层窗口,内部的具体窗口结构更复杂。
FindWindow 是 Windows C 编程中一个非常基础且强大的工具,用于获取窗口的“身份证号”(HWND),它通常是你与另一个已运行的 GUI 程序进行交互(例如自动化测试、数据获取等)的第一步。
核心要点回顾:
- 头文件:
#include <windows.h> - 函数:
HWND FindWindowW(LPCWSTR className, LPCWSTR windowName); - 参数:
className(窗口类名) 和windowName(窗口标题),可以为NULL。 - 返回值: 成功返回
HWND句柄,失败返回NULL。 - 实践: 先用 Spy++ 获取目标窗口的准确信息,再编写代码进行查找。
