对界面进行封装,一般都是一个窗口一个类,比如实现一个最基本的窗口类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