大家好,今天小编给大家分享一下在Windows中,句柄是一个体系内部数据结构的引证。例如当你操作一个窗口,或说是一个Delphi窗体时,体系会给你一个该窗口的句柄,体系会告诉你:你正在操作142号窗口,就此你的应用程序就能要求体系对142号窗口进行操作——移动窗口、改动窗口巨细、把窗口最小化等等。实际上许多Windows API函数把句柄作为它的第一个参数,如GDI(图形设备接口)句柄、菜单句柄、实例句柄、位图句柄等,不仅仅局限于窗口函数。换句话说,句柄是一种内部代码,通过它能引证受体系控制的特别元素,如窗口、位图、图标、内存块、光标、字体、菜单等。
窗口句柄详细简介图1
概念
单从概念上讲,句柄指一个目标的标识,而指针是一个目标的内存首地址。从实际处理的角度讲,即能够把句柄界说为指针,又能够把它界说为同类目标数组的索引,这两种处理办法都有优缺点,至于选用哪种方式,完全应该看实际需求,这能够说是一种程序设计上的技巧。那种单纯以为句柄是指针或索引的主意都是机械的、不切当的。
其实,在Windows中类似的处理是许多的、很灵活的。再举个相似的例子:
咱们知道,在Windows中有个函数叫做CallWindowProc。望文生义,它的效果就是向指定的窗口过程传递一个消息。你或许会想,已然我现已有了窗口过程的指针,为什么我不能够直接通过这个指针调用该函数(这是C语言的内建功能)?事实上,在Win16中确实能够这么做,因为GetWindowLong回来的确实是该函数的指针。但在Win32下,GetWindowLong回来的并不是该函数的指针,而是一个包括函数指针的数据结构的指针(MSDN上说回来的是一个窗口函数地址或它的句柄,就是指的这种情况)。该数据结构是可变的,但只需你运用CallWindowProc来调用的话是不会犯错的。这儿咱们又看到运用句柄处理带来的优点。(补充阐明一点:微软在这儿之所以这么处理,是为了处理16位/32位以及ANSI/UNICODE的转化问题)
解疑
界说
句柄是什么?
在windows中,句柄是和目标一一对应的32位无符号整数值。目标能够映射到唯
一的句柄,句柄也能够映射到唯一的目标。
用途
为什么咱们需求句柄?
更准确地说,是windows需求句柄。windows需求向程序员供给必要的编程接口
,在这些接口中,答应程序员拜访、创立和销毁目标。可是,出于封装地考虑,wi
ndows并不想向程序员回来指针。指针包括了太多的信息。首先指针给出了目标存储
确实切位置;其次,要操作一个指针,程序员必须知道指针所指目标的内部结构特
征,也即,windows必须向程序员露出相应的数据结构,而这些数据结构或许是操作
体系想向程序员隐藏的。
假如说COM技能向用户隐藏了数据,只露出了接口并只答应按接口界说的办法操
作数据的话,句柄这种方式则答应你按自己的方式直接操作数据,但windows又不向
你直接露出数据。直接操作数据是程序员需求的,不露出数据是windows所需求的,
句柄封装方式完成了各取所需。
映射
句柄怎么与目标映射
封装背后,必须有一个当地能够完成解码,以完成句柄和目标的相互转化。在
windows中,存在两种映射方式:
a. 全等映射。也即,句柄自身就是一个指针。映射在这儿只是类型转化而已。
这种情况有,进程实例句柄或模块句柄,以及资源句柄等等。
b. 根据表格的映射。这是目标指针与句柄之间最普通的映射机制。操作体系创
建表格,并保存一切要考虑的目标。需求创立新目标时,要先在表格中找到空进口
,然后把表示目标的数据添入其中。当目标被删除时,它的数据成员和其在表中的
进口被释放。
完成
句柄的界说和完成
咱们以GDI目标为例进行讨论。创立了GDI目标,就会得到该目标的句柄。句柄
的目标或许是HBRUSH、HPEN、HFONT或HDC中的一种,这依赖于你创立 的GDI目标类
型。可是最普通的GDI目标类型是HGDIOBJ。HGDIOBJ被界说成空指针。
HPEN的实际编译类型界说随编译时间宏STRICT的不同而不同。假如STRCIT现已
被界说了,HPEN是这样的:
struct HPEN__ {int unused};
typedef struct HPEN__ HPEN;
假如STRICT没有界说,HPEN是这样界说的:
typedef void HANDLE;
typedef HANDLE HPEN;
上面这段代码是一个重视细节的程序员最接近句柄的当地,因而咱们重点剖析
一下。这儿有一点点技巧。假如界说了STRICT宏,HPEN是指向有单个未运用字段的
结构的指针,不然HPEN是空指针。C/C++编译器答应把任何类型的指针作为空指什传
递,反之则不能够。两个不同类型的非空指针是互不兼容的。在STRICT版本中,编
译对GDI目标句柄的不正确混用将给出正告,关于非GDI句柄,如HWND、HMENU的不正
确混用也会给出正告,从而使程序在编译器得到更STRICT的检查。
接下来的剖析或许不那么令你感兴趣,但它更深刻地提醒了句柄。对GDI句柄来
说,虽然windows头文件把它界说成指针,但假如你仔细检查这些句柄的值,它根本
就不像指针,这也是为什么我说它只是一个32位无符整数值的原因。对句柄就是指
针的情况,这句话也依然适用。让咱们随意地生成一些句柄,比如你用GetStockOb
ject()以得到一些句柄,你会发现,它们的值总在区间0x01900011到0xba040389。
前者指向用户区中的未分配的无效区域,后者指向内核地址空间。另外你或许发现
,两个句柄之间的值或许只差数值1,这也阐明GDI句柄不是指针。
和多数人想象的不一样,句柄也不是一个单纯的索引值。对GDI目标句柄来说,
GDI句柄由8位 、1位堆目标符号(标明目标是否创立在堆中)、7位目标类型信息和
高4位为0的16位索引组成,如:
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
10 9 8 7 6 5 4 3 2 1 0 98 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
/ 8 位引证计数 /堆 / 目标类型7 / 16位索引 /
符号
在这儿你能够看到,对GDI来说,它只运用了16位作为索引。这意味着一个进程最多只
能够创立小于64K个句柄,实际上受其他一些约束,整个Windows体系中大约能够容纳约
16384(0x4000)个GDI目标。