在上一文中,我們從零開始建立了一個視窗。其中很重要的一個步驟,就是註冊視窗類,如下面的程式碼:
//注册窗口类 BOOL Register(LPSTR lpClassName, WNDPROC wndProc) { WNDCLASSEX wce = { 0 }; wce.cbSize = sizeof(wce); wce.cbClsExtra = 0; wce.cbWndExtra = 0; wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wce.hCursor = NULL; wce.hIcon = NULL; wce.hIconSm = NULL; wce.hInstance = g_hInstance; wce.lpfnWndProc = wndProc; wce.lpszClassName = lpClassName; wce.lpszMenuName = NULL; wce.style = CS_HREDRAW | CS_VREDRAW; ATOM nAtom = RegisterClassEx(&wce); if (nAtom == 0) return FALSE; return true; }
Windows下的任何一個視窗,在創建之前都要在系統中已經明確的註冊,我們在使用CreateWindowEx進行視窗的建立時,第二個參數的名稱就是視窗類別名稱,這個名稱在我們程式碼可見的作用域內應該是唯一的。本文主要討論下Windows下,視窗類別的問題。
Windows中所有可見的一切元素基本上都屬於一個視窗,不管它的形狀如何,是圓的、方的、甚至是無規則的。所有的這些視窗都屬於某一個視窗類,大體上來說Windows的視窗類共分為三種:
(1)系統視窗類別
(2)全域視窗類別
(3)局部視窗類別
下面,我將分別就Windows中視窗類別的分類進行討論。
一個按鈕、一個編輯框所有這些我們在windows作業系統中可見的控制項其實都是一個視窗。當我們安裝完作業系統之後,Windows會在作業系統內部註冊大量的系統層級的視窗類,我們在進行開發時,可以直接根據視窗類名稱建立這些視窗。為了解釋這個問題,在上一文的程式碼之上,我們引入下面的程式碼。
HWND CreateMain(LPSTR lpClassName, LPSTR lpWndName) { HWND hWnd = CreateWindowEx(0, lpClassName, lpWndName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hInstance, NULL); return hWnd; } int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { // TODO: Place code here. g_hInstance = hInstance; HWND hWnd = CreateMain("Button", "window"); Display(hWnd); Message(); return 0; }
CreateMain是我們定義的一個建立視窗的函數。它接收兩個參數,第一個時已經註冊的視窗類別名稱,第二個是視窗的標題。與上一文中的程式碼不同,我們省去了註冊自訂視窗的步驟。而是在WinMain函數中,呼叫CreateMain建立了一個視窗類別名稱為「Button」的視窗。我想你已經知道我們要做什麼了吧?對,就是要產生一個Button按鈕。我們常用的所有控制項都已經被作業系統註冊成了系統視窗類,我們都可以直接使用。請看下面的程式運行結果:
你也可以嘗試建立諸如編輯框、下拉框等其他系統層級的視窗。
全域視窗類別指註冊後可在應用程式全域範圍內使用的視窗類別。例如,我們可以在dll中對全域視窗類別進行註冊,那麼引入該dll的所有程式都可以使用該類別。註冊全域使用的視窗類別時,我們只需要在註冊時對wec的結構體的style成員加入CS_GLOBALCLASS屬性,如下:
wce.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
為了驗證這個問題,我們新新增一個dll項目,然後定義一個如下的視窗註冊函數RegisterWindow():
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_DESTROY: PostQuitMessage(0);//可以使GetMessage返回0 break; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } BOOL RegisterWindow() { WNDCLASSEX wce = { 0 }; wce.cbSize = sizeof(wce); wce.cbClsExtra = 0; wce.cbWndExtra = 0; wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wce.hCursor = NULL; wce.hIcon = NULL; wce.hIconSm = NULL; wce.hInstance = NULL; wce.lpfnWndProc = WndProc; wce.lpszClassName = "DllMain"; wce.lpszMenuName = NULL; wce.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS; ATOM nAtom = RegisterClassEx(&wce); if (nAtom == 0) return FALSE; return true; }
RegisterWindow()中註冊的視窗類別名稱為"DllMain",我們在dll的主函數中呼叫該註冊函數完成註冊:
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { .... RegisterWindow(); return TRUE; } }
在我們的主程式中使用此視窗類別建立視窗:
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { ... HWND hWnd = CreateMain("DllMain", "我是一个Dll注册的窗口"); Display(hWnd); Message(); return 0; }
執行程式你會發現我們也成功生產了這個視窗:
局部視窗類別從定義上來說,凡是未在wce的style中加入CS_GLOBALCLASS,而註冊的視窗類別都是局部視窗類。
wce.style = CS_HREDRAW | CS_VREDRAW;//未添加CS_GLOBALCLASS
我们在上一文中注册的窗口就是一个局部的窗口类,它的特点就是只能在注册的作用域内使用,由于它和全局窗口类只在注册的style和作用域上有分别,这里就不再详述,如要了解,请参照上一文。
以上是Win32 SDK基礎(五)之關於視窗類別的簡單介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!