您的位置:首页 > 理论基础 > 数据结构算法

关于windows句柄机制的一些心得体会

2011-07-30 14:29 302 查看
windows会为所有加载的资源分配一个唯一的标识符,该标识符就是句柄,通过句柄可以操作它所指向的对象,那么句柄究竟是什么样的数据结构,它是如何实现和指针的转换呢?先看句柄在MFC头文件WINNT.H中的定义:

//*****************************************************************************************************************

#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;

//*****************************************************************************************************************

1.##是宏中的字符串连接符号,比如定义DECLARE_HANDLE(HMENU),展开后为struct HMENU__{int unused;};typedef struct HMENU__ *HMENU

2.STRICT 宏被定义为#define STRICT这副德行,什么都不做,但是一旦定义,编译器将启用类型检查,当定义了STRICT时,通用句柄HANDLE被定义为void*类型,同时定义宏

DECLARE_HANDLE(name),这个宏允许定义其他句柄子集,如DECLARE_HANDLE(HMENU)等,这样HMENU这个代表菜单资源的句柄被定义为指向一个包含未用字段unused的结构体指针,如果STRICT未定义,HANDLE被定义为PVOID,PVOID的定义是typedef void* PVOID,本质上和直接定义为void*没什么区别,但DECLARE_HANDLE(name)定义为 typedef HANDLE name,若定义HMENU,HMENU则定义为HANDLE,成了无类型指针void*

说道这里,只知道句柄是一个void或name##__{int unused;}类型的指针,windows如何实现它和指针的绑定的呢?windows如何通过一个资源的HANDLE拿到对象的指针?其实关于句柄和它指向对象之间的对应关系,只有微软的程序员知道,微软并没有公布句柄与对象绑定的实现,但可以推测它的原理,网上的资料翻阅了不少,关于句柄原理的文章不多,有提及其原理的,也只是推测,但推测并不代表臆测,因为推测的原理是完全可行的,现在来说说这个所谓的推测的原理:

句柄与对象指针间的对应被设置成一张表格的形式,由内核去维护这张句柄表格,当windows为资源分配内存之后,会将该资源在内存中的地址,也就是该资源的指针保存起来,保存在哪里?噢,前面提及了内核表格的东西,windows会在资源分配内存后,在内核进程维护的一张表格里寻找入口,将对象地址以及对象的一些信息存入表格,成为这张巨大的表格中的一个单元,并且为改单元分配一个索引,有点类似单元格ID的东西,这就是句柄了,示意图:

ID(句柄)                                 对象信息                               对象指针                                                                  
1.....0x......
2.....0x......
3.....(Menu)0x00010101
   
比如系统刚为一个Menu对象分配了内存,windows会在内核维护的句柄表格中找到入口,插入一个单元,单元索引分配为3,然后将Menu对象的信息写入该单元第二项,对象指针写入第三项,这样的映射机制就将句柄(单元索引或ID)与Menu对象的指针联系在了一起,由于windows是虚拟内存机制,当某个资源空闲是,windows可能会将其从内存中释放,这样句柄表格中相应的单元会被删除掉,当资源需要使用时,windows会重新为其分配内存,内存地址会发生变化,此时会重新在内存表格中加入一项,只是此时,单元的ID可能会跟之前不一样,这就是同一资源句柄可能变化的原因

在程序中通过CMenu* m_pMenu = CMenu::FromHandle(HMENU)来获取对象指针,那么这个函数是如何通过句柄拿到对象指针的呢,相信你已经能够猜出来,内核会将它维护的句柄映射表格的一份只读拷贝放到应用程序的进程空间中去,这样FromHandle会去搜索这个表格,将其传入的句柄拿去与表格的ID进行一一比对,当发现匹配的单元时,就将此单元的指针返回,如果没有找到,则表明你传入了一个无效句柄,返回NULL。到这里,句柄与指针的映射机制讲完,错误的地方,望各位指正批评!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息