句柄(HANDLE)是Windows程序中一个重要的概念,使用也非常频繁。在Windows程序中,有各种各样的资源(窗口、图标、光标等),系统在创建这些资源时会为它们分配内存,并返回标识这些资源的标识号,即句柄。
窗口句柄是windows句柄的一种,且是重要的一种句柄。在Windows应用程序中,窗口是通过窗口句柄(HWND)来标识的。我们要对某个窗口进行操作,首先就要得到这个窗口的句柄。
窗口句柄的概念比较抽象,简单说窗口句柄就是一个窗口(window)的代表。我们通过几个例子来认识它。
1.LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
windows窗口处理函数,windows消息机制说的是,每当某个窗口发生变化(比如改变大小,移动),windows系统都会发相应的消息(wm_size,wm_move)给这个窗口。即调用函数 SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);注意这里WndProc和SendMessage的第一个参数都是HWND,窗口句柄代表这个窗口。
2. hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
这里说的是窗口句柄的产生,可以把hWnd想象成指针,CreateWindow想象成c++里的new,创建一个window,系统要为这个window对象分配一些资源,可以想象,window是由一个大的结构构成的。同时窗口句柄用来标识这个窗口。
3.有个窗口的句柄,则你就可以操控这个窗口的一切。
大量管理window的win32 api都是以hwnd做为参数。下面列举一些:
BringWindowToTop
FindWindowEx
GetParent
SetWindowPos
GetWindowRect
等等。
4.不仅窗口,窗口上的控件,象按钮,编辑框等也有窗口句柄,因为它们也是一种特殊的窗口,上面操作窗口的api大部分对这些控件窗口也适用。
获取句柄的方法:
这篇文章是关于如何获取窗口句柄,以及有哪些函数可供使用的简单讨论!可适用于vc、bcb(其他的我没有试,估计可以),本人在bcb环境下试验。
首先我会罗列出一些获取句柄的win32 api 函数,然后简单说说他们的用途!最后说说我是怎么理解和应用的。见笑了!
可用的win32 api函数:
1.HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName)
HWND FindWindowEx(HWND hwndParent, HWND hwndChildAfter,LPCTSTR lpClassName, LPCTSTR lpWindowName)
2.HWND WindowFromPoint(POINT& Point)
3.BOOL CALLBACK EnumChildProc(HWND hwnd,LPARAM lParam)
BOOL CALLBACK EnumChildWindows(HWND hWndParent, WNDENUMPROC lpEnumFunc,LPARAM lParam)
BOOL CALLBACK EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
一般用途:
对于第一种,大家都很熟悉,是捕捉句柄的常规武器,FindWindow这两兄弟,可以接受捕捉对象的类名或者窗口标题之一,作为参数,返回一个HWND。可是对于一般群众,不一定知道所有的窗口(包括标题栏、按钮等等)的类名啊!--可以简单举例,请问你知道桌面图标的窗口的类名吗?而对于窗口标题,有可能会出现相同的标题,有两个窗口--指一个程序的两个进程,这又是个麻烦吧!好了,这个问题先放放,继续下一组。
第二组,通过win32定义的POINT结构(typedef struct tagPOINT { LONG x;
LONG y;} POINT),来获得当前鼠标光标位置的窗口HWND,这是最直观的武器!常规操作如下:先得到Cursor的POINT(BOOL GetCursorPos(LPPOINT)函数),再用WindowFromPoint。这样,我们几乎可以获得任何打开的有窗口的函数的HWND了!然后通过获取类名的win32 api函数(int GetClassName( HWND hWnd, LPTSTR lpClassName, int nMaxCount ))得到类名--这里的lpClassName最好用字符数组地址,nMaxCount就是数组的size了,同时,这种方法解决了第一个问题的麻烦!--我可以把鼠标放在任何地方!*^_^*
第三组,这些是用来列举和处理任何窗口的超级武器!通过组合运用EnumWindows和EnumWindowsProc,EnumChildWindows与EnumChildProc,可以扫描桌面所有窗口并对之处理!
我的理解:(这部分用任务驱动式教学方法--谁让小弟是老师呢!xi xi)
任务:得到所有的窗口的类名。
解决办法1:我们会先想到第三组,可以自桌面窗口开始(它是所有窗口的祖先),依次扫描,获取类名并存之。有点儿像Visual Stdio的Spy++,或者Borland 的WinSight32,具体办法如下:(bcb中)
在主程序中,调用EnumWindows,传入YouEnumProc的函数地址作第一个参数,别忘了转换成WNDENUMPROC类型。第二参可NULL。::EnumWindows(reinterpret_cast<WNDENUMPROC> YouEnumProc,NULL);
在YouEnumProc函数中,如果第一参HWND = = NULL,就跳离(return FALSE;),可以结束啦!
然后,把类名数组准备好,得到类名,存之。
返回真值,继续下一次扫描。
看起来并不复杂,是一种函数递归。但是我可会解释!面啊!: p
第二种解决方法:简单、直观--自己想出来的,颇得意
首先准备一个时钟,一种存类名方法(我用TMemo)
在定时器处理函数中:
1、得到当前cursor的点位置
2、再用WindowFromPoint,
3、然后得到类名,放到TMemo里
这样可以用鼠标获得你想要的窗口(包括按钮等),只要鼠标在窗口放一会儿。。。哈哈
第三种方法:其实利用FindWindow和循环结构也应该可以
总结:其实得到HWND的方法很多,比如知道了窗口层次,依次向下扫。。。在说第三种呢!但我觉得,我的方法最直接有效,你说呢?
欢迎大家与我联系,并讨论这个问题!有关这个问题我还有许多疑问,比如HWND与ID的转换,在如IE页面中的表单控件的HWND或ID,还是其他的东东,总之是能识别他的东西。。。这个我很困惑,没办法!
不清楚地方,大家要参照MSDN啊
其它获取句柄的方法:
1.根据id获取窗口句柄
Hwnd hwnd = GetDlgItem(hwndParent,id).
2.根据窗口句柄,获取id
id = GetWindowLong(hwndChild,GWL_ID)
id = GetDlgCtrlID(hwndchild).
3.获取实例句柄的若干方法
hInst = GetWindowLong(hwnd,GWL_HINSTANCE)
把HINSTANCE 作为全局变量保存.
当建立窗口时,参数lparam指向了一个建立结构的地址.
可以这样获取实例句柄
hInst = ((LPCREATESTRUCT)lParam)->hInstance.