[翻譯]-WinCE 程序設計 (3rd 版)--4.2 窗口管理函數

窗口管理函數
瞭解了Windows以窗口爲中心的本質,當您可以從衆多用於窗口的函數中進行選擇時也就不足爲怪了。這些函數允許窗口查詢自己的環境,判斷自己在窗口家族裏的位置。要找到自己的父窗口,窗口可以調用GetParent(HWND hWnd),該函數接收一個窗口句柄,返回調用該函數的窗口的父窗口句柄。如果這個窗口沒有父窗口,則函數返回NULL。

枚舉窗口
GetWindow函數是一個多用途函數,它允許窗口來查詢其子窗口、擁有者和兄弟窗口。
函數原型如下:HWND GetWindow(HWND hWnd, UINT uCmd);
第一個參數是查詢窗口的句柄,第二個參數是一個常量,指出要查詢的關係。常量GW_CHILD,表示返回窗口第一個子窗口的句柄。GetWindow是按Z座標順序來返回窗口的,所以在這種情況下,第一個子窗口就是Z座標最高的子窗口。如果窗口沒有子窗口,該函數則返回NULL。常量GW_HWNDFIRST和GW_HWNDLAST,按Z座標返回第一個和最後一個窗口。如果傳入的窗口句柄是頂層窗口(頂層窗口是指沒有父窗口或父窗口是桌面窗口的窗口),這些常量按Z座標返回第一個和最後一個最頂層(topmost)窗口。如果傳入的窗口句柄是子窗口,GetWindow返回第一個和最後一個兄弟窗口。常量GW_HWNDNEXT和GW_HWNDPREV按Z座標返回下一個更低和更高的窗口。這些常量允許窗口獲得下一個窗口,並用獲得的窗口的句柄調用GetWindow來獲得下一個窗口,依次類推,最終遞歸遍歷所有的兄弟窗口。常量GW_OWNER則返回窗口擁有者的句柄。

另外一種遍歷窗口的方法是EnumWindows函數,其原型如下:
BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam);
參數lpEnumFunc指向一個回調函數,EnumWindows爲桌面上的每個頂層窗口調用一次該回調函數,並依次傳入每個窗口的句柄。lParam的值是應用程序定義的值,並被傳遞給枚舉函數。該函數比通過GetWindow循環來尋找頂層窗口的遍歷方式要好,因爲該函數始終返回有效的窗口句柄,而一個GetWindow遍歷循環裏,獲得的窗口句柄可能在下次調用GetWindow之前其對應的窗口就已經被銷燬了。但是,因爲EnumWindows只對頂層窗口有效,所以當遍歷一系列子窗口時GetWindow還是有用武之地的。

查找窗口
要獲得一個指定窗口的句柄,可以用函數FindWindow,其原型如下:HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName)。
該函數可以通過窗口的類名或者窗口的標題找到窗口。當應用程序剛啓動的時候,可以用它來判斷是否有程序的另一個副本正在運行,而應用程序所要做的只是用程序主窗口的窗口類名來調用FindWindow就可以了。因爲在運行時應用程序幾乎總是有一個主窗口的,所以當FindWindow返回NULL,就表示函數用指定的窗口類沒找到另外一個窗口,由此幾乎可以肯定沒有另一個副本在運行。

要查找桌面窗口(desktop window)的句柄,可以使用下面的函數:HWND GetDesktopWindow(void);

編輯窗口結構的內容
函數對GetWindowLong和SetWindowLong允許程序編輯窗口結構中的數據。這兩個函數原型如下:
LONG GetWindowLong(HWND hWnd, int nIndex);
LONG SetWindowLong(HWND hWnd, int nIndex, LONG dwNewLong);

一起回憶一下傳給RegisterClass函數的WNDCLASS結構吧,它有一個cbWndExtra域,用來控制分配給該結構額外字節數。如果在窗口類註冊時您爲窗口結構分配了額外的空間,那麼您可以用GetWindowLong和SetWindowLong函數來訪問這些字節。在Windows CE下,該項必須按4字節爲單位來分配和引用。所以如果窗口類在註冊時用12填充了cbWndExtra域,那麼程序可以使用窗口句柄,通過GetWindowLong或SetWindowLong函數來訪問,並且可以將nIndex參數設置爲0、4和8。

GetWindowLong和SetWindowLong支持一個預定義的索引值集合,用來使應用程序訪問窗口的一些基本參數。下面是Windows CE支持的索引值列表。
GWL_STYLE 窗口風格標誌
GWL_EXSTYLE窗口擴展風格標誌
GWL_WNDPROC指向窗口過程的指針
GWL_ID窗口標識
GWL_USERDATA應用程序使用的32位值

對話框窗口還支持下面附加的值:
DWL_DLGPROC 指向對話框窗口過程的指針
DWL_MSGRESULT 當對話框函數返回時的返回值
DWL_USER 應用程序使用的32位值

Windows CE不支持GWL_HINSTANCE和GWL_HWNDPARENT值,這些值在Windows 2000和Windows XP下是支持的。

改變風格標誌
編輯窗口結構在很多方面是很有用的。在窗口被創建後,通過改變其窗口風格位,可以改變窗口的默認行爲和外觀。例如,通過切換WS_CAPTION風格位,可以顯示或隱藏窗口的標題欄。任何修改窗口外觀的風格標誌被改變後,習慣上都要通過調用SetWindowPos來強制系統重新繪製窗口的非客戶區。

SetWindowPos是Windows中始終使用的函數之一。它允許應用程序移動窗口、改變窗口大小、變換窗口Z座標,並且在前面提到的情況下,它會重新繪製窗口的非客戶區。它的函數原型如下:
BOOL SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags);
第一個參數是即將改變的窗口的句柄。可選參數hWndInsertAfter允許設置窗口的Z座標。該參數要麼是窗口句柄,要麼是下面4個標誌之一,用來放置窗口到Z座標頂部或底部。標誌位如下所示:
HWND_BOTTOM 窗口在桌面上所有窗口之下。
HWND_TOP窗口在所有窗口的頂部
HWND_TOPMOST 窗口始終放置在其它窗口頂部,即使該窗口處於非活動窗口。
HWND_NOTTOPMOST 窗口位於其它非置頂窗口(nontopmost windows)之上,但沒有標記爲置頂窗口(topmost window),這樣當有另一個窗口成爲活動窗口時,該窗口可以被覆蓋。

可選的X、Y、cx和cy參數指定了窗口的位置和大小。標誌位參數uFlags包含一個或多個標誌位,用來描述要完成的任務。這些標誌如下所示:
SWP_NOMOVE 不移動窗口
SWP_NOSIZE 不改變窗口大小
SWP_NOZORDER 不設置窗口Z座標
SWP_NOACTIVATE 如果設置了Z座標,則不激活窗口
SWP_DRAWFRAME 重繪非客戶區
SWP_FRAMECHANGED 重新計算非客戶區,並重新繪製。
另有兩個標誌,SWP_SHOWWINDOW和SWP_HIDEWINDOW,可以顯示和隱藏窗口,但調用ShowWindow函數來顯示和隱藏窗口會更容易一些。在風格位改變後,要用SetWindowPos來強制重繪框架的話,可以如下操作:
SetWindowPos (hWnd, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);

窗口子類化
SetWindowLong的另一個用途是子類化一個窗口。本質上講,窗口子類化是使應用程序從先前存在的窗口類派生出新窗口類的一個實例。子類化的典型應用是修改窗口控件的行爲,例如一個Edit控件。

子類化的過程實際上是很簡單的。先創建一個窗口過程來爲被子類化的窗口提供新功能,再用基礎窗口類創建一個窗口。然後爲該窗口調用GetWindowLong來獲得並保存一個指向其初始窗口過程的指針,之後調用SetWindowLong函數,將窗口實例的窗口過程設置成新的窗口過程。這樣,新的窗口過程就開始接收發給該窗口的消息了。任何沒有被新窗口過程響應的消息都通過調用CallWindowProc傳遞給到舊的窗口過程。下面的代碼展示了窗口創建及被子類化的過程。子類化窗口過程截獲了WM_LBUTTONDOWN消息,並且在窗口收到該消息時使揚聲器發出聲音。
// Prototype of subclass procedure
LRESULT CALLBACK SCWndProc(HWND hWnd, UINT wMsg, WPARAM wParam,   LPARAM lParam);
  
// Variable that holds the pointer to the original WndProc
WNDPROC lpfnOldProc = 0;
//
// Routine that subclasses the requested window.
//
BOOL SubClassThisWnd (HWND hwndSC) {
  
    if (lpfnOldProc == 0) {
        // Get and save the pointer to the original window procedure
        lpfnOldProc = (WNDPROC)GetWindowLong (hwndSC, GWL_WNDPROC);
  
        // Point to new window procedure
        return SetWindowLong (hwndSC, GWL_WNDPROC, (DWORD)SCWndProc);
    }
    return FALSE;
}
//
// Subclass procedure
//
LRESULT CALLBACK SCWndProc(HWND hWnd, UINT wMsg, WPARAM wParam,
                           LPARAM lParam) {
    switch (wMsg) {
  
    case WM_LBUTTONDOWN:
        MessageBeep(0);
        break;
    }
    return CallWindowProc (lpfnOldProc, hWnd, wMsg, wParam, lParam);
}

要去除窗口的子類化,只要調用SetWindowLong,把WndProc指針設置回最初的窗口過程即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章