对句柄的认识

之前在编写MFC程序的时候,有时会碰到句柄这一概念,由于对它一直不是很重视,所以并没有主动去了解它.随着不断深入学习MFC,特别是看完候先生的<<深入浅出MFC>>后,对句柄的实质产生了很大的兴趣,于是到处收集资料,现在总结一下.
       handle的中文意思主要有多种,一种是作为名词:柄,把柄;一种是作为动词:处理.硬要从中文意思来说的话,这两种中文意思都可以用来勉强解释句柄.例如一个锅的手柄,你只要抓住了它,你就可以很好地操作那个锅,不过很明显你只能通过锅的手柄来做一些诸如炒菜之类的事,你不可能是因为抓住了锅的手柄才能去看电视.不能的物体都会至少有一个属于它的"手柄".在MFC里面,有很多对象,例如对话框,窗口,画笔,显示器,打印机等,每个对象都会产生一个属于它自己的句柄.oh!慢着,似乎还没说清楚句柄的本质,下面再作详细的解说吧.

       如果查看各种HANDLE的定义,如HDC,HPEN,HINSTANCE等等,你会发现有这样一个声明:

       DECLARE_HANDLE(HDC);

       再把DECLARE_HANDLE这个宏展开来看一下:

       #define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name

       这是什么意思?用HDC替换上面的name来看看,我们就得到了下面的一段代码:

      struct HDC__

       {

       int unused;

       };

       typedef struct HDC__ *HDC

        oh,原来句柄就是一个指向某一结构的指针,这个结构体只有一个成员,它是一个整数(不知为什么MS要把这个成员叫做unused,难道真的没有用吗?).

        嗯,我们再看一个HANDLE的定义,在winnt.h头文件中,我们看到了HANDLE的定义:

        typedef PVOID HANDEL;

        PVOID是什么?再看它的定义:

        typedef void *PVOID;

        真相出来了,原来HANDLE不过是一个指向void型,即无类型的指针,嗯,目前的指针是32位的吧.其实也不能说HANDLE是一种指针,它只充当一种索引的作用.真的很难解释HANDLE是什么,再往下看看,只能意会吧,呵呵.

        知道了HANDLE的本质(一个32位的整数,用16进制表示),再来说说HANDLE的作用.看我前面第二段的例子,你可以了解到为了控制一个物体,你需要找到它的"手柄".HANDLE就是充当win32下各种"物体"的"手柄".事实上,很多windows API都需要一个HANDLE作为输入参数,这是因为API需要和一些你看不见的对象打交道,这些对象是不能被你所移动或修改的,所以不能给你一个指针来对它进行操作.oh,指针的确是个好东西,它所拥有的能力实在太强大了,但所谓能力越大,责任越大,使用指针的时候千万要小心,不然会造成毁灭性的错误.所以,为了安全,还是给你一个HANDLE吧,通过这个HANDLE,你就可以对那些对象进行一些处理.HANDLE在这里充当什么角色呢?应该算是一个中间人吧,HANDLE是固定的,它不会变,但是对象的地址会变,当对象在内存中的位置发生改变后,我们不能通过之前的对象指针找到对象,怎么办呢?嗯,这时候HANDLE的用处就出来了,HANDLE就是用来记录对象的最新地址的.有点明白了吧?换一种说法吧,嗯,其实就是你知道HANDLE在哪里,但你不知道对象在哪里,而HANDLE知道对象在哪里,所以,只要你知道了HANDLE在哪里,你就能找到对象(尽管你还是不知那个对象住在内存的哪个地方,不过找到它就行了,不是吗?).嗯,是不是有点像索引的作用呢?为什么不给我们知道对象在内存中的位置呢?呵呵,操作系统怕你对它进行一些不利的操作啊.反正你通过HANDLE能让对象做它应该做的事,这就足够了.这就是封装吧,MS最喜欢做的事情,呵呵.

       其实对于HANDLE的定义,MS公司也不能说得清清楚楚,把HANDLE翻译成句柄也是不太合适的,但有时就是这样,英文能理解的东西,翻译到中文反而就混乱了,所以"句柄"这个名词比较适合初学者,如我.那些有丰富编程经验的人一定不喜欢使用"句柄"这个名词吧,还是用handle这个原版英文单词比较容易理解

阅读更多

我对句柄认识,抛砖引玉

04-25

今天看再次拿起了,看到了让我困惑很久的句柄的概念,在csdn上so了一圈,看到了一片"句柄的本质——拨乱反正篇",突然想起了在大学的时候看过这篇文章,当时才刚刚踏入win32的世界,感觉很蒙,今天又看到了这篇文章,文中的分析让我产生了疑惑,我来说说我对句柄的认识吧.不妥指出请朋友指正.rn 打开winnt.h文件,看看handle的定义吧.rn#ifdef STRICTrntypedef void *HANDLE;rn#define DECLARE_HANDLE(name) struct name##__ int unused; ; typedef struct name##__ *namern#elserntypedef PVOID HANDLE;rn#define DECLARE_HANDLE(name) typedef HANDLE namern#endifrntypedef HANDLE *PHANDLE;rnHANDLE 被定义为无类型指针,注意到STRICT这个宏,他是用来指示编译器执行句柄的类型检查的,vc6默认定义这个宏,当定义STRICT这个宏时,HANDLE被定义为名为name__的指针,这样,对于DECLARE_HANDLE(HWND),DECLARE_HANDLE(HICON)这样的句柄声明,就定义了不同名称的HANDLE这样,当试图在接受参数为HWND*的函数中传入HICON*的指针时,编译器就会发出警告.这就时STRICT的作用.当不定义这个宏的时候,那么,HANDLE就时个void*类型,可以指向任意类型,如上传入参数的时候也就不会发出警告了.rn 每个进程在被创建的时候,都会产生一个句柄表,句柄表的内部结构没有ws的文档说明,引用windows核心编程里面讲解,句柄表其实是一个这样的数组,数组中的每个成员是一个结构,结构里面包含的关于内核对象的信息,如内核对象的地址,所以,通过句柄,我们就可以间接的操作这个内核对象,而句柄的值具体表示什么?看看定义STRICT的时候的情况,是个结构指针,而该结构的成员是个int unused32位整形,在不定义STRICT的情况,是个void*,也就是说,他们可以是任何东西.指针也好,整数也好,但他确实保存了一个值在里面,我们通过这个值,通过句柄表,来间接的操作内核对象,可以想象成指针的指针,通过句柄间接的指向内核对象,我们来间接的操作内核对象,由于句柄表是每个进程个有自己的,句柄也是进程相关的,所以,当跨越进程边界用一个进程的句柄来在另一个进程中访问的时候,是不被允许的.rn 让我们在看看HINSTANCE这个东东,他其实也是个HANDLE,但是,他是个实例句柄,用来保存的是进程实例映象的首地址,紧紧是地址而已,没有指向内核对象....rn 看来,句柄真是个神奇的东东.呵呵.以上是我对句柄的认识,如有不妥或不全之处,朋友一定要发个留言上来啊.接受批评和指正.

没有更多推荐了,返回首页