當前位置:編程學習大全網 - 熱門推薦 - 每壹個窗口都有壹個固定的句柄嗎?

每壹個窗口都有壹個固定的句柄嗎?

在Windows中,句柄是壹個系統內部數據結構的引用。例如,當妳操作壹個窗口,或說是壹個Delphi窗體時,系統會給妳壹個該窗口的句柄,系統會通知妳:妳正在操作142號窗口,就此,妳的應用程序就能要求系統對142號窗口進行操作——移動窗口、改變窗口大小、把窗口極小化為圖標,等等。實際上許多Windows API函數把句柄作為它的第壹個參數,如GDI(圖形設備接口)句柄、菜單句柄、實例句柄、位圖句柄等等,不僅僅局限於窗口函數。

換句話說,句柄是壹種內部代碼,通過它能引用受系統控制的特殊元素,如窗口、位圖、圖標、內存塊、光標、字體、菜單等等。

案例:獲取窗口句柄

案例說明

本例實現窗口句柄的獲取。

實現過程

Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long

Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Private Declare Function SetLayeredWindowAttributes Lib "user32" (ByVal hwnd As Long, ByVal crKey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long

Private Const WS_EX_LAYERED = &H80000

Private Const GWL_EXSTYLE = (-20)

Private Const LWA_ALPHA = &H2

Private Sub Form_Activate()

On Error Resume Next

For i = 0 To 150 Step 2.5

SetLayeredWindowAttributes Me.hwnd, 0, i, LWA_ALPHA

DoEvents

Next i

End Sub

Private Sub Form_load()

Dim rtn As Long

rtn = GetWindowLong(Me.hwnd, GWL_EXSTYLE)

rtn = rtn Or WS_EX_LAYERED

SetWindowLong Me.hwnd, GWL_EXSTYLE, rtn

SetLayeredWindowAttributes Me.hwnd, 0, 0, LWA_ALPHA

End Sub

單從概念上講,句柄指壹個對象的標識,而指針是壹個對象的首地址。從實際處理的角度講,即可以把句柄定義為指針,又可以把它定義為同類對象數組的索引,這兩種處理方法都有優缺點,至於選用哪種方式,完全應該看實際需要,這可以說是壹種程序設計上的技巧。那種單純認為句柄是指針或索引的想法都是機械的、不確切的。

其實,在Windows中類似的處理是很多的、很靈活的。再具個相似的例子:

我們知道,在Windows中有個函數叫做CallWindowProc。故名思義,它的作用就是向指定的窗口過程傳遞壹個消息。妳也許會想,既然我已經有了窗口過程的指針,為什麽我不可以直接通過這個指針調用該函數(這是C語言的內建功能)?事實上,在Win16中確實可以這麽做,因為GetWindowLong返回的確實是該函數的指針。但在Win32下,GetWindowLong返回的並不是該函數的指針,而是壹個包含函數指針的數據結構的指針(MSDN上說返回的是壹個窗口函數地址或它的句柄,就是指的這種情況)。該數據結構是可變的,但只要妳使用CallWindowProc來調用的話是不會出錯的。這裏我們又看到使用句柄處理帶來的好處。(補充說明壹點:微軟在這裏之所以這麽處理,是為了解決16位/32位以及ANSI/UNICODE的轉化問題)

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對象。

  • 上一篇:吳彥祖的電影《如夢》想表達什麽?
  • 下一篇:索尼全息透鏡技術眼鏡SmartEyeGlasses有什麽了不起
  • copyright 2024編程學習大全網