typedef unsigned int HANDLE;
#define DECLARE_HANDLE(name) typedef UINT name
DECLARE_HANDLE(HMODULE);
DECLARE_HANDLE(HINSTANCE);
DECLARE_HANDLE(HLOCAL);
DECLARE_HANDLE(HGLOBAL);
DECLARE_HANDLE(HDC);
DECLARE_HANDLE(HRGN);
DECLARE_HANDLE(HWND);
DECLARE_HANDLE(HMENU);
DECLARE_HANDLE(HACCEL);
DECLARE_HANDLE(HTASK);
...
#define DECLARE_HANDLE(x) typedef WORD x
//+-------------------------------------------------------------------------
// DECLARE_HANDLE Macro
//--------------------------------------------------------------------------
#ifndef DECLARE_HANDLE
#define DECLARE_HANDLE(name) \
struct name##__ { DWORD unused; }; \
typedef struct name##__ _far* name
#endif
知道本質了吧~~~~
WINDOWS程式中并不是用實體位址來辨別一個記憶體塊,檔案,任務或動态裝入子產品的,相反的,WINDOWS API給這些項目配置設定确定的句柄,并将句柄傳回給應用程式,然後通過句柄來進行操作。
在< <WINDOWS程式設計短平快>>(南京大學出版社)一書中是這麼說的:句柄是WONDOWS用來辨別被應用程式所建立或使用的對象的唯 一整數,WINDOWS使用各種各樣的句柄辨別諸如應用程式執行個體,視窗,控制,位圖,GDI對象等等。WINDOWS句柄有點象C語言中的檔案句柄。
從 上面的2個定義中的我們可以看到,句柄是一個辨別符,是拿來辨別對象或者項目的,它就象我們的姓名一樣,每個人都會有一個,不同的人的姓名不一樣,但是, 也可能有一個名字和你一樣的人。從資料類型上來看它隻是一個16位的無符号整數。應用程式幾乎總是通過調用一個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);
這樣應用程式才能存取這塊記憶體。
[url]http://bbs.xiakexing.com/cgi-bin/topic.cgi?forum=36&topic=16&show=0[/url]
1.句柄是什麼?
在windows中,句柄是和對象一一對應的32位無符号整數值。對象可以映射到唯
一的句柄,句柄也可以映射到唯一的對象。
2.為什麼我們需要句柄?
更準确地說,是windows需要句柄。windows需要向程式員提供必要地程式設計接口
,在這些接口中,允許程式員通路、建立和銷毀對象。但是,出于封裝地考慮,wi
ndows并不想向程式員傳回指針。指針包含了太多的資訊。首先指針給出了對象存儲
的确切位置;其次,要操作一個指針,程式員必須知道指針所指對象的内部結構特
征,也即,windows必須向程式員暴露相應的資料結構,而這些資料結構也許是操作
系統想向程式員隐藏的。
如果說COM技術向使用者隐藏了資料,隻暴露了接口并隻允許按接口定義的方法操
作資料的話,句柄這種方式則允許你按自己的方式直接操作資料,但windows又不向
你直接暴露資料。直接操作資料是程式員需要的,不暴露資料是windows所需要的,
句柄封裝方式實作了各取所需。
3.句柄如何與對象映射?
封裝背後,必須有一個地方可以實作解碼,以實作句柄和對象的互相轉換。在
windows中,存在兩種映射方式:
a. 全等映射。也即,句柄本身就是一個指針。映射在這裡隻是類型轉換而已。
這種情況有,程序執行個體句柄或子產品句柄,以及資源句柄等等。
b. 基于表格的映射。這是對象指針與句柄之間最普通的映射機制。作業系統創
建表格,并儲存所有要考慮的對象。需要建立新對象時,要先在表格中找到空入口
,然後把表示對象的資料添入其中。當對象被删除時,它的資料成員和其在表中的
入口被釋放。
4.句柄的定義和實作
我們以GDI對象為例進行讨論。建立了GDI對象,就會得到該對象的句柄。句柄
的對象可能是HBRUSH、HPEN、HFONT或HDC中的一種,這依賴于你建立 的GDI對象類
型。但是最普通的GDI對象類型是HGDIOBJ。HGDIOBJ被定義成空指針。
HPEN的實際編譯類型定義随編譯時間宏STRICT的不同而不同。如果STRCIT已經
被定義了,HPEN是這樣的:
struct HPEN__ {int unused};
typedef struct HPEN__* HPEN;
如果STRICT沒有定義,HPEN是這樣定義的:
typedef void *HANDLE;
typedef HANDLE HPEN;
上面這段代碼是一個注重細節的程式員最接近句柄的地方,是以我們重點分析
一下。這裡有一點點技巧。如果定義了STRICT宏,HPEN是指向有單個未使用字段的
結構的指針,否則HPEN是空指針。C/C++編譯器允許把任何類型的指針作為空指什傳
遞,反之則不可以。兩個不同類型的非空指針是互不相容的。在STRICT版本中,編
譯對GDI對象句柄的不正确混用将給出警告,對于非GDI句柄,如HWND、HMENU的不正
确混用也會給出警告,進而使程式在編譯器得到更STRICT的檢查。
接下來的分析可能不那麼令你感興趣,但它更深刻地揭示了句柄。對GDI句柄來
說,盡管windows頭檔案把它定義成指針,但如果你仔細檢查這些句柄的值,它根本
就不像指針,這也是為什麼我說它隻是一個32位無符整數值的原因。對句柄就是指
針的情況,這句話也仍然适用。讓我們随意地生成一些句柄,比如你用GetStockOb
ject()以得到一些句柄,你會發現,它們的值總在區間0x01900011到0xba040389。
前者指向使用者區中的未配置設定的無效區域,後者指向核心位址空間。另外你可能發現
,兩個句柄之間的值可能隻差數值1,這也說明GDI句柄不是指針。
和多數人想象的不一樣,句柄也不是一個單純的索引值。對GDI對象句柄來說,
GDI句柄由8位 、1位堆對象标記(表明對象是否建立在堆中)、7位對象類型資訊和
高4位為0的16位索引組成,如圖:
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
| 8 位引用計數 |堆 | 對象類型7 | 16位索引 |
标
記
在這裡你可以看到,對GDI來說,它隻使用了16位作為索引。這意味着一個程序最多隻
可以建立小于64K個句柄,實際上受其他一些限制,整個windwos系統中大概可以容納約
16384(0x4000)個GDI對象。
【主要内容取自windows圖形程式設計,袁峰著。稍作整理,應該不影響正确性。】
什麼是句柄
時間:2004-08-10
[url]http://blog.xjtu.edu.cn/user1/505/archives/2005/17886.shtml[/url]
所謂句柄實際上是一個資料,是一個Long (整長型)的資料。
句柄是WONDOWS用來辨別被應用程式所建立或使用的對象的唯一整數,WINDOWS使用各種各樣的句柄辨別諸如應用程式執行個體,視窗,控制,位圖,GDI對象等等。WINDOWS句柄有點象C語言中的檔案句柄。
從 上面的定義中的我們可以看到,句柄是一個辨別符,是拿來辨別對象或者項目的,它就象我們的姓名一樣,每個人都會有一個,不同的人的姓名不一樣,但是,也可 能有一個名字和你一樣的人。從資料類型上來看它隻是一個16位的無符号整數。應用程式幾乎總是通過調用一個WINDOWS函數來獲得一個句柄,之後其他的 WINDOWS函數就可以使用該句柄,以引用相應的對象。
如果想更透徹一點地認識句柄,我可以告訴大家,句柄是一種指向指針的指針。我 們知道,所謂指針是一種記憶體位址。應用程式啟動後,組成這個程式的各對象是住留在記憶體的。如果簡單地了解,似乎我們隻要獲知這個記憶體的首位址,那麼就可以 随時用這個位址通路對象。但是,如果您真的這樣認為,那麼您就大錯特錯了。我們知道,Windows是一個以虛拟記憶體為基礎的作業系統。在這種系統環境 下,Windows記憶體管理器經常在記憶體中來回移動對象,依此來滿足各種應用程式的記憶體需要。對象被移動意味着它的位址變化了。如果位址總是如此變化,我 們該到哪裡去找該對象呢?
為了解決這個問題,Windows作業系統為各應用程式騰出一些記憶體儲位址,用來專門登記各應用對象在記憶體中的 位址變化,而這個位址(存儲單元的位置)本身是不變的。Windows記憶體管理器在移動對象在記憶體中的位置後,把對象新的位址告知這個句柄位址來儲存。這 樣我們隻需記住這個句柄位址就可以間接地知道對象具體在記憶體中的哪個位置。這個位址是在對象裝載(Load)時由系統配置設定給的,當系統解除安裝時 (Unload)又釋放給系統。
句柄位址(穩定)→記載着對象在記憶體中的位址────→對象在記憶體中的位址(不穩定)→實際對象
本質:WINDOWS程式中并不是用實體位址來辨別一個記憶體塊,檔案,任務或動态裝入子產品的,相反的,WINDOWS API給這些項目配置設定确定的句柄,并将句柄傳回給應用程式,然後通過句柄來進行操作。
但 是必須注意的是程式每次從新啟動,系統不能保證配置設定給這個程式的句柄還是原來的那個句柄,而且絕大多數情況的确不一樣的。假如我們把進入電影院看電影看成 是一個應用程式的啟動運作,那麼系統給應用程式配置設定的句柄總是不一樣,這和每次電影院售給我們的門票總是不同的一個座位是一樣的道理。