枚举遍历所有子窗口句柄控件类型标题

为指定的父窗口枚举子窗口、按钮

  很早就写过类似spy++和查看密码窗口的东西,一直想给这个小东西再加点特别的。前段时间对软件安装注册发生了兴趣,有些软件如果你不输入正确注册码,那该死的“下一步”按钮就一直disable。这次我就让spy++彻底spy到底,把那个注册用的按钮置亮,让我轻松进入“下一步”,呵呵…。
  我的想法是光标移到指定的窗口上后,探测这个窗口上到底有多少按钮,如果有,就将它们都Enable。在这里我不想讨论怎样具体实现这个功能,但你要知道的是想得到这些被disable窗口(按钮)的句柄是根本无法通过WindowFromPoint这个API函数得到的,GetWindow也不要妄想了。顺手查了下MSDN,看到EnumChildWindows可是个好东西,可以枚举一个父窗口的所有子窗口:
BOOL EnumChildWindows(
HWND hWndParent, // handle to parent window // 父窗口句柄
WNDENUMPROC lpEnumFunc, // callback function // 回调函数的地址
LPARAM lParam // application-defined value // 你自已定义的参数
);
  就这么简单,让我们再定义一个回调函数,像下面这样:
BOOL CALLBACK EnumChildProc(
HWND hwnd, // handle to child window
LPARAM lParam // application-defined value
);
  注意:这个回调函数要么是类的静态函数,要么就是一个全局的函数。
--------------------------------
  在调用EnumChildWindows 这个函数时,直到调用到最个一个子窗口被枚举或回调函数返回一个false,否则将一直枚举下去。有了上面的知识,我想你应该知道怎么做了。有了回调函数的概念及上面的例子,我们可以继续了。其实想要找到一个标题已知的窗口句柄,用一个API函数就可以了:FindWindow.其函数原形是:
01.function FindWindow(lpClassName, lpWindowName: PChar): HWND; stdcall;
02.lpClassName:窗口类名.如果只知道标题,可以为空.窗口类名可以用很多工具获得.如winsignt32.
lpWindowName:窗口标题.
调用方式举例:
01.var wndhwnd:HWND;
02.wndhwnd:=FindWindow(nil,’某窗口标题’);
03.if wndhwnd<>0 then file://找到此窗口句柄.
04.begin
05. xxxxx
06.end
07.else begin
08. MessageBox(self.handle,’没找到该窗口句柄’,’提示’,0);
09.end;
  有了这个窗口句柄,就离我们的初始目的不远了:控制其他窗体上的窗口控件.同样,首先要得到其他窗体上窗口控件的句柄.我们用这个API函数:EnumChildWindows.其函数原形是:
01.function EnumChildWindows(hWndParent: HWND;
02. lpEnumFunc: TFNWndEnumProc;
03. lParam: LPARAM): BOOL; stdcall;
  这个函数和EnumWindow函数很有些想象.其作用也很相似.它的功能就是列举窗口句柄为hWndParent的窗体上所有的窗口控件的句柄.同样也是以回调函数参数的形式给出的. 我们再举一个实际的例子,来说明这个函数的用法.程序的功能是让用户输入一个窗口标题,然后调用FindWindow函数找到此窗口句柄.通过这个句柄,我们在一个Memo里显示该窗口上所有的窗口控件.同样先编写回调函数.
01.function EnumChildWndProc(AhWnd:LongInt;
02. AlParam:lParam):boolean;stdcall;
03.var04. WndClassName: array[0..254] of Char;
05. WndCaption: array[0..254] of Char;
06.begin
07. GetClassName(AhWnd,wndClassName,254);
08. GetWindowText(aHwnd,WndCaption,254);
09. with form1.memo1 do
10. begin
11. lines.add( string(wndClassName));
12. lines.add( string(wndCaption));
13. lines.add(‘——-‘);
14. end;
15. result:=true;
16.end;
然后在一事件里调用EnumChildWindows函数.

procedure TForm1.Button1Click(Sender: TObject);
var hWnd:LongInt;
begin
memo1.Lines.Clear;
Memo1.Lines.Add(Edit1.Text+’ 有如下控件类名称’);
hWnd:=FindWindow(nil,pchar(Edit1.Text));
if hWnd<>0 then
begin
EnumChildWindows(hWnd,@EnumChildWndProc,0);
end
else MessageBox(self.handle,’没找到该窗口句柄’,’提示’,0);
end;
程序清单如下:
01.unit Unit1;
02.
03.interface
04.
05.uses
06. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
07. Dialogs, StdCtrls;
08.
09.type10. TForm1 = class(TForm)
11. Memo1: TMemo; //用来显示找到的控件
12. Label1: TLabel; 
13. Edit1: TEdit;  //输入标题.
14. Button1: TButton;
15. procedure Button1Click(Sender: TObject);
16. private
17. { Private declarations }
18. public19. { Public declarations }
20. end;
21.
22.var
23. Form1: TForm1;
24.
25. function EnumChildWndProc(AhWnd:LongInt;
26. AlParam:lParam):boolean;stdcall;
27.
28.implementation
29.
30.{$R *.dfm}
31.function EnumChildWndProc(AhWnd:LongInt;
32. AlParam:lParam):boolean;stdcall;
33.
var
34. WndClassName: array[0..254] of Char;
35. WndCaption: array[0..254] of Char;
36.begin
37. GetClassName(AhWnd,wndClassName,254);
38. GetWindowText(aHwnd,WndCaption,254);
39. with form1.memo1 do
40. begin
41. lines.add( string(wndClassName));
42. lines.add( string(wndCaption));
43. lines.add(‘——-‘);
44. end;
45. result:=true;
46.end;
47.
48.procedure TForm1.Button1Click(Sender: TObject);
49.var
50. hWnd:LongInt;
51.begin
52. memo1.Lines.Clear;
53. Memo1.Lines.Add(Edit1.Text+’ 有如下控件类名称’);
54. hWnd:=FindWindow(nil,pchar(Edit1.Text));
55. if hWnd<>0 then
56. begin
57. EnumChildWindows(hWnd,@EnumChildWndProc,0);
58. end
59. else MessageBox(self.handle,’没找到该窗口句柄’,’提示’,0);
60.end;
61.end.
  有了控件句柄,我们当然就可以随心所欲了.比如:
01.SendMessage(hWnd,WM_SETTEXT,0,LongInt(Pchar(‘sdafdsf’)));
  就可以给控件发送文本.其他还可以发送不同的消息可以做很多事情.但是,有很大一个问题:假设一个窗体上有很多相同的控件,并且根本没办法区分他们,即使我们能找到所有的控件句柄,我们又不能区分到底哪个是我们想要的,同样是干着急.我想了很长时间,后来在大富翁里找到了答案,只要用到一个小技巧,就可以解决了.

>

【Demo 0028】获取窗体信息
作为一个窗体,除了具有窗体类信息外还有其自身的一些信息如风格,扩展风格,窗体处理函数外还包括一个用户信息,我们可以通过信息空间将我们要公共信息置入其中实现信息共享. 接下来我们看看它的功能.
(一) 函数声明
LONG_PTR GetWindowLongPtr(HWND hWnd, int nIndex );
获取指定窗体特定标识信息, 此函数支持32位和64位
LONG GetWindowLong(HWND hWnd, int nIndex );
功能同GetWindowLongPtr一致, 但其仅支持32位
nIndex 值可参考
GWL_EXSTYLE
Retrieves the extended window styles. For more information, see CreateWindowEx.
GWL_STYLE
Retrieves the window styles.
GWL_WNDPROC
Retrieves the address of the window procedure, or a handle representing the address of the window procedure.
You must use the CallWindowProc function to call the window procedure.
GWL_HINSTANCE
Retrieves a handle to the application instance.
GWL_HWNDPARENT
Retrieves a handle to the parent window, if any.
GWL_ID
Retrieves the identifier of the window.
GWL_USERDATA
Retrieves the user data associated with the window. This data is intended for use by the application that created the window. Its value is initially zero.
The following values are also available when the hWnd parameter identifies a dialog box.
DWL_DLGPROC
Retrieves the address of the dialog box procedure, or a handle representing the address of the dialog box procedure.
You must use the CallWindowProc function to call the dialog box procedure.
DWL_MSGRESULT
Retrieves the return value of a message processed in the dialog box procedure.
DWL_USER
Retrieves extra information private to the application, such as handles or pointers.

 Code1:
 1.  找到NotePad窗体句柄
 2.  将100 置入NotePad主窗体UserData中

HWND hWndNotePad = FindWindowEx(NULL, NULL, _T(“Notepad”), NULL);
SetWindowLongPtr(hWndNotePad, GWLP_USERDATA, 100);

 Code2:
 1.  获取NotePad窗体句柄
 2.  获取NotePad窗体信息并显示

HWND hWndNotePad = FindWindowEx(NULL, NULL, _T(“Notepad”), NULL);
if (NULL != hWndNotePad && IsWindow(hWndNotePad))
{
int nIndexList[] = { GWL_EXSTYLE, GWL_STYLE, GWLP_WNDPROC, GWLP_HINSTANCE, GWLP_HWNDPARENT,
GWLP_ID, GWLP_USERDATA, DWLP_DLGPROC, DWLP_MSGRESULT, DWLP_USER };
int* nValueList = new int[sizeof(nIndexList) / sizeof(*nIndexList)];
const TCHAR* szInfo[] = { _T(“Extend Style:\t 0xX\n”),
_T(“Style:\t 0xX\n”),
_T(“WndProc: 0xX\n”),
_T(“hInstance: 0xX\n”),
_T(“hParent:\t 0xX\n”),
_T(“ID: 0xX\n”),
_T(“UserData: 0xX\n”),
_T(“DlgProc:\t 0xX\n”),
_T(“MsgResult: 0xX\n”),
_T(“User: 0xX\n”)};
assert((sizeof(nIndexList) / sizeof(*nIndexList)) == (sizeof(szInfo) / sizeof(*szInfo)));

TCHAR szClassInfo[1024] = {0};
TCHAR szTemp[256];
for (int ii = 0; ii < sizeof(nIndexList) / sizeof(*nIndexList); ii++)
{
    nValueList[ii] = GetWindowLongPtr(hWndNotePad, nIndexList[ii]);
    TCHAR szTemp[256];
    _stprintf_s(szTemp, szInfo[ii], nValueList[ii]);
    _tcscat(szClassInfo, szTemp);
}
SetWindowText(GetDlgItem(hWnd, ID_LABINFO), szClassInfo);
OutputDebugString(szClassInfo);
delete[] nValueList;

}

我们可以看到从Demo0028置入100UserData信息

此函数我们使用比较多,通常与SetWindowLongPtr配合使用于,用于设置用户信息、读取窗体风格,以及读取同一进程窗体过程函数以便恢复.
(二) 特别说明
1. 如果用于替换窗体过程函数需要同一个进程中(见后序章节)

>

【Demo 0029】截取同进程窗体消息
今天这个话题比较简单,仅截取同进程的窗体消息,如果我们再做一些处理做成一个DLL然后将DLL驻入到指定进程的窗体中那更有意思了,我们将在后面的章节里再研究一下。我们开始学习了。本节与上一节都在讲述着同相的内容围绕着GetWindowLongPtr, SetWindowLongPtr两个API进行的
(一) 函数声明
LONG_PTR GetWindowLongPtr(HWND hWnd, int nIndex );

  LONG_PTR SetWindowLongPtr(HWND hWnd, int nIndex, LONG_PTR dwNewLong );
  获取/修改Window窗体信息值

  Code1:  通过修改窗体过程函数来截取窗体消息
 1.  为了保存原窗体过程函数, 我们将它到设置USER_DATA位,实现各函数数据共享;
 2.  通过SetWindowLongPtr, 来设置新的窗体过程函数;    

if (!bHook)
{
TCHAR szTmp[MAX_PATH];
TCHAR szClsName[MAX_PATH];
GetClassName(hWnd, szClsName, MAX_PATH);
WNDCLASSEX wcx = {0};
wcx.cbSize = sizeof(WNDCLASSEX);

SetWindowText(GetDlgItem(hWnd, ID_BTNHOOKMSG), _T("Stop Hook"));
OutputDebugString(_T("\n============== Start Hook Message ================\n"));

GetClassInfoEx(GetModuleHandle(NULL), szClsName, &wcx);
_stprintf_s(szTmp, _T("WndProc Value before SetWindowLongPtr: 0x%0X  ==> 0x%0X\n"), wcx.lpfnWndProc, GetWindowLongPtr(hWnd, GWLP_WNDPROC));
OutputDebugString(szTmp);
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)WndProc);
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG)_HookWndProc);
GetClassInfoEx(GetModuleHandle(NULL), szClsName, &wcx);
_stprintf_s(szTmp, _T("WndProc Value After SetWindowLongPtr: 0x%0X  ==> 0x%0X\n"), wcx.lpfnWndProc, GetWindowLongPtr(hWnd, GWLP_WNDPROC));
OutputDebugString(szTmp);
OutputDebugString(_T("==================================================================\n"));
bHook = true;

} else {
SetWindowText(GetDlgItem(hWnd, ID_BTNHOOKMSG), _T(“Start Hook”));
OutputDebugString(_T(“\n============== Stop Hook Message ================\n”));
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)0);
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG)WndProc);
bHook = false;
}
3. 在新的窗体过程函数中打印被截取消息

//////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK _HookWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
TCHAR szTemp[256];
_stprintf_s(szTemp, _T(“[HookProc msg] => hWnd: 0xX nMsg: X wParam: 0xX lParam: 0xX\n”),
hWnd, nMsg, wParam, lParam);
OutputDebugString(szTemp);
WNDPROC _oldWndProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (NULL == _oldWndProc)
{
_oldWndProc = (WNDPROC)GetClassLongPtr(hWnd, GCLP_WNDPROC);
}
return _oldWndProc(hWnd, nMsg, wParam, lParam);
}

演示结果:
1. 没修改窗体过程前
[WndProc msg] => hWnd: 0x010BBA nMsg: 000020 wParam: 0x010BBA lParam: 0x2000012
[WndProc msg] => hWnd: 0x010BBA nMsg: 0000A0 wParam: 0x000012 lParam: 0x282023C
[WndProc msg] => hWnd: 0x010BBA nMsg: 0002A2 wParam: 0x000000 lParam: 0x000000
[WndProc msg] => hWnd: 0x010BBA nMsg: 000086 wParam: 0x000000 lParam: 0x000000
[WndProc msg] => hWnd: 0x010BBA nMsg: 000006 wParam: 0x000000 lParam: 0x000000
[WndProc msg] => hWnd: 0x010BBA nMsg: 00001C wParam: 0x000000 lParam: 0x001B10
[WndProc msg] => hWnd: 0x010BBA nMsg: 000008 wParam: 0x000000 lParam: 0x000000
[WndProc msg] => hWnd: 0x010BBA nMsg: 000281 wParam: 0x000000 lParam: 0xC000000F
[WndProc msg] => hWnd: 0x010BBA nMsg: 000282 wParam: 0x000001 lParam: 0x000000
2. 修改窗体过程之后
============== Start Hook Message ================
WndProc Value before SetWindowLongPtr: 0x8C11B8 ==> 0x8C11B8

WndProc Value After SetWindowLongPtr: 0x8C11B8 ==> 0x8C10DC

[WndProc msg] => hWnd: 0x010BBA nMsg: 000111 wParam: 0x0003E9 lParam: 0x010BBE
[HookProc msg] => hWnd: 0x010BBA nMsg: 000020 wParam: 0x010BBE lParam: 0x2000001
[WndProc msg] => hWnd: 0x010BBA nMsg: 000020 wParam: 0x010BBE lParam: 0x2000001
[HookProc msg] => hWnd: 0x010BBA nMsg: 000020 wParam: 0x010BBE lParam: 0x2000001
[WndProc msg] => hWnd: 0x010BBA nMsg: 000020 wParam: 0x010BBE lParam: 0x2000001
[HookProc msg] => hWnd: 0x010BBA nMsg: 000020 wParam: 0x010BBE lParam: 0x2000001
3. 恢复原窗体过程
============== Stop Hook Message ================
[WndProc msg] => hWnd: 0x010BBA nMsg: 000111 wParam: 0x0003E9 lParam: 0x010BBE
[WndProc msg] => hWnd: 0x010BBA nMsg: 000020 wParam: 0x010BBE lParam: 0x2000001
[WndProc msg] => hWnd: 0x010BBA nMsg: 000020 wParam: 0x010BBE lParam: 0x2000001
[WndProc msg] => hWnd: 0x010BBA nMsg: 000020 wParam: 0x010BBE lParam: 0x2000001
[WndProc msg] => hWnd: 0x010BBA nMsg: 000020 wParam: 0x010BBE lParam: 0x2000001
[WndProc msg] => hWnd: 0x010BBA nMsg: 000020 wParam: 0x010BBE lParam: 0x2000001
[WndProc msg] => hWnd: 0x010BBA nMsg: 000020 wParam: 0x010BBE lParam: 0x2000001
(二) 特别说明
演示的代码里我们也在设置窗体过程函数前后打印了WNDCLASSEX类信息, 也发布我们设置的窗体过程并没有修改了WNDCLASS wndProc;

>

【Demo 0031】遍历顶层窗体
今天我们将讲述如何遍历系统中所有的顶层窗体,讲述之前我们提个问题,什么是顶层窗体,顶层窗体有些什么特点呢? 我引用了Codeguru上的老外的描述看看他是怎么说的:

Q: What is a top-level window?
A: A top-level window is a window that is not child, i.e. it has not WS_CHILD style set.
Notes
unlike the child windows, a top-level window can be displayed anywhere in the screen;
many definitions state that a top-level window is “a window that has no parent”;
that is correct but can lead in a confusion: many people think that every window which is created passing a valid hWndParent in CreateWindow(Ex) “has a parent” then, according to the definition it is not top-level;
in fact hWndParent may be either a handle to parent or owner window;
if hWndParent is a valid window handle and WS_CHILD style is not set, then we have a top-level owned window;
a top-level window can or can not be owned but is never a child; further we can say that it can have an owner but never has a parent.
top-level windows can be either overlapped windows (having WS_OVERLAPPED style and generally used as application main window) or popup windows (having WS_POPUP style, usually temporary windows like message boxes and dialogs);
the coordinates used in CreateWindow(Ex), MoveWindow, SetWindowPos, and so on are always scren coordinates (relative to top-left corner of the screen).
Examples
Code:
// create a top-level window (not owned)
HWND hWnd = CreateWindow(szWindowClass, szTitle,
WS_OVERLAPPED, // WS_CHILD style is not set, so it’s a top-level window.
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
NULL, // no handle to the owner, so it’s not owned.
NULL, hInstance, NULL);
Code:
// create a top-level window (owned)
HWND hWnd = CreateWindow(szWindowClass, szTitle,
WS_OVERLAPPED, // WS_CHILD style is not set, so it’s a top-level window
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
hWndParent, // handle to the owner, so it’s an owned window
NULL, hInstance, NULL);
正如上文所说, 顶层窗体就是不具体WS_CHILD风格的窗体它可以在屏幕上任务拖动, 从文中还加深对CreateWindow 中HWNDPARENT参数的理解,它在风格不为WS_CHILD时,这个Parent 不是父窗体而是拥有者窗体, 同时也让我明白怎么样的窗体是拥有者窗体 (有学到新东西, 心情爽极了! ^_^), 再引用一下什么时拥有者窗体:
Q: What is an owned window?
A: An owned window is a top-level window that has an owner.
It has the following properties:
being a top-level window, it can be displayed anywhere in the screen;
it stays always in the front of its owner window;
it is hidded when its owner is hidden or minimized;
it is destroyed when its owner is being destroyed;
Notes
An owned window is created by passing the owner window handle as hWndParent parameter in CreateWindow(Ex) function call.
WS_CHILD style must not be set, otherwise results a child and not an owned top-level window.
Example
Code:
// create an owned top-level window
HWND hWnd = CreateWindow(szWindowClass, szTitle,
WS_OVERLAPPED, // WS_CHILD style is not set
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
hWndParent, // handle to the OWNER window
NULL, hInstance, NULL);
有了对上文的讲述,我们对下面的内容就好理解多了,通常顶层窗体都是应用窗体的主窗体,可用这个方法找到系统中运行的应用程序(有UI的),系统为达到此目的提供对应的函数:
一、函数声明
BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam);
功能: 遍历屏幕中所有的顶层窗体,并通过预定的回调函数返回遍历到窗体的句柄直到遍历结束或回调函数返回FALSE
回调函数类型: typedef BOOL (CALLBACK* WNDENUMPROC)(HWND, LPARAM);

二、代码演示
1. 设置遍历顶层窗体的回调函数,并将ListBox控件做为参数->(我们通过一个ListBox将顶层窗体信息显示出来)
EnumWindows(EnumWndProc, (LPARAM)GetDlgItem(hWnd, IDC_LSTWNDLIST));
SetWindowText(GetDlgItem(hWnd, IDC_BTNDATAREAD), _T(“Refresh”));

2.  遍历到顶层窗体后

//////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumWndProc(HWND hWnd, LPARAM lParam)
{
HWND hListbox = (HWND)lParam;
if (NULL == hWnd) return FALSE;
if (NULL != hListbox && IsWindow(hListbox))
{
TCHAR szWndInfo[512] = {0};
TCHAR szWndTitle[256] = {0};
TCHAR szClsName[64] = {0};
GetWindowText(hWnd, szWndTitle, 256);
GetClassName(hWnd, szClsName, 64);
_stprintf(szWndInfo,
_T(“´°¿ÚX”)
_T(“\”%s\”“)
_T(“%s”),
hWnd,
szWndTitle,
szClsName);
SendMessage(hListbox, LB_ADDSTRING, 0, (LPARAM)szWndInfo);
}
return TRUE;
}
备注: 若我们要提前退出遍历函数,可将此回调函数返加值设为FALSE即可提前结束遍历;

>

【Demo 0032】遍历子窗体
在上节中我们学习如何遍历顶层窗体,本节中我们继续学习如何遍历子窗体,在例程中我们用使用了二种方法来遍历子窗体;
1. 使用EnumChildWindows 遍历
BOOL EnumChildWindows(HWND hWndParent, WNDENUMPROC lpEnumFunc, LPARAM lParam );
功能: 遍历指定窗体的子窗体,将遍历到的子窗体通知预设的回调函数,并以遍历完子窗体或回调函数返回FALSE结束, 最后一参数用于将信息传递给回调函数
说明: a. 与函数与EnumChildWindows函数用法与EnumWindows几乎一样, EnumWindows 仅能遍历顶层窗体; 此函数枚举的窗体为CreateWindowEx时风格设有WS_CHILD
且父窗体被指定为EnumChildWindows中第一个参数
b. EnumChildWindows 不能枚举到遍历前己销毁和遍历期间己创建的窗体

  1. 使用GetWindow 遍历
    HWND GetWindow(HWND hWnd, UINT uCmd);
    功能: 获取与指定窗体相对关系(Z-ORDER,OWNER), 根据uCmd参数不同返回不同的窗体
    GW_CHILD 返回hWnd窗体第一个子窗体
    GW_ENABLEDPOPUP
    GW_HWNDFIRST 返回与hWnd窗体具有相同z-oder的窗体
    GW_HWNDLAST 意思与GW_HWNDFIRST 相同, 仅表示返回的是最后一个
    GW_HWNDNEXT 通常与GW_HWNDFIRST配合使用返回下一个具有相同z-oder的窗体
    GW_HWNDPREV 通常与GW_HWNDLAST配合使用返回上一个具有相同z-oder的窗体
    GW_OWNER 获取指定窗体拥有者窗体或父窗体
    说明: 此方法遍历子窗体没有EnumChildWindows函数稳定,但它可以枚举到遍历期间消毁的窗体.

我们例程功能主要演示了这两种遍历方法的使用, 演示过程中我们将遍历到的窗体分别显示到二个ListBox窗体中, 看看演示代码
1. 调用方法
case WM_COMMAND:
{
switch (wParam)
{
case IDC_BTNDATAREAD:
{
HWND hListbox = GetDlgItem(hWnd, IDC_LSTWNDLIST);
HWND hListbox1 = GetDlgItem(hWnd, IDC_LSTWNDLIST1);
SendMessage(hListbox, LB_RESETCONTENT, 0, 0);
SendMessage(hListbox1, LB_RESETCONTENT, 0, 0);

        HWND hParent = GetDesktopWindow();
        _EnumChildWindows(hParent, hListbox);
        EnumChildWindows(hParent, EnumChildWndProc, (LPARAM)hListbox1);

        SetWindowText(GetDlgItem(hWnd, IDC_BTNDATAREAD), _T("Refresh"));
    }
    break;
}
break;

}
2. _EnumChildWindows - GetWindow方法遍历

//////////////////////////////////////////////////////////////////////////
void _EnumChildWindows(HWND hParent, HWND hDisplay)
{
HWND hWndChild = GetWindow(hParent, GW_CHILD);
HWND hWndTemp = GetWindow(hWndChild, GW_HWNDFIRST);
do {
TCHAR szWndInfo[512] = {0};
TCHAR szWndTitle[256] = {0};
TCHAR szClsName[64] = {0};

    GetWindowText(hWndTemp, szWndTitle, 256);
    GetClassName(hWndTemp, szClsName, 64);
    _stprintf(szWndInfo,
                _T("´°¿ÚX ")
                _T("\"%s\"")
                _T("%s ")
                _T("%s"),
                hWndTemp,
                szWndTitle,
                szClsName,
                IsWindowVisible(hWndTemp) ? _T("Visible") : _T("Invisible"));
    SendMessage(hDisplay, LB_ADDSTRING, 0, (LPARAM)szWndInfo);
} while (NULL != (hWndTemp = GetWindow(hWndTemp, GW_HWNDNEXT)));

}
3. EnumChildWindows 方法
//////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumChildWndProc(HWND hWnd, LPARAM lParam)
{
HWND hListbox = (HWND)lParam;
if (NULL == hWnd) return FALSE;

if (NULL != hListbox && IsWindow(hListbox))
{
    TCHAR szWndInfo[512]    = {0};
    TCHAR szWndTitle[256]    = {0};
    TCHAR szClsName[64]        = {0};

    GetWindowText(hWnd, szWndTitle, 256);
    GetClassName(hWnd, szClsName, 64);
    _stprintf(szWndInfo,
              _T("´°¿ÚX ")
              _T("\"%s\" ")
              _T("%s ")
              _T("%s"),
              hWnd,
              szWndTitle,
              szClsName,
              IsWindowVisible(hWnd) ? _T("Visible") : _T("Invisible"));
    SendMessage(hListbox, LB_ADDSTRING, 0, (LPARAM)szWndInfo);
}

return TRUE;

}
遍历结果图, 我也参考了SPY++ 的遍历方法

根据上图的结果我发现两个问题, 1. 使用GetWindow与EnumChildWindows枚举出来的窗体不一致; 2. SPY++ 遍历的结果与通过GetWindow的得到的结果是一样的,说明SPY++也是使用了这种方式.

>

【Demo 0033】遍历窗体中控件
今天学习的内容在Demo032中基本上己学过了, 此例仅在Demo32基础上做了一点延伸。
在上节中我们了解EnumchildWindows遍历桌面的子窗体, 本节使 用此函数来获取窗体中所有控件.
一、代码演示
//////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumChildWndProc(HWND hWnd, LPARAM lParam)
{
HWND hListbox = (HWND)lParam;
if (NULL == hWnd) return FALSE;
if (NULL != hListbox && IsWindow(hListbox))
{
TCHAR szWndInfo[512] = {0};
TCHAR szWndTitle[256] = {0};
TCHAR szClsName[64] = {0};
GetWindowText(hWnd, szWndTitle, 256);
GetClassName(hWnd, szClsName, 64);
_stprintf(szWndInfo,
_T(“´°¿ÚX “)
_T(“\”%s\” “)
_T(“%s “)
_T(“%s”),
hWnd,
szWndTitle,
szClsName,
IsWindowVisible(hWnd) ? _T(“Visible”) : _T(“Invisible”));
SendMessage(hListbox, LB_ADDSTRING, 0, (LPARAM)szWndInfo);
}
return TRUE;
}
HWND hListbox = GetDlgItem(hWnd, IDC_LSTWNDLIST);
SendMessage(hListbox, LB_RESETCONTENT, 0, 0);
HWND hParent = FindWindowEx(NULL, NULL, _T(“Notepad”), NULL);
EnumChildWindows(hParent, WndEnumProc, (LPARAM)GetDlgItem(hWnd, IDC_LSTWNDLIST));
SetWindowText(GetDlgItem(hWnd, IDC_BTNDATAREAD), _T(“Refresh”));
TCHAR szTmp[128];
DWORD dwcount = SendMessage(GetDlgItem(hWnd, IDC_LSTWNDLIST), LB_GETCOUNT, 0, 0);
_stprintf(szTmp, _T(“size: %d”), dwcount);
OutputDebugString(szTmp);
本例以Notepad 窗体为目标, 通过EnumChildWindows 获取NotePad中所有的控件
二、显示结果

运行后发现NodePad 有两个控件1. Edit 2. statusbar  且不可见

>

【Demo 0035】获取窗体状态
本章学习内容非常少就一个API(GetWindowPlacement)
1. 代码演示
//////////////////////////////////////////////////////////////////////////
BOOL CALLBACK WndEnumProc(HWND hWnd, LPARAM lParam)
{
HWND hListbox = (HWND)lParam;
if (NULL == hWnd) return FALSE;
if (NULL != hListbox && IsWindow(hListbox) && IsWindowVisible(hWnd))
{
TCHAR szWndInfo[512] = {0};
TCHAR szWndTitle[256] = {0};
TCHAR szClsName[64] = {0};
WINDOWPLACEMENT wp = {0};
wp.flags = 0;
wp.length = sizeof(wp);
RECT rtWnd, rtClient;
GetWindowRect(hWnd, &rtWnd);
GetClientRect(hWnd, &rtClient);
GetWindowText(hWnd, szWndTitle, 256);
GetClassName(hWnd, szClsName, 64);
GetWindowPlacement(hWnd, &wp);
_stprintf(szWndInfo,
_T(“\”%s\”“)
_T(” %d “)
_T(“wnd[%d,%d,%d,%d], client[%d,%d,%d,%d], normal[%d,%d,%d,%d] min[%d, %d] max[%d, %d]”),
szWndTitle,
wp.showCmd,
rtWnd.left, rtWnd.top, rtWnd.right, rtWnd.bottom,
rtClient.left, rtClient.top, rtClient.right, rtClient.bottom,
wp.rcNormalPosition.left, wp.rcNormalPosition.top, wp.rcNormalPosition.right, wp.rcNormalPosition.bottom,
wp.ptMinPosition.x, wp.ptMinPosition.y,
wp.ptMaxPosition.x, wp.ptMaxPosition.y);
SendMessage(hListbox, LB_ADDSTRING, 0, (LPARAM)szWndInfo);
}
return TRUE;
}
2. BOOL GetWindowPlacement(HWND hWnd, WINDOWPLACEMENT *lpwndpl )
功能: 该函数返回指定窗口的显示状态以及被恢复的、最大化的和最小化的窗口位置
typedef struct _WINDOWPLACEMENT {
UINT length;
UINT flags;
UINT showCmd;
POINT ptMinPosition;
POINT ptMaxPosition;
RECT rcNormalPosition;
} WINDOWPLACEMENT;
返回值说明:
showCmd – 直接COPY MSDN
SW_HIDE
Hides the window and activates another window.
SW_MAXIMIZE
Maximizes the specified window.
SW_MINIMIZE
Minimizes the specified window and activates the next top-level window in the z-order.
SW_RESTORE
Activates and displays the window. If the window is minimized or maximized, the system restores it to its original size and position.
An application should specify this flag when restoring a minimized window.
SW_SHOW
Activates the window and displays it in its current size and position.
SW_SHOWMAXIMIZED
Activates the window and displays it as a maximized window.
SW_SHOWMINIMIZED
Activates the window and displays it as a minimized window.
SW_SHOWMINNOACTIVE
Displays the window as a minimized window.
This value is similar to SW_SHOWMINIMIZED, except the window is not activated.
SW_SHOWNA
Displays the window in its current size and position.
This value is similar to SW_SHOW, except the window is not activated.
SW_SHOWNOACTIVATE
Displays a window in its most recent size and position.
This value is similar to SW_SHOWNORMAL, except the window is not actived.
SW_SHOWNORMAL

你可能感兴趣的:(枚举遍历所有子窗口句柄控件类型标题)