找回密码
 加入
搜索
查看: 4666|回复: 8

[系统综合] 关于获取窗口句柄的奇怪问题[已解决]

[复制链接]
发表于 2012-5-24 22:35:12 | 显示全部楼层 |阅读模式
本帖最后由 bitgao 于 2012-5-25 01:18 编辑
#Include <WinAPI.au3>

$Process="notepad.exe"
$ProcessID = ProcessExists($Process)
$ProcesshWnd = _WinAPI_OpenProcess(0x1F0FFF, True, $ProcessID, False)
MsgBox(0,0,$ProcessID)
MsgBox(0,0, $ProcesshWnd )

$handle = WinGetHandle("无标题 - 记事本", "")
MsgBox(0,0,$handle)
为什么这两种方法获取的同一个记事本程序窗口句柄不同呢?
发表于 2012-5-24 22:49:48 | 显示全部楼层
回复 1# bitgao


    有什么奇怪的,你先深入理解什么叫做Handle吧

上面得到的两个是不同的Handle,一个是Internal Handle,一个是Object Handle

微软从来没有明确定义过什么叫Handle,只是说明性解释了下面的三点:
① A HANDLE is a context-specific unique identifier.
② The HANDLE itself is just an integral type. Usually, but not necessarily, it is a pointer to some underlying type or memory location.
③ HANDLEs are intentionally opaque representations that provide encapsulation and abstraction from internal Win32 resources. This way, the Win32 APIs could potentially change the underlying type behind a HANDLE, without it impacting user code in any way

评分

参与人数 1金钱 +30 贡献 +2 收起 理由
user3000 + 30 + 2 赞个!

查看全部评分

 楼主| 发表于 2012-5-24 23:26:40 | 显示全部楼层
回复 2# happytc


    多谢多谢,还是经师不到学艺不高啊。呵呵。
那么再请教一下,如何才能通过进程名精确获取WinGetHandle函数返回的句柄呢?
 楼主| 发表于 2012-5-24 23:38:43 | 显示全部楼层
维基百科上句柄的定义:
在程序设计中,句柄是一种特殊的智能指针 。当一个应用程序要引用其他系统(如数据库、操作系统)所管理的内存块或对象时,就要使用句柄。
句柄与普通指针的区别在于,指针包含的是引用对象的内存地址,而句柄则是由系统所管理的引用标识,该标识可以被系统重新定位到一个内存地址上。这种间接访问对象的模式增强了系统对引用对象的控制。(参见封装)。
在上世纪80年代的操作系统(如Mac OS和Windows)的内存管理中,句柄被广泛应用。Unix系统的文件描述符基本上也属于句柄。和其它桌面环境一样,Windows API大量使用句柄来标识系统中的对象,并建立操作系统与用户空间之间的通信渠道。例如,桌面上的一个窗体由一个HWND类型的句柄来标识。
如今,内存容量的增大和虚拟内存算法使得更简单的指针愈加受到青睐,而指向另一指针的那类句柄受到冷淡。尽管如此,许多操作系统仍然把指向私有对象的指针以及进程传递给客户端的内部数组下标称为句柄。
 楼主| 发表于 2012-5-24 23:41:56 | 显示全部楼层
本帖最后由 bitgao 于 2012-5-24 23:46 编辑

网上找到的一篇比较经典的理解:
转自http://hi.baidu.com/fancys_he/bl ... cfe32609f7efd1.html

句柄是WONDOWS用来标识被应用程序所建立或使用的对象的唯一整数,WINDOWS使用各种各样的句柄标识诸如应用程序实例,窗口,控制,位图,GDI对象等等。WINDOWS句柄有点象C语言中的文件句柄。

从上面的定义中的我们可以看到,句柄是一个标识符,是拿来标识对象或者项目的,它就象我们的姓名一样,每个人都会有一个,不同的人的姓名不一样,但是,也可能有一个名字和你一样的人。从数据类型上来看它只是一个16位的无符号整数。应用程序几乎总是通过调用一个WINDOWS函数来获得一个句柄,之后其他的WINDOWS函数就可以使用该句柄,以引用相应的对象。

如果想更透彻一点地认识句柄,我可以告诉大家,句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这个程序的各对象是住留在内存的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象。但是,如果您真的这样认为,那么您就大错特错了。我们知道,Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。如果地址总是如此变化,我们该到哪里去找该对象呢?

为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统。

句柄地址(稳定)→记载着对象在内存中的地址────→对象在内存中的地址(不稳定)→实际对象

本质:WINDOWS程序中并不是用物理地址来标识一个内存块,文件,任务或动态装入模块的,相反的,WINDOWS API给这些项目分配确定的句柄,并将句柄返回给应用程序,然后通过句柄来进行操作。

但是必须注意的是程序每次从新启动,系统不能保证分配给这个程序的句柄还是原来的那个句柄,而且绝大多数情况的确不一样的。假如我们把进入电影院看电影看成是一个应用程序的启动运行,那么系统给应用程序分配的句柄总是不一样,这和每次电影院售给我们的门票总是不同的一个座位是一样的道理。

受M$的帮助文档以及很多Windows编程书籍的影响,大家对局柄比较普遍的认识是:句柄是一个整数,用以标识Windows对象,句柄不是一个指针……
而实际上,这些不过是M$进行数据封装的幌子而已,下面我们一起来分析一下HANDLE到底是什么。
请先到Windef.h找绝大多数句柄的定义:
DECLARE_HANDLE(HWND);
DECLARE_HANDLE(HHOOK);
……
DECLARE_HANDLE(HGDIOBJ);
DECLARE_HANDLE(HBITMAP);
DECLARE_HANDLE(HBRUSH);
……
typedef HANDLE          HGLOBAL;
typedef HANDLE          HLOCAL;
……
OK, 现在大家跟我一起翻到Winnt.h,看看DECLARE_HANDLE和HANDLE到底是什么:
#ifdef STRICT
typedef void *HANDLE;
#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
#else
typedef PVOID HANDLE;
#define DECLARE_HANDLE(name) typedef HANDLE name
#endif
typedef HANDLE *PHANDLE;
哈哈,现在知道了吧,HANDLE就是PVOID,也就是无类型指针,
而DECLARE_HANDLE(HWND);就是:
struct HWND__ {
   int unused;};
typedef struct HWND__ *HWND;
现在实际上都清楚啦,这些Handles都不过是指向struct的指针,至于这个struct的用处,连M$都说unused了,^o^
现在解释下M$这么做的意义,这就是所谓数据封装,你可以在你的程序中把M$的内部结构指针传来传去,可是你却不知道它到底指向的内容是什么,而且可以编个句柄的瞎话防止大家的质疑:)。而M$的程序大可以这么写:
#include <windows.h> //这个和大家用的一样
#include "windows_in.h" //这个是M$自用的,外人别想看到^o^
HSOMETHINGELSE DoSomething(HSOMETHING hSomething) {
   struct RealSomething* p = (struct RealSomething*)hSomething; //先强制类型转换成内部结构指针
   ……do something……
   return (HSOMETHINGELSE)pRealSomethingElse;//强制类型逆转换
 楼主| 发表于 2012-5-24 23:55:13 | 显示全部楼层
另一篇理解:
转自:http://blog.csdn.net/yongali/article/details/1688486

一、书上定义:

<<Microsoft Windows 3 Developer''s Workshop>>(Microsoft Press,by Richard Wilton)
    在Windows环境中,句柄是用来标识项目的,这些项目包括:模块(module)、任务(task)、实例 (instance)、文件(file)、内存块(block of memory)、菜单(menu)、控制(control)、字体(font)、资源(resource),包括图标(icon),光标 (cursor),字符串(string)等、GDI对象(GDI object),包括位图(bitmap),画刷(brush),元文件(metafile),调色板(palette),画笔(pen),区域 (region),以及设备描述表(device context)。

<<WINDOWS编程短平快>>(南京大学出版社):
    句柄是WONDOWS用来标识被应用程序所建立或使用的对象的唯一整数,WINDOWS使用各种各样的句柄标识诸如应用程序实例,窗口,控制,位图,GDI对象等等。WINDOWS句柄有点象C语言中的文件句柄。

二、MFC源代码:

#ifdef STRICT
typedef void *HANDLE;
#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
#else
typedef PVOID HANDLE;
#define DECLARE_HANDLE(name) typedef HANDLE name
#endif

DECLARE_HANDLE(HMODULE);
DECLARE_HANDLE(HINSTANCE);
DECLARE_HANDLE(HLOCAL);
DECLARE_HANDLE(HGLOBAL);
DECLARE_HANDLE(HDC);
DECLARE_HANDLE(HRGN);
DECLARE_HANDLE(HWND);
DECLARE_HANDLE(HMENU);
DECLARE_HANDLE(HACCEL);
DECLARE_HANDLE(HTASK);


三、理解:
    HANDLE就是PVOID,也就是无类型指针,
    上面这些资源的句柄Handles都不过是指向struct的指针,至于这个struct的用处,连M$都说unused了,现在解释下M$这么做的意义,这就是所谓数据封装,你可以在你的程序中把M$的内部结构指针传来传去,可是你却不知道它到底指向的内容是什么。

    句柄与指针确实是完全不同的两个概念。句柄仅仅是一个32位整数,WIN32中用于标记某个系统或进程的对象,可以理解为对象索引(由于M$未完全公开相关技术,在一定程度上只能如此理解),这个索引更像是一种映射关系(从句柄到对象指针的映射),而不是纯粹意义上的“数组下标”。


     句柄可以理解为用于指向或标识内存的一块“资源”,这些资源如:文件(file)、内存块(block of memory)、菜单(menu)等等。操作系统通过句柄来定位核心对象和系统资源。
    指针即为指向内存的“数据或指令”某一单元。

    说的确切一点,句柄实际上是一种指向某种资源的指针,但与指针又有所不同:指针对应着一个数据在内存中的地址,得到了指针就可以自由地修改该数据。Windows并不希望一般程序修改其内部数据结构,因为这样太不安全。所以Windows给每个使用GlobalAlloc等函数声明的内存区域指定一个句柄(本质上仍是一个指针,但不要直接操作它),平时你只是在调用API函数时利用这个句柄来说明要操作哪段内存。

   
四、引喻:
   牧童遥指杏花村
   牧童的手为指针,杏花村的牌子为句柄,杏花村酒店为对象的实例.


附注:获得窗口句柄三种方法

1.HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName)

   HWND FindWindowEx(HWND hwndParent, HWND hwndChildAfter,LPCTSTR lpClassName, LPCTSTR lpWindowName)

2.HWND WindowFromPoint(POINT& Point)//获得当前鼠标光标位置的窗口HWND

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)
 楼主| 发表于 2012-5-24 23:58:23 | 显示全部楼层
本帖最后由 bitgao 于 2012-5-25 00:30 编辑

http://www.autoitx.com/forum.php ... amp;fromuid=7658484
本站阿祥的帖子
 楼主| 发表于 2012-5-25 00:10:47 | 显示全部楼层
回复 2# happytc


您说的Internal Handle跟Object Handle有什么区别呢?
 楼主| 发表于 2012-5-25 00:20:53 | 显示全部楼层
本帖最后由 bitgao 于 2012-5-25 00:24 编辑

好像明白了,这两个函数取得的根本就不是一种东西嘛。。。。。。汗

一个是窗口的句柄,一个是进程的句柄。两个都叫句柄,把人引入歧途。
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-9-30 09:25 , Processed in 0.077209 second(s), 23 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表