句柄是什么?Windows结构体里面句柄的作用( 三 )


01typedef struct HMENU__02{03int unused;04} *HMENU;复制代码typedef struct HMENU__{int unused;} *HMENU;到这里,你是不是觉得有一点眉目了呢,对,句柄是一种指向结构体的指针,结合这里的int unused定义很容易猜到结构体的第一个字段就是我们的逻辑地址(指针) 。那么,是不是仅仅如此呢,当然不是!!!由于指向结构体指针可以强制截断只获取第一个字段,这里的struct结构体绝对不止一个字段,联系我们在Windows中的编程经验,对于线程HANDLE有计数那么必须有计数段,对于事件HEVENT等内核对象会要求指定属性那么必须有属性段,对于内存分配HANDLE有可移动和不可移动之说那么必须有内存可移动属性段,等等 。基于此我们可以大胆猜测Windows的句柄指向的结构类似如下
01struct02{03int pointer;//指针段04int count;//内核计数段05int attribute;//文件属性段:SHARED等等06int memAttribute;//内存属性段:MOVABLE和FIXED等等07...08};复制代码struct{int pointer;//指针段int count;//内核计数段int attribute;//文件属性段:SHARED等等int memAttribute;//内存属性段:MOVABLE和FIXED等等...};事实上,Windows内存管理器管理的其实都是句柄,通过句柄来管理指针,Windows的系统整理内存时检测内存属性段,如果是可以移动的就能够移动逻辑地址,移动完后将新的地址更新到对应句柄的指针段中,当要使用MOVABLE地址时的时候必须Lock住,这时候计数加1,内存管理器检测到计数》0便不会移动逻辑地址,这时候才能获得固定的逻辑地址来操作物理内存,使用完后Unlock内存管理器又可以移动逻辑地址了,到此MOVABLE的内存访问为什么不会乱这个问题就解决了 。
下面再说一说,FIXED的内存为什么说就是指向分配内存块的指针 。我们看上面的通用句柄定义,可以发现HANDLE的句柄定义一直是void指针,其他的特殊句柄在严格类型检查的时候定义为结构体指针,为什么不把二者定义为一样的呢 。查看MSDN关于GlobalAlloc的叙述对于GMEM_FIXED类型“Allocates fixed memory. The return value is a pointer.”,这里返回的是一个指针,为了验证这个说法,我写了一小段程序
01//GMEM_FIXED02hGlobal = GlobalAlloc(GMEM_FIXED, (lstrlen(szBuffer) 1) * sizeof(TCHAR));03pGlobal = GlobalLock(hGlobal);04lstrcpy(pGlobal, szBuffer);05_tprintf(TEXT("pGlobal和hGlobal%sn"), pGlobal==hGlobal ? TEXT("相等") : TEXT("不相等"));06GlobalUnlock(hGlobal);07_tprintf(TEXT("使用句柄当做指针访问的数据为:%sn"), hGlobal);08GlobalFree(hGlobal);复制代码//GMEM_FIXEDhGlobal = GlobalAlloc(GMEM_FIXED, (lstrlen(szBuffer) 1) * sizeof(TCHAR));pGlobal = GlobalLock(hGlobal);lstrcpy(pGlobal, szBuffer);_tprintf(TEXT("pGlobal和hGlobal%sn"), pGlobal==hGlobal ? TEXT("相等") : TEXT("不相等"));GlobalUnlock(hGlobal);_tprintf(TEXT("使用句柄当做指针访问的数据为:%sn"), hGlobal);GlobalFree(hGlobal);运行结果为
01pGlobal和hGlobal相等02使用句柄当做指针访问的数据为:Test text复制代码pGlobal和hGlobal相等使用句柄当做指针访问的数据为:Test text对比使用GMEM_MOVABLE程序为
01//GMEM_MOVABLE02hGlobal = GlobalAlloc(GMEM_MOVEABLE, (lstrlen(szBuffer) 1) * sizeof(TCHAR));03pGlobal = GlobalLock(hGlobal);04lstrcpy(pGlobal, szBuffer);05_tprintf(TEXT("pGlobal和hGlobal%sn"), pGlobal==hGlobal ? TEXT("相等") : TEXT("不相等"));06_tprintf(TEXT("使用句柄当做指针访问的数据为:%sn"), hGlobal);07GlobalUnlock(hGlobal);08GlobalFree(hGlobal);复制代码//GMEM_MOVABLEhGlobal = GlobalAlloc(GMEM_MOVEABLE, (lstrlen(szBuffer) 1) * sizeof(TCHAR));pGlobal = GlobalLock(hGlobal);lstrcpy(pGlobal, szBuffer);_tprintf(TEXT("pGlobal和hGlobal%sn"), pGlobal==hGlobal ? TEXT("相等") : TEXT("不相等"));_tprintf(TEXT("使用句柄当做指针访问的数据为:%sn"), hGlobal);GlobalUnlock(hGlobal);GlobalFree(hGlobal);运行结果为
01pGlobal和hGlobal不相等02使用句柄当做指针访问的数据为:?复制代码pGlobal和hGlobal不相等使用句柄当做指针访问的数据为:?显然,使用GMEM_FIXED和使用GMEM_MOVABLE得到的数据类型不是一样的,我们有理由相信Windows在调用GlobalAlloc使用GEM_FIXED的时候返回的就是数据指针,使用Windows在调用GMEM_MOVABLE的时候返回的是指向结构体的句柄,这样操作的原因相信是为了使用更加方便 。那么这里我们就要修正一下前面的说法了:通用句柄HANDLE有时候是逻辑指针,大多数时候是结构体指针,特殊句柄如HMENU等是结构体指针 。这样第二个问题也解决了 。

推荐阅读