windows(4)修改視窗過程函式的機制和論證
修改視窗類的視窗過程,能夠讓所有用這個視窗類來建立的視窗都改變了視窗過程嗎?或者換句話說,修改視窗過程,會讓修改應用於後面建立的視窗上嗎?更或者說,註冊的視窗類資訊(視窗過程)永久修改了嗎?
如果你有這些疑問,那麼就繼續往下看吧。
不管是系統視窗類,還是應用程式的視窗類(區域性和全域性),都是遵循一套機制。這種設計理念,可以讓這些保持一致,減少複雜度。這一點,我想,有點經驗的人都會想到。只是系統視窗類和應用程式視窗類註冊的時間、註冊的主體以及制定視窗類引數的主體和視窗過程等都不一樣罷了。
對於這個思想,一定要清楚,也就是提高複用,降低重複編碼。對於兩種視窗類,也都是一套機制來建立和註冊的。當然,對於其他的,也不會差的太多。那麼對於修改視窗類來說,也是一致的。
修改視窗類,並不會真的在寫入視窗類的地方直接修改,然後永久保留。為什麼?我們先說說系統公共視窗類。這個是系統中所有程序都可以使用的。我們確實可以修改系統視窗類。但是系統不會讓我們的修改,導致其他程序使用的時候,變成你修改的樣子。所以,系統會保證公共的系統類不能被任何其他的方式修改。
那你是如何修改系統視窗類,還可以定製這些視窗的樣式的呢?不讓你直接修改系統的視窗類,是不讓你直接修改讓它,因為這個會影響別人。你的修改實際上是生成了一個副本,被修改的副本,會儲存到一個地方。通過SetWindowLong的第一個引數視窗控制代碼我們得知,這個修改,只會對你這個視窗有效。你修改了視窗類之後,再用這個視窗類去建立其讓視窗,其他視窗還是與原始視窗類的樣子來工作的。也就是說,你對前面一個視窗的視窗類的視窗過程的修改,並不會影響到後面建立的視窗。
那麼這就說明,其實系統讓你修改視窗類,是讓你有一個單獨定製一個視窗的機會,系統會將你的修改的部分,單獨儲存起來,並與你這個視窗關聯,那麼與這個關聯的視窗相關的訊息,用你指定的新的視窗類來執行,而其他的視窗類,也就是沒有修改視窗過程的視窗,它們的訊息還是預設的處理方式。
系統視窗類是這麼處理的,其實應用程式視窗類也是如此,他們都是一套思想做的。所以,視窗子類化(修改視窗的處理過程)就是一個單獨的行為,只會影響到指定的視窗,不會影響到其他。
下面給兩個程式碼例子大家去驗證。第一個視窗是用原始的視窗類來建立的,但是修改了這個視窗的視窗過程。那麼他就會執行新的視窗過程來處理訊息。如果是系統視窗類,那麼你就可以定製這個視窗的行為了。而應用程式視窗類本來你就可以定義,不過你修改後,可以用另外一個視窗類來處理。而第二個視窗則是在第一個視窗修改了視窗過程後建立的,而創建出來的視窗,由原始的視窗的視窗過程處理,也就是說,不受你修改的視窗過程處理。這就證明了,你修改視窗過程的行為只對你指定的這個視窗有效。
程式碼1.修改系統視窗類效果圖和程式碼
第一個視窗被修改視窗過程背景成了灰色,單擊可以彈出訊息
第二個視窗沒有受到第一個視窗的視窗過程的修改,是系統預設的樣子,單擊沒有彈出訊息
程式碼如下:
#include <Windows.h> #include <tchar.h> LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK BTNProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, PSTR szCmdLine, int iCmdShow) { MSG msg; HWND hButton = CreateWindow(_T("Button"), _T("按鈕"), WS_TILEDWINDOW, 0, 0, 600, 400, NULL, NULL, NULL, NULL); SetWindowText(hButton, _T("原始視窗標題_C++技術網")); ShowWindow(hButton, SW_SHOWNORMAL); SetWindowLong(hButton, GWL_WNDPROC, (LONG)BTNProc); HWND hButton2 = CreateWindow(_T("Button"), _T("按鈕2"), WS_TILEDWINDOW, 0, 0, 600, 400, NULL, NULL, NULL, NULL); SetWindowText(hButton2, _T("新標題_C++技術網")); ShowWindow(hButton2, SW_SHOWNORMAL); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK BTNProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rect; switch (message) { case WM_PAINT: hdc = BeginPaint(hwnd, &ps); GetClientRect(hwnd, &rect); FillRect(hdc, &rect, (HBRUSH)GetStockObject(GRAY_BRUSH)); DrawText(hdc, _T("新視窗上的文字 - C++技術網"), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); EndPaint(hwnd, &ps); return 0; case WM_LBUTTONDOWN: GetClientRect(hwnd, &rect); MessageBox(NULL, _T("新視窗單擊"), _T("按鈕"), MB_ICONINFORMATION); return 0; case WM_RBUTTONDOWN: GetClientRect(hwnd, &rect); MessageBox(NULL, _T("新視窗右擊"), _T("按鈕"), MB_ICONINFORMATION); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
自己註冊的視窗類建立的視窗修改視窗過程使用了新的視窗過程的效果
第二個視窗建立,依然沒有受到第一個視窗修改視窗過程的影響
程式碼如下:
#include <Windows.h> #include <tchar.h> LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK BTNProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, PSTR szCmdLine, int iCmdShow) { static TCHAR szExeName[] = _T("Win32"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WinProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szExeName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, _T("註冊視窗類失敗,此程式需要執行在Windows NT平臺下。"), szExeName, MB_ICONERROR); return 0; } HWND hButton = CreateWindow(szExeName, _T("按鈕"), WS_TILEDWINDOW, 0, 0, 600, 400, NULL, NULL, NULL, NULL); SetWindowText(hButton, _T("原始視窗標題_C++技術網")); ShowWindow(hButton, SW_SHOWNORMAL); SetWindowLong(hButton, GWL_WNDPROC, (LONG)BTNProc); HWND hButton2 = CreateWindow(szExeName, _T("按鈕2"), WS_TILEDWINDOW, 0, 0, 600, 400, NULL, NULL, NULL, NULL); SetWindowText(hButton2, _T("視窗2標題_C++技術網")); ShowWindow(hButton2, SW_SHOWNORMAL); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rect; switch (message) { case WM_PAINT: hdc = BeginPaint(hwnd, &ps); GetClientRect(hwnd, &rect); FillRect(hdc, &rect, (HBRUSH)GetStockObject(GRAY_BRUSH)); DrawText(hdc, _T("原始視窗上的文字 - C++技術網"), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); EndPaint(hwnd, &ps); return 0; case WM_LBUTTONDOWN: GetClientRect(hwnd, &rect); MessageBox(NULL, _T("原始視窗按鈕左擊"), _T("按鈕"), MB_ICONINFORMATION); return 0; case WM_RBUTTONDOWN: GetClientRect(hwnd, &rect); MessageBox(NULL, _T("原始視窗按鈕右擊"), _T("按鈕"), MB_ICONINFORMATION); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); } LRESULT CALLBACK BTNProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rect; switch (message) { case WM_PAINT: hdc = BeginPaint(hwnd, &ps); GetClientRect(hwnd, &rect); FillRect(hdc, &rect, (HBRUSH)GetStockObject(GRAY_BRUSH)); DrawText(hdc, _T("新視窗上的文字 - C++技術網"), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); EndPaint(hwnd, &ps); return 0; case WM_LBUTTONDOWN: GetClientRect(hwnd, &rect); MessageBox(NULL, _T("新視窗單擊"), _T("按鈕"), MB_ICONINFORMATION); return 0; case WM_RBUTTONDOWN: GetClientRect(hwnd, &rect); MessageBox(NULL, _T("新視窗右擊"), _T("按鈕"), MB_ICONINFORMATION); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }