日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

句柄与指针的区别与联系

發(fā)布時(shí)間:2025/5/22 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 句柄与指针的区别与联系 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原帖地址(http://mahanyang94.blog.163.com/blog/static/25498051200911176212455/

句柄其實(shí)就是指針,但是他和指針最大的不同是:給你一個(gè)指針,你可以通過這個(gè)指針做任何事情,也許是好事,也許是通過這個(gè)指針破壞內(nèi)存,干一些搗亂的事情。這個(gè)我想大家都會碰到過,因?yàn)閬y用指針導(dǎo)致程序崩潰
??? 句柄就沒有這個(gè)缺點(diǎn),通過句柄,你只能干一些windows讓你干的事情(調(diào)用一些api函數(shù)等等),沒有了指針的壞處。

??? 句柄是一些表的索引也就是指向指針的指針,句柄和指針都是地址,句柄是Windows編程的一個(gè)關(guān)鍵性的概念,編寫Windows應(yīng)用程序總是要和各種句柄打交道。
??? 所謂句柄,就是一個(gè)唯一的數(shù),用以標(biāo)識許多不同的對象類型,如窗口、菜單、內(nèi)存、畫筆、畫刷等。在Win32里,句柄是指向一個(gè)“無類型對象”(void*)的指針,也就是一個(gè)4字節(jié)長的數(shù)據(jù)。
??? 無論它的本質(zhì)是什么,句柄并不是一個(gè)真正意義上的指針。從構(gòu)造上看,句柄是一個(gè)指針,盡管它沒有指向用于存儲某個(gè)對象的內(nèi)存位置。事實(shí)上,句柄指向一個(gè)包含了對該對象進(jìn)行的引用的位置。
??? 句柄的聲明是這樣的:
??? typedef void *HANDLE
??? 由于Windows是一個(gè)多任務(wù)操作系統(tǒng),它可以同時(shí)運(yùn)行多個(gè)程序或一個(gè)程序的多個(gè)副本。這些運(yùn)行的程序稱為一個(gè)實(shí)例。為了對同一程序的多個(gè)副本進(jìn)行管理,Windows引入了實(shí)例句柄。Windows為每個(gè)應(yīng)用程序建立一張表,實(shí)例句柄就好象是這張表的一個(gè)索引。
??? 不同在于:
????? 1、句柄所指的可以是一個(gè)很復(fù)雜的結(jié)構(gòu),并且很有可以是與系統(tǒng)有關(guān)的,比如說上面所說的線程的句柄,它指向的就是一個(gè)類或者結(jié)構(gòu),他和系統(tǒng)有很密切的關(guān)系,當(dāng)一個(gè)線程由于不可預(yù)料的原因,而終止時(shí)在系統(tǒng)就可以回它所占用的資料,如CPU,內(nèi)存等等,反過來想可以知道,這個(gè)句柄中的某一些項(xiàng),是與系統(tǒng)進(jìn)行交互的。由于Windows系統(tǒng),是一個(gè)多任務(wù)的系統(tǒng),它隨時(shí)都可能要分配內(nèi)存,回收內(nèi)存,重組內(nèi)存。
????? 2、指針?biāo)部梢灾赶蛞粋€(gè)復(fù)雜的結(jié)構(gòu),但是通常是用戶定義的,所以的必需的工作都要用戶完成,特別是在刪除的時(shí)候。但在VC++6.0中也有一些指針,它們都是處理一些小問題才用的,如最常見的字符的指針,它也是要用戶處理的如果你動態(tài)分配了內(nèi)存;但是Cstring 就不要用戶處理了,它其實(shí)是VC++中的一個(gè)類,所以的操作都由成員函數(shù)完成,產(chǎn)生(分配)由構(gòu)造函數(shù),刪除(回收)由析構(gòu)函數(shù)完成。


獲得窗口句柄三種方法

.HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName)

HWND FindWindowEx(HWND hwndParent, HWND hwndChildAfter,LPCTSTR lpClassName, LPCTSTR lpWindowName)

2.HWND WindowFromPoint(POINT& Point)//獲得當(dāng)前鼠標(biāo)光標(biāo)位置的窗口HWND

3.BOOL CALLBACK EnumChildProc(HWND hwnd,LPARAM lParam)

BOOL CALLBACK EnumChildWindows(HWND hWndParent, WNDENUMPROC lpEnumFunc,LPARAM lParam)
BOOL CALLBACK EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)

指針 句柄之間的轉(zhuǎn)換

a.由指針獲得句柄
CWnd * pWnd;
CWnd HWnd;
HWnd = pWnd->GetSafeHWnd();

b.由句柄得到指針:
CWnd* pWnd=FromeHandle(hMyHandle);
pWnd->SetWindowText("Hello World!");
or CWnd* pWnd; pWnd->Attach(hMyHandle);

MFC類中有的還提供了標(biāo)準(zhǔn)方法,比如Window 句柄:
static CWnd* PASCAL FromHandle( HWND hWnd );
HWND GetSafeHwnd( ) const;

對于位圖:
static CBitmap* PASCAL FromHandle( HBITMAP hBitmap );
static CGdiObject* PASCAL FromHandle( HGDIOBJ hObject );
HGDIOBJ GetSafeHandle( ) const;

??? 有人說句并就是一個(gè)標(biāo)示,一個(gè)ID號,是錯誤的。一個(gè)ID號可以包括多個(gè)資源,比如說單文檔中的IDR_MAINFRAME,一般是指在硬盤上的資源。但是當(dāng)把硬盤上的資源調(diào)入內(nèi)存以后,將有一個(gè)句柄指向它,但是句柄只能指向一個(gè)資源。而且句柄知道所指的內(nèi)存有多大。還有指針,指針指向地址,它不知道分配的內(nèi)存有多大。
??? 但是如果你定義一個(gè)句柄,然后在VC里面右擊鼠標(biāo),選擇"go to definition of HANDLE,你會發(fā)現(xiàn)它的本質(zhì)就是一個(gè)指針,但是它的作用不同于指針。

??? 句柄是個(gè)指針,指向一塊內(nèi)存,但至于這塊內(nèi)存跟句柄所標(biāo)識的對象是怎么聯(lián)系起來的,調(diào)用者不需要清楚,調(diào)用者只需要知道,這個(gè)句柄聯(lián)系著一個(gè)win32對象。
??? 句柄是物理地址,可以跨進(jìn)程傳遞,例如,HANDLE ha進(jìn)程A的一個(gè)窗口,你可以在進(jìn)程B中利用一個(gè)跟ha相等的值(相等就是說它們強(qiáng)制轉(zhuǎn)成int32的值相等)初始化一個(gè)句柄,利用這個(gè)句柄你可以對進(jìn)程 A的那個(gè)對象進(jìn)行操作,例如MoveWindow,ShowWindow等。
??? 句柄包含了一些引用計(jì)數(shù)之類的東西,所以我的上一點(diǎn)說的給句柄賦值是不安全的,Windows API提供了一些函數(shù),可以對句柄進(jìn)行操作。

句柄就是受限的指針。
??? 它是由操作系統(tǒng)管理的,你不能通過它存取操作系統(tǒng)創(chuàng)建的數(shù)據(jù)結(jié)構(gòu)。

??? 操作系統(tǒng)在創(chuàng)建一個(gè)對象(如GDI, FILE)等的時(shí)候,它會為這個(gè)對象CONTEXT保留一塊數(shù)據(jù)結(jié)構(gòu),然后把它放在一張全局表中。。句柄就是這塊數(shù)據(jù)結(jié)構(gòu)在表中的索引

??? 指針對應(yīng)著一個(gè)數(shù)據(jù)在內(nèi)存中的地址,得到了指針就可以自由地修改該數(shù)據(jù)。Windows并不希望一般程序修改其內(nèi)部數(shù)據(jù)結(jié)構(gòu),因?yàn)檫@樣太不安全。所以 Windows給每個(gè)使用GlobalAlloc等函數(shù)聲明的內(nèi)存區(qū)域指定一個(gè)句柄(本質(zhì)上仍是一個(gè)指針,但不要直接操作它),平時(shí)你只是在調(diào)用API函數(shù)時(shí)利用這個(gè)句柄來說明要操作哪段內(nèi)存。當(dāng)你需要對某個(gè)內(nèi)存進(jìn)行直接操作時(shí),可以使用GlobalLock鎖住這段內(nèi)存并獲得指針來直接進(jìn)行操作。
??? lshgao的意見:
??? 句柄是指針的“指針”,使用句柄主要是為了利于windows在進(jìn)程內(nèi)存地址空間移動分配的內(nèi)存塊,以防止進(jìn)程的內(nèi)存空間被撕的四分五裂而存在過多的碎片。
???
??? 阿城的意見:
??? 句柄是一些表的索引也就是指向指針的指針。間接的引用對象,windows可以修改對象的"物理"地址和
??? 描述器的值,但是句柄的值是不變的。
???
??? 劉志用的意見:
??? 句柄和指針都是地址,不同在于:
??? 1,句柄所指的可以是一個(gè)很復(fù)雜的結(jié)構(gòu),并且很有可以是與系統(tǒng)有關(guān)的,比如說上面所說的線程的句柄,它指向的就是一個(gè)很類或者結(jié)構(gòu),他和系統(tǒng)有很密切的關(guān)系,當(dāng)一個(gè)線程由于不可預(yù)料的原因,而終止時(shí)在系統(tǒng)就可以回它所占用的資料,如CPU,內(nèi)存等等,反過來想可以知道,這個(gè)句柄中的某一些項(xiàng),是與系統(tǒng)進(jìn)行交互的。由于Windows系統(tǒng),是一個(gè)多任務(wù)的系統(tǒng),它隨時(shí)都可能要分配內(nèi)存,回收內(nèi)存,重組內(nèi)存。
??? 2,指針?biāo)部梢灾赶蛞粋€(gè)復(fù)雜的結(jié)構(gòu),但是通常是用戶定義的,所以的必需的工作都要用戶完成,特別是在刪除的時(shí)候。
??? 但在VC++6.0中也有一些指針,它們都是處理一些小問題才用的,如最常見的字符的指針,它也是要用戶處理的如果你動態(tài)分配了內(nèi)存;但是Cstring 就不要用戶處理了,它其實(shí)是VC++中的一個(gè)類,所以的操作都由成員函數(shù)完成,產(chǎn)生(分配)由構(gòu)造函數(shù),刪除(回收)由析構(gòu)函數(shù)完成。
???
??? zjf問:
??? 你好,我在學(xué)習(xí)用vc++6.0編譯多線程程序中遇到了很多句柄,但是不明白他的具體作用以及如何使用句柄,希望您能給我舉幾個(gè)具體實(shí)例,不甚感激!
??? 比如說: HANDLE hThread,它是怎樣具體使用的?
??? 答:你使用CreateThead后函數(shù)會返回一個(gè)句柄,它代表這個(gè)線程。你可能會調(diào)用SetThreadPriority去修改線程的優(yōu)先級,使用 ResumeThread去重新開始一個(gè)線程的運(yùn)行,在調(diào)用這些函數(shù)時(shí)你都需要告訴系統(tǒng)你到底要操作哪個(gè)線程,而剛才返回的句柄派上用處了,這些函數(shù)的第一個(gè)參數(shù)就是線程的句柄。
??? 看VC中總是出現(xiàn)這個(gè)句柄的概念,以前一直以為就是指指針,但是越看越覺得不是這么簡單,于是本著有問題百度一下的原則,看到如下解釋,很是經(jīng)典:

??? csdn上有人說過:牧童遙指杏花村。
??? 牧童的手為指針,杏花村的牌子為句柄,杏花村酒店為對象的實(shí)例.

??? 句柄就是烤叉,用烤爐烤過鴨,雞,牛,羊,狗么?
??? 爐子里的東西是看不見,摸不到的,但你能用叉子去控制,至于叉子上的是什么,你放進(jìn)去前應(yīng)該記住。呵呵

??? 句柄有時(shí)是指針,有時(shí)是索引,但他絕對是一把鑰匙,內(nèi)核句柄110的鑰匙,GDI句柄是您的鑰匙,只對您有效。

??? 單從概念上講,句柄指一個(gè)對象的標(biāo)識,而指針是一個(gè)對象的首地址。從實(shí)際處理的角度講,即可以把句柄定義為指針,又可以把它定義為同類對象數(shù)組的索引,這兩種處理方法都有優(yōu)缺點(diǎn),至于選用哪種方式,完全應(yīng)該看實(shí)際需要,這可以說是一種程序設(shè)計(jì)上的技巧。那種單純認(rèn)為句柄是指針或索引的想法都是機(jī)械的、不確切的。其實(shí),在Windows中類似的處理是很多的、很靈活的。再具個(gè)相似的例子:

??? 我們知道,在Windows中有個(gè)函數(shù)叫做CallWindowProc。
??? 故名思義,它的作用就是向指定的窗口過程傳遞一個(gè)消息。你也許會想,既然我已經(jīng)有了窗口過程的指針,為什么我不可以直接通過這個(gè)指針調(diào)用該函數(shù)(這是C語言的內(nèi)建功能)?事實(shí)上,在Win16中確實(shí)可以這么做,因?yàn)镚etWindowLong返回的確實(shí)是該函數(shù)的指針。但在Win32 下,GetWindowLong返回的并不是該函數(shù)的指針,而是一個(gè)包含函數(shù)指針的數(shù)據(jù)結(jié)構(gòu)的指針(MSDN上說返回的是一個(gè)窗口函數(shù)地址或它的句柄,就是指的這種情況)。該數(shù)據(jù)結(jié)構(gòu)是可變的,但只要你使用CallWindowProc來調(diào)用的話是不會出錯的。這里我們又看到使用句柄處理帶來的好處。(補(bǔ)充說明一點(diǎn):微軟在這里之所以這么處理,是為了解決16位/32位以及ANSI/UNICODE的轉(zhuǎn)化問題)

??? 看來,句柄很多時(shí)候是一個(gè)用于描述和標(biāo)記一個(gè)資源的數(shù)據(jù)結(jié)構(gòu)的指針,而不是資源本身的指針,句柄中可能包含資源的指針,但是根多時(shí)候不僅僅是這樣。

句柄vs指針
??? 句柄是一種指向指針的指針。我們知道,所謂指針是一種內(nèi)存地址。應(yīng)用程序啟動后,組成這個(gè)程序的各對象是住留在內(nèi)存的。如果簡單地理解,似乎我們只要獲知這個(gè)內(nèi)存的首地址,那么就可以隨時(shí)用這個(gè)地址訪問對象。但是,如果您真的這樣認(rèn)為,那么您就大錯特錯了。我們知道,Windows是一個(gè)以虛擬內(nèi)存為基礎(chǔ)的操作系統(tǒng)。在這種系統(tǒng)環(huán)境下,Windows內(nèi)存管理器經(jīng)常在內(nèi)存中來回移動對象,依此來滿足各種應(yīng)用程序的內(nèi)存需要。對象被移動意味著它的地址變化了。如果地址總是如此變化,我們該到哪里去找該對象呢?為了解決這個(gè)問題,Windows操作系統(tǒng)為各應(yīng)用程序騰出一些內(nèi)存儲地址,用來專門登記各應(yīng)用對象在內(nèi)存中的地址變化,而這個(gè)地址(存儲單元的位置)本身是不變的。Windows內(nèi)存管理器在移動對象在內(nèi)存中的位置后,把對象新的地址告知這個(gè)句柄地址來保存。這樣我們只需記住這個(gè)句柄地址就可以間接地知道對象具體在內(nèi)存中的哪個(gè)位置。這個(gè)地址是在對象裝載(Load)時(shí)由系統(tǒng)分配給的,當(dāng)系統(tǒng)卸載時(shí) (Unload)又釋放給系統(tǒng)。句柄地址(穩(wěn)定)→記載著對象在內(nèi)存中的地址→對象在內(nèi)存中的地址(不穩(wěn)定)→實(shí)際對象。但是,必須注意的是程序每次從新啟動,系統(tǒng)不能保證分配給這個(gè)程序的句柄還是原來的那個(gè)句柄,而且絕大多數(shù)情況的確不一樣的。假如我們把進(jìn)入電影院看電影看成是一個(gè)應(yīng)用程序的啟動運(yùn)行,那么系統(tǒng)給應(yīng)用程序分配的句柄總是不一樣,這和每次電影院售給我們的門票總是不同的一個(gè)座位是一樣的道理。

?

指針與句柄的區(qū)別

??? 對于Wind32 API,盡管為每個(gè)對象分配了數(shù)據(jù)塊,但是微軟不想向用戶程序返回指針。對于一個(gè)聰明的程序員來說,指針包含了太多的信息。它給出了對象存儲的確切位置。指針一般允許對對象的內(nèi)部表示進(jìn)行讀寫操作,而這些內(nèi)部表示也許正是操作系統(tǒng)想隱瞞的。指針還使越過進(jìn)程地址空間共享對象變得困難。為了對程序員進(jìn)一步隱藏信息,Win32對象創(chuàng)建程序?qū)嵗话銜祷貙ο缶浔ο罂梢杂成涞轿ㄒ痪浔?#xff0c;句柄也可由映射到唯一的對象。為了保證句柄能夠完成信息隱藏的的任務(wù),對象和句柄之間的映射沒有任何文檔記載,不保證固定不變,而已僅有微軟知道這種映射,或者還有少數(shù)系統(tǒng)級工具開放商知道。
??? 對象指針和句柄之間的映射可以由函數(shù)Encode和Decode來實(shí)現(xiàn),原型如下:
??? HANDLE Encode(void* pObject);
??? Void* Decode(HANDLE hObject);
??? 在極端情況下,句柄可以和對象指針相同,Encode和Decode只需做類型轉(zhuǎn)換,對象和句柄之間的映射主要是全等映射。
??? 在Win32 API中,實(shí)例句柄(HINSTANCE)或者模塊句柄(HMODULE)是指向映射到內(nèi)存的PE文件映像的指針。LockResource用來鎖住全局資源句柄得到指針,但實(shí)際上它們的值相同。LockResource返回的資源句柄只是偽裝后的內(nèi)存映射資源的指針。
??? 通常情況下,對象指針和句柄之間的映射是基于表格的映射。操作系統(tǒng)創(chuàng)建表格或者是一級表示保存所有要考慮的對象。需要創(chuàng)建新對象時(shí),首先要在表格中找到空入口。然后就把表示對象的數(shù)據(jù)添入其中。當(dāng)對象被刪除時(shí),它的數(shù)據(jù)成員和它在中的入口被釋放,以便再利用入口。用這種基于表的對象管理方法,表中的索引可以很好的組成對象的句柄,編碼和解碼也很簡單。
??? (在Win32 API中,內(nèi)核對象是用進(jìn)程表實(shí)現(xiàn)的。為了容納大量內(nèi)核對象,每個(gè)進(jìn)程都有自己的內(nèi)核對象表。NT/2000內(nèi)核執(zhí)行體中一部分是對象管理器,它只管理內(nèi)核對象。對象管理器提供函數(shù)ObReferenceObjectByHandle。根據(jù)DDK(Driver Develepment Kits)文檔,它提供對象指針的解碼全過程,如果存取操作被批準(zhǔn),則會返回對象體相應(yīng)的指針。因此對于一個(gè)把對象句柄翻譯稱為對象指針的解碼全程來說,額外的安全檢查很重要。
www.internals.com上面有個(gè)非常好的工具HandleEx,它能夠列出Windows NT/2000的內(nèi)核對象。
??? 只有句柄是不夠的,盡管句柄提供了近乎完美的抽象,信息隱藏和保護(hù),但是它也是程序員遭受挫折的地方。在像Win32 API這樣以句柄為中心的API中,微軟沒有任何文檔記載對象的內(nèi)部表示以及對象是如何管理的,也沒有提供參考實(shí)現(xiàn),程序員只有函數(shù)原型,微軟文檔和或多或少基于微軟文檔的書籍。程序員面臨的首要問題包括系統(tǒng)資源。當(dāng)對象被創(chuàng)建,對象的句柄被返回時(shí),誰都不知道對象用了什么資源,因?yàn)閷ο蟮膬?nèi)部表示是不知道的。程序員是應(yīng)該保護(hù)該對象還是應(yīng)該在對象沒有用時(shí)盡快把它刪除呢?GDI支持的三種位圖,為了減少系統(tǒng)資源消耗,應(yīng)該使用哪一種呢?CPU時(shí)間時(shí)計(jì)算機(jī)的主要資源。當(dāng)內(nèi)部表示對程序員隱藏時(shí),程序員就很難在復(fù)雜的算法設(shè)計(jì)中判斷這種操作的復(fù)雜性如果你用GDI組成復(fù)雜區(qū)域,算法的復(fù)雜度是O(n)(問題規(guī)模n),O( )(問題規(guī)模)還是O()。隨著程序的隱藏,調(diào)試也成問題。程序運(yùn)行5分鐘顯示了一些垃圾數(shù)據(jù),猜測由資源泄漏,但是泄漏在哪兒?怎么解決?如果是處理系統(tǒng)中幾百個(gè)應(yīng)用程序的管理員,當(dāng)系統(tǒng)資源很少時(shí),如果找出問題?唯一可以用的資源泄漏工具是BoundsChecker,它依賴API窺視技術(shù)查出對象創(chuàng)建和刪除之間的不匹配之處。最讓人受挫的地方可能是程序的兼容性。程序?yàn)槭裁茨茉赪indows95下把GDI對象從一個(gè)進(jìn)程傳遞到另外一個(gè)進(jìn)程,而 Windows NT/2000不行?為什么Windows95不能處理大的設(shè)備無關(guān)圖?
??? 以GDI對象為例子,創(chuàng)建了GDI對象,就會得到該對象的句柄。句柄的類型有可能是HPEN,HBRUSH,HFONT或者是HDC中的一種。但最普通的 GDI對象類型是HGDIOBJ,它被定義成為空指針。HPEN的實(shí)際編譯類型是隨著時(shí)間宏STRICT的不同而不同。不同GDI句柄的定義模仿了GDI 對象不同類的類層次結(jié)構(gòu),但是沒有真正的類層次結(jié)構(gòu)。GDI對象一般有多個(gè)創(chuàng)建函數(shù)和一個(gè)接受HGDIOBJ的析構(gòu)函數(shù)——DeleteObject。也可以用GetStockObject取得預(yù)先創(chuàng)建好的GDI對象句柄,無論GetStockObject調(diào)用順序是如何,它返回的句柄看起來總是常數(shù)。甚至當(dāng)運(yùn)行一個(gè)程序的兩個(gè)實(shí)例時(shí),它在每個(gè)進(jìn)程中返回相同的,唯一解釋是對象句柄堆是不變的,系統(tǒng)初始化,堆對象被創(chuàng)建并被所有進(jìn)程重復(fù)使用。盡管 Windows頭文件把GDI句柄定義成為指針,但是檢查這些句柄的值時(shí),它們根本不像指針。生成幾個(gè)GDI對象句柄并看一下返回句柄的十六進(jìn)制顯示,就會發(fā)現(xiàn)結(jié)果從0x01900011變化到0xba040389。如果HGDIOBJ像在Windows頭文件里面定義的那樣是指針,則前者是指向用戶地址空間中未分配的無效指針,而后者是執(zhí)行內(nèi)核地址空間。這就暗示GDI句柄不是指針。另一個(gè)發(fā)現(xiàn)是GetStockObject(BLACK_PEN)和 GetStockObject(NULL_PEN)返回值只相差一,如果句柄真的是指針的話,這不可能是存儲內(nèi)部GDI對象的空間,因此可以肯定的說 GDI對象句柄不是指針。系統(tǒng)GDI句柄數(shù)限制為16384個(gè),進(jìn)程GDI句柄數(shù)限制為12000個(gè)。這樣單獨(dú)的進(jìn)程不會搞亂整個(gè)GDI系統(tǒng)。但是 Windows 2000第一版沒有對每個(gè)進(jìn)程加以限制。現(xiàn)在在同一個(gè)系統(tǒng)下運(yùn)行兩個(gè)GDIHandles,在每一個(gè)進(jìn)程中調(diào)用8192次CreatePen。第一個(gè)很好的創(chuàng)建了對象,第二個(gè)在7200左右會停止。第二個(gè)進(jìn)程失敗后,整個(gè)屏幕一團(tuán)糟,這個(gè)試驗(yàn)表示GDI對象同樣是從同一個(gè)資源池分配的。系統(tǒng)中的進(jìn)程使用 GDI資源時(shí)會互相影響。把8192和7200相加。考慮到GDIHandle屬性頁面和其它進(jìn)程的頁面使用的GDI對象句柄,可以猜測,GDI句柄數(shù)目有系統(tǒng)范圍限制:16384。GDI對象存儲于系統(tǒng)范圍內(nèi)的固定大小的對象表中,稱之為對象句柄表。它是一個(gè)大小固定的表,而不是一個(gè)會動態(tài)增長的數(shù)據(jù)結(jié)構(gòu)。這就意味著簡明和效率。但是???? 缺點(diǎn)就是前面說的,限制了GDI句柄數(shù):16384個(gè)。下面看看HGDIOBJ的構(gòu)成,Windows NT/2000下,GDI返回的對象句柄是32位值,組成8位十六進(jìn)制數(shù)。如果用GDIHandles創(chuàng)建很多GDI對象,注意到其中顯示的雙字句柄的低位字,會發(fā)現(xiàn)它們都在0x000到0x3FFF之間。低位字在進(jìn)程中總是唯一的,出了堆對象外,低位字甚至在進(jìn)程中也是唯一的。句柄的低位有時(shí)候按照遞增的順序排列,有時(shí)候又遞減。在進(jìn)程間也是這樣。例如,某些情況下,CreatePen在低位返回0x03C1,另一個(gè)進(jìn)程中的下一個(gè)CreatePen在低位返回0x03C3。對這些現(xiàn)象的解釋是HGDIOBJ的低位字是對系統(tǒng)范圍的16384個(gè)GDI對象所組成的表的索引。再來關(guān)注高4位的十六進(jìn)制數(shù)。創(chuàng)建幾個(gè)畫刷,幾個(gè)畫筆,幾個(gè)字體,DC等。不難看出相同類型的GDI對象句柄有個(gè)共同特點(diǎn):相同類型的對象句柄的第三位和第四位十六進(jìn)制數(shù)幾乎都是相同的。畫刷句柄的第三位和第四位總是0x90和0x10,畫筆總是0x30和0xb0等等。最高位是1(二進(jìn)制)的對象句柄都是堆對象。因此可以有足夠的證據(jù)說對象句柄的第三位和第四位十六進(jìn)制數(shù)是對象類型的編碼和堆對象標(biāo)記。在32位GDI句柄值中余下的兩個(gè)十六進(jìn)制位暫時(shí)還沒找到有意義的模式。總結(jié)一下,GDI對象句柄由8位位置高位,一位堆對象標(biāo)記,7位對象類型信息和高四位為0的16位索引組成。因?yàn)镚DI對象表是由系統(tǒng)中所有過程和系統(tǒng)DLL所共享的,桌面,瀏覽器,字處理器以及DirectX游戲都在為同一個(gè)GDI句柄的儲存區(qū)而競爭。而在Windows 2000中,DirectX則使用一個(gè)獨(dú)立的對象句柄表。GDI句柄表一般存儲在內(nèi)核模式的地址空間里以使圖形引擎能很容易訪問它,通過一定技巧,將為每個(gè)使用GDI的進(jìn)程在用戶模式存儲空間里面建立表的只讀視圖。在Windows 2000終端服務(wù)中,每個(gè)對話都有它自己的Windows圖形引擎和視窗管理器(WIN32K.SYS)的拷貝,以至于系統(tǒng)中有多個(gè)GDI對象表。
??? GDI句柄表的每一個(gè)入口都是一個(gè)16字節(jié)的結(jié)構(gòu)體,如下面代碼所示: Typedef struct?

??? {??

??? void*??????? pKernel;??

??? unsigned short nPaid;??

??? unsigned short nCount;??

??? unsigned short nUnique;??

??? unsigned short nType;??

??? void*??????? pUser;??

} GdiTableEntry;?
復(fù)制代碼可見:GDI對象有一個(gè)指向它的內(nèi)核模式對象的指針,一個(gè)指向其用戶模式的指針,一個(gè)過程ID,一個(gè)種類的計(jì)數(shù),一個(gè)唯一性的標(biāo)準(zhǔn)值以及一個(gè)類型標(biāo)識符。多么完美,優(yōu)雅的設(shè)計(jì)!
??? 盡管Win32 API不是面相對象的API,但它也面臨著和面相對象語言一樣要解決的問題,即信息的隱藏和抽象數(shù)據(jù)類型,而且Win32 API比面相對象語言更想隱藏對象。用于創(chuàng)建Win32對象的Win32函數(shù)隱藏了該對象的大小和儲存位置,而且沒有返回指向?qū)ο蟮闹羔?#xff0c;而是僅僅返回該對象的句柄。Win32 API句柄是Win32對象一一對應(yīng)的變量,它僅能被操作系統(tǒng)識別。分析一下,你會發(fā)現(xiàn)Win32使用了相當(dāng)多的抽象數(shù)據(jù)類型,如文件對象,它包括了許多具體的對象類型,我們可以用CreateFile來創(chuàng)建文件,管道,通訊端口,控制臺,目錄以及設(shè)備等,但是這些操作都返回一種類型的句柄。跟蹤到 WriterFile中,會發(fā)現(xiàn)最后的操作其實(shí)是操作系統(tǒng)中不同例程甚至是不同產(chǎn)商提供的設(shè)備驅(qū)動程序來處理的,這就像是C++的虛函數(shù)和多態(tài)機(jī)制。同樣,在GDI域中,設(shè)備上下文被當(dāng)作一個(gè)抽象對象類型看待。創(chuàng)建或者檢索打印機(jī)設(shè)備上下文,顯示設(shè)備上下文,內(nèi)存設(shè)備上下文和圖元文件上下文的程序都將返回同類型的設(shè)備上下文句柄。顯而易見的是,同年國國句柄的類屬繪圖調(diào)用是通過不同的例程來處理的,而這些例程但是由GDI或者圖形設(shè)備驅(qū)動程序通過物理設(shè)備結(jié)構(gòu)中的函數(shù)指針表來實(shí)現(xiàn)的。因此實(shí)現(xiàn)這樣的機(jī)制也會像C++一樣有一個(gè)類似于虛函數(shù)表的函數(shù)指針表,一個(gè)變量和函數(shù)指針通過這個(gè)表形成映射,方便的實(shí)現(xiàn)這種虛函數(shù)和多態(tài)機(jī)制,這個(gè)變量就是句柄....

總結(jié)

以上是生活随笔為你收集整理的句柄与指针的区别与联系的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。