轉(zhuǎn)一篇說(shuō)明的比較不錯(cuò)的:

句柄是WONDOWS用來(lái)標(biāo)識(shí)被應(yīng)用程序所建立或使用的對(duì)象的唯一整數(shù),WINDOWS使用各種各樣的句柄標(biāo)識(shí)諸如應(yīng)用程序?qū)嵗翱冢刂疲粓D,GDI對(duì)象等等。WINDOWS句柄有點(diǎn)象C語(yǔ)言中的文件句柄。


從 上面的定義中的我們可以看到,句柄是一個(gè)標(biāo)識(shí)符,是拿來(lái)標(biāo)識(shí)對(duì)象或者項(xiàng)目的,它就象我們的姓名一樣,每個(gè)人都會(huì)有一個(gè),不同的人的姓名不一樣,但是,也可 能有一個(gè)名字和你一樣的人。從數(shù)據(jù)類(lèi)型上來(lái)看它只是一個(gè)16位的無(wú)符號(hào)整數(shù)。應(yīng)用程序幾乎總是通過(guò)調(diào)用一個(gè)WINDOWS函數(shù)來(lái)獲得一個(gè)句柄,之后其他的 WINDOWS函數(shù)就可以使用該句柄,以引用相應(yīng)的對(duì)象。


如果想更透徹一點(diǎn)地認(rèn)識(shí)句柄,我可以告訴大家,句柄是 一種指向指針的指針。我們知道,所謂指針是一種內(nèi)存地址。應(yīng)用程序啟動(dòng)后,組成這個(gè)程序的各對(duì)象是住留在內(nèi)存的。如果簡(jiǎn)單地理解,似乎我們只要獲知這個(gè)內(nèi) 存的首地址,那么就可以隨時(shí)用這個(gè)地址訪(fǎng)問(wèn)對(duì)象。但是,如果您真的這樣認(rèn)為,那么您就大錯(cuò)特錯(cuò)了。我們知道,Windows是一個(gè)以虛擬內(nèi)存為基礎(chǔ)的操作 系統(tǒng)。在這種系統(tǒng)環(huán)境下,Windows內(nèi)存管理器經(jīng)常在內(nèi)存中來(lái)回移動(dòng)對(duì)象,依此來(lái)滿(mǎn)足各種應(yīng)用程序的內(nèi)存需要。對(duì)象被移動(dòng)意味著它的地址變化了。如果 地址總是如此變化,我們?cè)摰侥睦锶フ以搶?duì)象呢?


為了解決這個(gè)問(wèn)題,Windows操作系統(tǒng)為各應(yīng)用程序騰出一些內(nèi)存儲(chǔ)地址,用來(lái) 專(zhuān)門(mén)登記各應(yīng)用對(duì)象在內(nèi)存中的地址變化,而這個(gè)地址(存儲(chǔ)單元的位置)本身是不變的。Windows內(nèi)存管理器在移動(dòng)對(duì)象在內(nèi)存中的位置后,把對(duì)象新的地 址告知這個(gè)句柄地址來(lái)保存。這樣我們只需記住這個(gè)句柄地址就可以間接地知道對(duì)象具體在內(nèi)存中的哪個(gè)位置。這個(gè)地址是在對(duì)象裝載(Load)時(shí)由系統(tǒng)分配給 的,當(dāng)系統(tǒng)卸載時(shí)(Unload)又釋放給系統(tǒng)。



句柄地址(穩(wěn)定)→記載著對(duì)象在內(nèi)存中的地址────→對(duì)象在內(nèi)存中的地址(不穩(wěn)定)→實(shí)際對(duì)象



本質(zhì):WINDOWS程序中并不是用物理地址來(lái)標(biāo)識(shí)一個(gè)內(nèi)存塊,文件,任務(wù)或動(dòng)態(tài)裝入模塊的,相反的,WINDOWS API給這些項(xiàng)目分配確定的句柄,并將句柄返回給應(yīng)用程序,然后通過(guò)句柄來(lái)進(jìn)行操作。



但 是必須注意的是程序每次從新啟動(dòng),系統(tǒng)不能保證分配給這個(gè)程序的句柄還是原來(lái)的那個(gè)句柄,而且絕大多數(shù)情況的確不一樣的。假如我們把進(jìn)入電影院看電影看成 是一個(gè)應(yīng)用程序的啟動(dòng)運(yùn)行,那么系統(tǒng)給應(yīng)用程序分配的句柄總是不一樣,這和每次電影院售給我們的門(mén)票總是不同的一個(gè)座位是一樣的道理。

受M$的幫助文檔以及很多Windows編程書(shū)籍的影響,大家對(duì)局柄比較普遍的認(rèn)識(shí)是:句柄是一個(gè)整數(shù),用以標(biāo)識(shí)Windows對(duì)象,句柄不是一個(gè)指針……


而實(shí)際上,這些不過(guò)是M$進(jìn)行數(shù)據(jù)封裝的幌子而已,下面我們一起來(lái)分析一下HANDLE到底是什么。


請(qǐng)先到Windef.h找絕大多數(shù)句柄的定義:

DECLARE_HANDLE(HWND);

DECLARE_HANDLE(HHOOK);

……

DECLARE_HANDLE(HGDIOBJ);

DECLARE_HANDLE(HBITMAP);

DECLARE_HANDLE(HBRUSH);

……

typedef HANDLE HGLOBAL;

typedef HANDLE HLOCAL;

……


OK, 現(xiàn)在大家跟我一起翻到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;


哈哈,現(xiàn)在知道了吧,HANDLE就是PVOID,也就是無(wú)類(lèi)型指針,

而DECLARE_HANDLE(HWND);就是:

struct HWND__ {

  int unused;};

typedef struct HWND__ *HWND;

現(xiàn)在實(shí)際上都清楚啦,這些Handles都不過(guò)是指向struct的指針,至于這個(gè)struct的用處,連M$都說(shuō)unused了,^o^


現(xiàn)在解釋下M$這么做的意義,這就是所謂數(shù)據(jù)封裝,你可以在你的程序中把M$的內(nèi)部結(jié)構(gòu)指針傳來(lái)傳去,可是你卻不知道它到底指向的內(nèi)容是什么,而且可以編個(gè)句柄的瞎話(huà)防止大家的質(zhì)疑:)。而M$的程序大可以這么寫(xiě):

#include <windows.h> //這個(gè)和大家用的一樣

#include "windows_in.h" //這個(gè)是M$自用的,外人別想看到^o^


HSOMETHINGELSE DoSomething(HSOMETHING hSomething) {

  struct RealSomething* p = (struct RealSomething*)hSomething; //先強(qiáng)制類(lèi)型轉(zhuǎn)換成內(nèi)部結(jié)構(gòu)指針

  ……do something……

  return (HSOMETHINGELSE)pRealSomethingElse;//強(qiáng)制類(lèi)型逆轉(zhuǎn)換