lal科比時代
回答數:114 | 被采納數:30
感謝你!
-----------------
*.模塊(module)
*.任務(task)
*.實例(instance)
*.文件(file)
*.內存塊(block of memory)
*.菜單(menu)
*.控製(control)
*.字體(font)
*.資源(resource),包括圖標(icon),光標(cursor),字符串(string)等
*.GDI對象(GDI object),包括位圖(bitmap),畫刷(brush),元文件(metafile),調色板(palette),畫筆(pen),區域(region),以及設備描述表(device context)。
WINDOWS程序中並不是用物理地址來標識一個內存塊,文件,任務或動態裝入模塊的。相反,WINDOWS API給這些項目分配確定的句柄,並將句柄返回給應用程序,然後通過句柄來進行操作。
在《WINDOWS編程短平快》(南京大學出版社)一書中是這麼說的:句柄是WINDOWS用來標識被應用程序所建立或使用的對象的唯一整數,WINDOWS使用各種各樣的句柄標識諸如應用程序實例,窗口,控製,位圖,GDI對象等等。WINDOWS句柄有點象C語言中的文件句柄。
從上麵的2個定義中我們可以看到,句柄是一個標識符,是拿來標識對象或者項目的。它就像我們的車牌號一樣,每一輛注冊過的車都會有一個確定的號碼,不同的車號碼各不相同,但是也可能會在不同的時期出現兩輛號碼相同的車,隻不過它們不會同時處於使用之中罷了。應用程序幾乎總是通過調用一個WINDOWS函數來獲得一個句柄,之後其他的WINDOWS函數就可以使用該句柄,以引用相應的對象。在WINDOWS編程中會用到大量的句柄,比如:HINSTANCE(實例句柄),HBITMAP(位圖句柄),HDC(設備描述表句柄),HICON(圖標句柄)等等。這當中還有一個通用的句柄,就是HANDLE,比如下麵的語句:
HINSTANCE hInstance;
可以改成:
HANDLE hInstance;
上麵的2條語句都是對的。
一個WINDOWS應用程序可以用不同的方法獲得一個特定項的句柄。許多API函數,諸如CreateWindow,GlobalAlloc,OpenFile的返回值都是一個句柄值。另外,WINDOWS也能通過應用程序的引出函數將一個句柄作為參數傳送給應用程序,應用程序一旦獲得了一個確定項的句柄,便可在WINDOWS環境下的任何地方對這個句柄進行操作。其實句柄的大量使用已經影響到了每一個WINDOWS的程序設計。
一個句柄,隻有當唯一地確定了一個項目的時候,它才開始有意義。句柄對應著項目表中的一項,而隻有WINDOWS本身才能直接存取這個表,應用程序隻能通過API函數來處理不同的句柄。舉個例子來說吧,比如:我們可以為我們的應用程序申請一塊內存塊,通過調用API函數GlobalAlloc,來返回一個句柄值:
hMem=GlobalAlloc(......);
其實現在hMem的值隻是一個索引值,不是物理地址,應用程序還不能直接存取這塊內存。這兒還有一個話外題,是關於操作係統的內存管理的。一般情況下操作係統給應用程序分配的內存塊都是可以被移動的或者是可以丟棄的,這樣能使有限的內存資源得到充分利用。所以,我們剛開始分配到的那塊內存的地址是不確定的,因為它是可以被移動的,所以得先鎖定那塊內存塊,這裏應用程序需要調用API函數GlobalLock函數來鎖定句柄。如下:
lpMem=GlobalLock(hMem);
這樣應用程序才能存取這塊內存。
句柄是一個標識符,是拿來標識對象或者項目的。應用程序幾乎總是通過調用一個WINDOWS函數來獲得一個句柄,之後其他的WINDOWS函數就可以使用該句柄,以引用相應的對象。
如果想更透徹一點地認識句柄,我可以告訴大家,句柄是一種指向指針的指針。我們知道,所謂指針是一種內存地址。應用程序啟動後,組成這個程序的各對象是駐留在內存中的。簡單地理解,似乎我們隻要獲知這個內存的首地址,就可以隨時用這個地址訪問對象了。如果您真的這樣認為,那您可就大錯特錯了。我們知道,Windows是一個以虛擬內存為基礎的操作係統。在這種係統環境下,Windows內存管理器經常在內存中來回移動對象,以此來滿足各種應用程序的內存需要。對象被移動意味著它的地址變化了。如果地址總是如此變化,我們該到哪裏去找那一個對象呢?
為了解決這個問題,Windows操作係統為全體應用程序騰出一些內存單元,用來專門登記各應用程序的對象在內存中的地址的變化,而前者的物理地址在係統運行期間是始終保持不變的。Windows內存管理器移動了對象在內存中的位置後,會把該對象新的地址及時地告知給對應的句柄進行更新。這樣我們隻要知道這個句柄,就可以間接地知道對象具體在內存中的哪個位置了。這個地址是在對象裝載(Load)時由係統分配給的,當係統卸載時(Unload)又釋放給係統。
[編輯本段]注意事項
內核對象句柄,是用來標識某個內核對象的一個id
同一個對象的該id對於每個進程是不同的,具體如何實現是ms不公開的算法,以下是一個近似的,可能的算法:
進程創建時,windows係統為進程構造了一個句柄表
當該進程希望獲得一個內核對象句柄或者創建一個內核對象從而獲得該對象句柄時
係統會將在句柄表中增加一個表項,表項的內容中存儲了指向目標內核對象的指針
同時,係統返回這個表項在句柄表中的索引作為句柄
這樣,進程就通過句柄查詢句柄表得到對象指針,從而可以訪問該對象。
同時又由於有了句柄表的保護,可以防止對內核對象的非法操作。
我想現在大家已經能對句柄概念有所了解了,我希望我的文章能對大家有所幫助。其實如果你學過SDK編程,那對句柄的概念理解會更好,更深。如果你是直接學VC6的MFC編程的,建議你看一下SDK編程,這會對你大有好處。