Delphi 中 FindWindow 和 FindWindowEx 的语法和用法

本文介绍了Delphi编程语言中FindWindow和FindWindowEx函数的语法、用法,并通过实例展示了如何查找特定窗口的句柄。

 Delphi 中 FindWindow 和 FindWindowEx 的语法和用法

FindWindow(
lpClassName,        {窗口的类名}
lpWindowName: PChar {窗口的标题}
): HWND;              {返回窗口的句柄; 失败返回 0}

//FindWindowEx 比 FindWindow 多出两个句柄参数:
FindWindowEx(
Parent: HWND;     {要查找子窗口的父窗口句柄}
Child: HWND;      {子窗口句柄}
ClassName: PChar; {}
WindowName: PChar {}
): HWND;
{
如果 Parent 是 0, 则函数以桌面窗口为父窗口, 查找桌面窗口的所有子窗口;
如果 是 HWND_MESSAGE, 函数仅查找所有消息窗口;
子窗口必须是 Parent 窗口的直接子窗口;
如果 Child 是 0, 查找从 Parent 的第一个子窗口开始;
如果 Parent 和 Child 同时是 0, 则函数查找所有的顶层窗口及消息窗口.
}




//测试1: 试着找找新建程序主窗口的句柄
var
h: HWND;
begin
{现在我们知道窗口的标题是: Form1、窗口的类名是: TForm1}
h := FindWindow( 'TForm1', 'Form1');
ShowMessage(IntToStr(h));      {656180; 这是随机, 每次启动窗口肯定不一样}

{假如不知道类名}
h := FindWindow( nil, 'Form1');
ShowMessage(IntToStr(h));      {656180}

{假如不知道标题名}
h := FindWindow( 'TForm1', nil);
ShowMessage(IntToStr(h));      {656180}

{其实这个窗口的句柄不就是 Self.Handle 吗}
ShowMessage(IntToStr(Handle)); {656180}
end;



//测试2: 找计算器窗口的句柄(先打开计算器)
var
h: HWND;
begin
{如果不是简体中文系统, 这样可能不灵}
h := FindWindow( nil, '计算器');
ShowMessage(IntToStr(h)); {1508334}

{最好这样, 但你得提前知道计算器窗口的类名是: SciCalc}
h := FindWindow( 'SciCalc', nil);
ShowMessage(IntToStr(h)); {1508334}
end;
<think> 我们正在讨论Windows API中的FindWindowFindWindowEx函数。用户已经明确询问这两个函数的区别。根据先前的对话历史引用内容,我们可以总结如下: 引用[1]提供了FindWindowEx的函数原型: ```cpp HWND FindWindowEx( HWND hwndParent, // 父窗口句柄 HWND hwndChildAfter, // 指定子窗口句柄,搜索从该子窗口之后开始 LPCTSTR lpszClass, // 指向类名字符串 LPCTSTR lpszWindow // 指向窗口名字符串 ); ``` 而FindWindow的函数原型(之前回答中已给出)是: ```cpp HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName); ``` 因此,主要区别在于: 1. **功能范围**: - `FindWindow` 用于在顶级窗口(即桌面窗口的直接子窗口)中查找匹配指定类名/或窗口名的第一个窗口。 - `FindWindowEx` 用于在指定的父窗口内查找子窗口(可以指定从哪个子窗口之后开始搜索),因此它用于查找子窗口(包括控件等)。 2. **参数差异**: - `FindWindow` 只有两个参数:类名窗口名。 - `FindWindowEx` 有四个参数: - `hwndParent`:指定要搜索子窗口的父窗口句柄。如果为NULL,则函数使用桌面窗口作为父窗口,即查找所有顶级窗口(此时与FindWindow类似,但行为仍有差异)。 - `hwndChildAfter`:指定一个子窗口句柄,查找将从该子窗口之后开始(即跳过该子窗口及其之前的所有子窗口)。如果为NULL,则从第一个子窗口开始搜索。 - `lpszClass` `lpszWindow`:与FindWindow相同,分别为类名窗口名(标题)。 3. **搜索方式**: - `FindWindow` 只能查找顶级窗口,且只能返回第一个匹配的窗口。 - `FindWindowEx` 可以查找指定父窗口下的子窗口,并且可以通过多次调用(每次传递上一次找到的子窗口句柄作为`hwndChildAfter`)来遍历所有子窗口。 4. **使用场景**: - 当需要查找一个已知类名或标题的顶级窗口(如记事本、计算器等)时,使用`FindWindow`。 - 当需要查找一个窗口中的子控件(如按钮、编辑框等)时,使用`FindWindowEx`。例如,在对话框中查找一个特定的按钮。 引用[2]中提到,有时子窗口句柄可能获取不到,这可能是由于窗口层次结构复杂或者窗口属于其他进程且未暴露其子窗口信息(如某些使用自定义控件的窗口)。同时,引用[2]提醒我们:窗口名称指的是窗口的标题(在任务管理器中看到的名称),而不是程序中的变量名。 因此,总结如下: ### FindWindowFindWindowEx的主要区别 | 特性 | FindWindow | FindWindowEx | |---------------------|---------------------------------|---------------------------------------------| | **搜索范围** | 仅顶级窗口 | 指定父窗口的子窗口(或顶级窗口,当父窗口为NULL时) | | **参数** | 类名、窗口名 | 父窗口句柄、起始子窗口句柄、类名、窗口名 | | **遍历能力** | 只能返回第一个匹配的顶级窗口 | 可通过循环遍历所有子窗口(通过改变hwndChildAfter) | | **典型应用场景** | 查找应用程序主窗口 | 查找对话框中的控件(如按钮、文本框) | ### 使用示例(C++伪代码) #### FindWindow示例(查找记事本主窗口): ```cpp HWND hWnd = FindWindow(TEXT("Notepad"), NULL); // 类名为"Notepad",窗口名任意 ``` #### FindWindowEx示例(查找父窗口下的第一个按钮): ```cpp // 假设hWndParent是一个已知的对话框句柄 HWND hButton = FindWindowEx(hWndParent, NULL, TEXT("Button"), TEXT("确定")); // 从第一个子窗口开始查找,类名为"Button",窗口名为"确定"的按钮 ``` ### 注意事项 - 如果使用`FindWindowEx`来查找顶级窗口,可以将`hwndParent`设置为`NULL`,此时它将在所有顶级窗口中查找(类似于`FindWindow`),但有以下不同: - `FindWindow`只查找匹配的第一个顶级窗口。 - 而`FindWindowEx`在`hwndParent`为NULL时,也是查找第一个匹配的顶级窗口(因为顶级窗口的父窗口是桌面,桌面是顶级窗口的父窗口)。但是,通过改变`hwndChildAfter`,可以遍历所有顶级窗口(尽管通常用EnumWindows来枚举顶级窗口)。 - 在查找子窗口时,如果目标窗口有多个相同类名标题的子窗口,可以使用循环来遍历: ```cpp HWND hChild = NULL; do { hChild = FindWindowEx(hParent, hChild, className, windowTitle); if (hChild) { // 处理找到的子窗口 } } while (hChild); ``` ### 引用说明 根据引用[1]引用[2],我们强调: - 获取窗口名称(标题)可以通过任务管理器等工具[^2]。 - 子窗口句柄可能因窗口类型权限问题而获取失败,特别是在跨进程操作时[^2]。 §§相关问题§§ 1. 如何使用FindWindowEx遍历所有子窗口? 2. 在跨进程操作时,FindWindowFindWindowEx有什么限制? 3. 如何获取窗口的类名以用于FindWindowEx? </think> ### FindWindowFindWindowEx函数的区别详解 在Windows API中,`FindWindow``FindWindowEx`都是用于获取窗口句柄的关键函数,但它们在功能使用场景上有本质区别。以下是两者的详细对比: | **特性** | **FindWindow** | **FindWindowEx** | |------------------|------------------------------------|--------------------------------------| | **核心功能** | 查找顶级窗口(主窗口) | 查找子窗口(控件/嵌套窗口) | | **参数数量** | 2个:类名 + 窗口标题 | 4个:父窗口 + 起始位置 + 类名 + 标题 | | **搜索范围** | 整个桌面窗口层级 | 指定父窗口的内部子窗口层级 | | **遍历能力** | 只能返回第一个匹配项 | 支持遍历所有子窗口 | | **典型应用场景** | 查找应用程序主窗口(如记事本) | 查找对话框内的按钮/文本框控件 | #### 1. **函数原型对比** ```cpp // FindWindow (查找顶级窗口) HWND FindWindow( LPCTSTR lpClassName, // 窗口类名 LPCTSTR lpWindowName // 窗口标题 ); // FindWindowEx (查找子窗口) HWND FindWindowEx( HWND hwndParent, // 父窗口句柄(必须指定) HWND hwndChildAfter, // 起始搜索位置(NULL表示从第一个子窗口开始) LPCTSTR lpszClass, // 控件类名(如"Button") LPCTSTR lpszWindow // 控件标题(如"确定") ); ``` #### 2. **关键区别解析** - **搜索范围** - `FindWindow`:只在**顶级窗口**(桌面直接子窗口)中搜索,无法访问子控件。 - `FindWindowEx`:在**指定父窗口内**搜索子窗口(包括按钮、编辑框等控件),通过`hwndParent`参数指定搜索范围[^1]。 - **遍历能力** - `FindWindow`:仅返回**第一个匹配的窗口**,无法获取多个同名窗口。 - `FindWindowEx`:支持**遍历所有子窗口**(通过循环更新`hwndChildAfter`参数),例如: ```cpp HWND hChild = NULL; do { hChild = FindWindowEx(hParent, hChild, "Button", NULL); // 查找所有按钮 if (hChild) { /* 处理按钮 */ } } while (hChild); ``` - **参数差异** - `hwndChildAfter`:指定从哪个子窗口之后开始搜索(用于遍历)。 - `hwndParent`:必须提供父窗口句柄(可通过`FindWindow`获取)[^1][^2]。 #### 3. **使用场景示例** **场景:操作记事本的"保存"按钮** ```cpp // 步骤1: 用FindWindow获取记事本主窗口 HWND hNotepad = FindWindow("Notepad", NULL); // 步骤2: 用FindWindowEx查找"保存"按钮 HWND hSaveButton = FindWindowEx( hNotepad, // 父窗口=记事本 NULL, // 从第一个子控件开始 "Button", // 按钮类名 "保存(&S)" // 按钮标题(通过Spy++获取) ); // 步骤3: 点击按钮 SendMessage(hSaveButton, BM_CLICK, 0, 0); ``` #### 4. **常见问题与注意事项** - **子窗口查找失败**: 如引用[2]所述,某些程序(如Java应用)使用自定义控件,类名可能无法识别。此时需用`SPY++`等工具动态获取类名[^2]。 - **参数传递技巧**: - 若只关心类名:设置`lpszWindow = NULL` - 若只关心标题:设置`lpszClass = NULL` - 避免同时为空(可能匹配错误窗口) - **替代方案**: 当`FindWindowEx`无法获取控件时,可尝试: 1. `EnumChildWindows`(枚举所有子窗口) 2. `GetDlgItem`(通过控件ID查找) > ⚠️ **注意**:窗口标题必须是实际显示的文本(如"确定"),而非代码中的变量名[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值