对界面进行封装,一般都是一个窗口一个类,比如实现一个最基本的窗口类CMyWnd,你一定会把窗口过程作为这个类的成员函数,但是使用WINAPI创建窗口时必须注册类WNDCLASS,里面有个成员数据lpfnWndProc需要WNDPROC的函数指针,一般想法就是把窗口类的消息处理函数指针传过去,使用静态类成员函数,或者全局的消息处理函数,否则无法转换到WNDPROC。
静态消息处理函数:缺点,消息处理函数无法获取到窗口对象的窗口句柄。
全局消息处理函数:无法得到窗口类对象指针。
一种解决方法是用窗口列表,开一个结构数组,窗口类对象创建窗口的时候把窗口HWND和this指针放入数组,全局消息处理函数遍历数组,利用HWND找出this指针,然后定位到对象内部的消息处理函数。这种方法查找对象的时间会随着窗口个数的增多而增长。代码如下:
#ifndef _WINDOW_H_ #define _WINDOW_H_ #include "stdafx.h" #include "Resource.h" #include <map> class window{ public: window():_hwnd(NULL){} ~window(){} bool Create(HINSTANCE hInstance,const LPCTSTR lpszClassName); protected: HWND _hwnd; private: LRESULT CALLBACK WndProc(UINT message, WPARAM wParam, LPARAM lParam); void RemoveHwndFormMap(); protected: static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); static std::map<HWND,window*>* _sWindowMap; }; std::map<HWND,window*>* window::_sWindowMap = new std::map<HWND,window*>; bool window::Create(HINSTANCE hInstance,LPCTSTR lpszClassName) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = StaticWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TEST)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_TEST); wcex.lpszClassName = lpszClassName; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); RegisterClassEx(&wcex); _hwnd = CreateWindow(lpszClassName, NULL, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (_hwnd == NULL) { MessageBox(NULL,TEXT("Error"),NULL,NULL); return FALSE; } //_sWindowMap[_hwnd] = this; (*_sWindowMap).insert(std::make_pair(_hwnd,this)); ShowWindow(_hwnd, SW_SHOW); UpdateWindow(_hwnd); return TRUE; } LRESULT CALLBACK window::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { if ((*_sWindowMap).empty()) { return ::DefWindowProcW(hWnd, message, wParam, lParam); }else return (*_sWindowMap)[hWnd]->WndProc( message, wParam, lParam); } LRESULT CALLBACK window::WndProc(UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // 分析菜单选择: switch (wmId) { case IDM_ABOUT: //DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); MessageBox(NULL,TEXT("AboutDlg"),TEXT("关于"),NULL); break; case IDM_EXIT: DestroyWindow(_hwnd); RemoveHwndFormMap(); break; default: return DefWindowProc(_hwnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(_hwnd, &ps); // TODO: 在此添加任意绘图代码... EndPaint(_hwnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); RemoveHwndFormMap(); break; default: return ::DefWindowProc(_hwnd, message, wParam, lParam); } return 0; } void window::RemoveHwndFormMap() { std::map<HWND,window*>::iterator it; it = (*_sWindowMap).find(_hwnd); (*_sWindowMap).erase(it); } #endif