05. 子类化
需求:对话框中的Edit Control只能输入字母和数字。
解决方案:替换Edit Control的WndProc,在收到WM_CHAR时判断是否合法,合法则调用原来的WndProc,否则直接返回。收到其他类型的消息时也调用原来的WndProc。最好通过CallWindowProc调用,而不是直接调用原来的WndProc。CallWindowProc的函数处理Unicode到ANSI转换,如果直接调用窗口过程,则无法利用此转换。
// WindowsProject1.cpp : 定义应用程序的入口点。 // #include "framework.h" #include "WindowsProject1.h" INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); INT_PTR oldProc; int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); DialogBox(hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), 0, About); return (int)0; } INT_PTR CALLBACK NewProc(HWND hEdit, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CHAR: if ('0' <= wParam && wParam <= '9' || 'a' <= wParam && wParam <= 'z' || 'A' <= wParam && wParam <= 'Z') { return CallWindowProc((WNDPROC)oldProc, hEdit, message, wParam, lParam); } else { return 0; } } return CallWindowProc((WNDPROC)oldProc, hEdit, message, wParam, lParam); } // “关于”框的消息处理程序。 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK) { if (!oldProc) { HWND hEdit = GetDlgItem(hDlg, IDC_EDIT1); oldProc = GetWindowLongPtr(hEdit, GWLP_WNDPROC); SetWindowLongPtr(hEdit, GWLP_WNDPROC, (LONG_PTR(NewProc))); } return (INT_PTR)TRUE; } if (LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); } break; } return (INT_PTR)FALSE; }
也可调用GetClassLongPtr和SetClassLongPtr实现需求,但是它们对新创建的Edit Control有效,已经创建的不受影响。
if (LOWORD(wParam) == IDOK) { if (!oldProc) { HWND hEdit = GetDlgItem(hDlg, IDC_EDIT1); oldProc = GetClassLongPtr(hEdit, GCLP_WNDPROC); SetClassLongPtr(hEdit, GCLP_WNDPROC, (LONG_PTR(NewProc))); HWND hNewEdit = CreateWindow(L"EDIT", L"文本", WS_BORDER |WS_CHILD, 62, 152, 200, 20, hDlg, 0, (HINSTANCE)GetClassLongPtr(hDlg, GCLP_HMODULE), 0); ShowWindow(hNewEdit,SW_SHOW); } return (INT_PTR)TRUE; }