封装窗口对象。
(注意。有些命名我是直接复制win32API的,偷懒了)
本来是想直接用虚函数来处理消息的,但是消息很多,写的会很吃力,所以采用类似MFC的消息映射,现在内存是很富裕的,不用担心虚函数表会占用大量内存,个人建议是采用虚函数的,我这里偷偷懒。
该类主要作用:消息处理函数调用该类的静态函数wndProc,再调用实例对象的WindowProc,进行消息处理,如果是已经注册的类,需要调换为我们的消息处理函数。(WM_CREATE和WM_NCCREATE并没有调用)
PWnd.h
#pragma once
// Windows 头文件:
#include <windows.h>
// C 运行时头文件
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <assert.h>
#include <map>
//简单的消息映射
#define DECLARE_MSGMAP()\
public:\
virtual MsgInfo* getThisMsgMap();\
static MsgInfo* getMsgMap();\
#define ADD_MSG(Msg, FunProc)\
Value_Type(Msg, (LRESULT(PWnd::*)(WPARAM wParam, LPARAM lParam))&FunProc)
#define IMPLEMENT_BEGIN_MSGMAP(thisClass, parentClass)\
MsgInfo* thisClass::getThisMsgMap()\
{ return thisClass::getMsgMap(); }\
\
MsgInfo* thisClass::getMsgMap()\
{\
typedef std::pair<UINT, LRESULT(PWnd::*)(WPARAM wParam, LPARAM lParam)> Value_Type;\
static MsgInfo info = { parentClass::getMsgMap,\
std::map<UINT, LRESULT(PWnd::*)(WPARAM wParam, LPARAM lParam)>({
#define IMPLEMENT_END_MSGMAP()\
})\
};\
return &info;\
}
class PWnd;
typedef struct _TagMsgInfo
{
struct _TagMsgInfo* (*_getParentMsg)(); //上一层消息信息
std::map<UINT, LRESULT(PWnd::*)(WPARAM wParam, LPARAM lParam)> _map; //该类所能处理消息
}MsgInfo;
class PWnd
{
public:
PWnd();
virtual ~PWnd();
protected:
static LRESULT CALLBACK wndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);
public:
static PWnd* fromHandle(HWND hWnd);
public:
LONG setWindowLongPtr(int nIndex, LONG nData);
LONG getWindowLongPtr(int nIndex);
BOOL setSubClassWindow(HWND hWnd); //动态子类化控件
BOOL isWindow();
BOOL showWindow(INT nShow);
BOOL updateWindow();
BOOL destroyWindow();
BOOL createWindowEx(DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName,
DWORD dwStyle, int X, int Y,
int nWidth, int nHeight, HWND hWndParent,
HMENU hMenu, HINSTANCE hInstance);
LRESULT default(UINT nMsg, WPARAM wParam, LPARAM lParam);
virtual BOOL preCreateWindow(LPCREATESTRUCT lpCs);
virtual LRESULT WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam);
virtual LRESULT defaultProc(UINT nMsg, WPARAM wParam, LPARAM lParam);
public: //消息
LRESULT onNcCreate(WPARAM wParam, LPARAM lParam);
LRESULT onCreate(WPARAM wParam, LPARAM lParam);
LRESULT onClose(WPARAM wParam, LPARAM lParam);
LRESULT ondestroy(WPARAM wParam, LPARAM lParam);
LRESULT onNcDestroy(WPARAM wParam, LPARAM lParam);
public: //简单消息处理
virtual MsgInfo* getThisMsgMap();
static MsgInfo* getMsgMap();
public:
HWND _hWnd;
protected:
WNDPROC _pfnOldWndProc;
};
PWnd.cpp
#include "PWnd.h"
#include <assert.h>
PWnd::PWnd() : _hWnd(NULL), _pfnOldWndProc(NULL)
{
}
PWnd::~PWnd()
{
if (isWindow() == TRUE) {
SetWindowLongPtr(_hWnd, GWL_USERDATA, NULL);
}
}
LRESULT CALLBACK PWnd::wndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
PWnd* pWnd = NULL;
if (nMsg == WM_NCACTIVATE || nMsg == WM_CREATE) {
LPCREATESTRUCT pCs = (LPCREATESTRUCT)lParam;
if (pCs && (pWnd = (PWnd*)pCs->lpCreateParams)) {
pWnd->_hWnd = hWnd;
return pWnd->WindowProc(nMsg, wParam, lParam);
}
return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
}
pWnd = (PWnd*)::GetWindowLongPtr(hWnd, GWL_USERDATA);
if (pWnd) {
return pWnd->WindowProc(nMsg, wParam, lParam);
}
return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
}
PWnd* PWnd::fromHandle(HWND hWnd)
{
assert(::IsWindow(hWnd) == TRUE);
return (PWnd*)::GetWindowLongPtr(hWnd, GWL_USERDATA);
}
LONG PWnd::setWindowLongPtr(int nIndex, LONG nData)
{
// assert(isWindow() == TRUE);
return ::SetWindowLongPtr(_hWnd, nIndex, nData);
}
LONG PWnd::getWindowLongPtr(int nIndex)
{
// assert(isWindow() == TRUE);
return ::GetWindowLongPtr(_hWnd, nIndex);
}
BOOL PWnd::setSubClassWindow(HWND hWnd)
{
assert(isWindow() == TRUE);
assert(hWnd != _hWnd);
_pfnOldWndProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWL_WNDPROC);
assert(_pfnOldWndProc != PWnd::wndProc);
::SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG)this);
return TRUE;
}
BOOL PWnd::isWindow()
{
return ::IsWindow(_hWnd);
}
BOOL PWnd::showWindow(INT nShow)
{
assert(isWindow() == TRUE);
::ShowWindow(_hWnd, nShow);
return 0;
}
BOOL PWnd::updateWindow()
{
assert(isWindow() == TRUE);
::UpdateWindow(_hWnd);
return 0;
}
BOOL PWnd::destroyWindow()
{
assert(isWindow() == TRUE);
::DestroyWindow(_hWnd);
return 0;
}
BOOL PWnd::createWindowEx(DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName,
DWORD dwStyle, int X, int Y,
int nWidth, int nHeight, HWND hWndParent,
HMENU hMenu, HINSTANCE hInstance)
{
assert(_hWnd == NULL);
CREATESTRUCT cs = {0};
cs.dwExStyle = dwExStyle;
cs.lpszClass = lpClassName;
cs.lpszName = lpWindowName;
cs.style = dwStyle;
cs.x = X;
cs.y = Y;
cs.cx = nWidth;
cs.cy = nHeight;
cs.hwndParent = hWndParent;
cs.hMenu = hMenu;
cs.hInstance = hInstance;
if (preCreateWindow(&cs) == FALSE)
return FALSE;
HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass, cs.lpszName,
cs.style, cs.x, cs.y,
cs.cx, cs.cy, cs.hwndParent,
cs.hMenu, cs.hInstance, cs.lpCreateParams);
//没有调用我们的静态函数
if (_hWnd == NULL) {
if (hWnd == NULL) {
return FALSE;
}
_hWnd = hWnd;
}
//对象实例绑定 以便 自定义的消息处理函数能调用实例
setWindowLongPtr(GWL_USERDATA, (LONG)this);
_pfnOldWndProc = (WNDPROC)getWindowLongPtr(GWL_WNDPROC);
//不是我们所注册的类
if (_pfnOldWndProc != PWnd::wndProc) {
setWindowLongPtr(GWL_WNDPROC, (LONG)PWnd::wndProc);
}
return TRUE;
}
LRESULT PWnd::default(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
//是我们注册的函数
if (_pfnOldWndProc == PWnd::wndProc) {
return defaultProc(nMsg, wParam, lParam);
}
//不是我们注册的函数,交予旧函数默认处理
return _pfnOldWndProc(_hWnd, nMsg, wParam, lParam);
}
BOOL PWnd::preCreateWindow(LPCREATESTRUCT lpCs)
{
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(wcex);
//判断是否要自注册类
if (::GetClassInfoEx(lpCs->hInstance, lpCs->lpszClass, &wcex) == FALSE) {
memset(&wcex, 0, sizeof(wcex));
wcex.cbSize = sizeof(wcex);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.hInstance = lpCs->hInstance;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wcex.lpszClassName = lpCs->lpszClass;
wcex.lpfnWndProc = PWnd::wndProc;
if (!::RegisterClassEx(&wcex))
return FALSE;
}
lpCs->lpCreateParams = this; //wndproc需要
return TRUE;
}
LRESULT PWnd::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
MsgInfo* pInfo = getThisMsgMap();
while(pInfo != NULL){
auto it = pInfo->_map.find(nMsg);
if (it != pInfo->_map.end()) {
return (this->*(it->second))(wParam, lParam);
}
if (pInfo->_getParentMsg == NULL)
break;
pInfo = pInfo->_getParentMsg();
}
return default(nMsg, wParam, lParam);
}
LRESULT PWnd::defaultProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
return ::DefWindowProc(_hWnd, nMsg, wParam, lParam);
}
LRESULT PWnd::onNcCreate(WPARAM wParam, LPARAM lParam)
{
return ::DefWindowProc(_hWnd, WM_NCCREATE, wParam, lParam);
}
LRESULT PWnd::onCreate(WPARAM wParam, LPARAM lParam)
{
return ::DefWindowProc(_hWnd, WM_CREATE, wParam, lParam);
}
LRESULT PWnd::onClose(WPARAM wParam, LPARAM lParam)
{
//默认调用DestroyWindow
return ::DefWindowProc(_hWnd, WM_CLOSE, wParam, lParam);
}
LRESULT PWnd::ondestroy(WPARAM wParam, LPARAM lParam)
{
PostQuitMessage(0);
return 0;
}
LRESULT PWnd::onNcDestroy(WPARAM wParam, LPARAM lParam)
{
return ::DefWindowProc(_hWnd, WM_CLOSE, wParam, lParam);
}
MsgInfo* PWnd::getThisMsgMap()
{
return PWnd::getMsgMap();
}
MsgInfo* PWnd::getMsgMap()
{
typedef std::pair<UINT, LRESULT(PWnd::*)(WPARAM wParam, LPARAM lParam)> Value_Type;
static MsgInfo info = { NULL, //没有信息,以NULL结尾
std::map<UINT, LRESULT(PWnd::*)(WPARAM wParam, LPARAM lParam)>({
ADD_MSG(WM_NCCREATE, PWnd::onNcCreate),
ADD_MSG(WM_CREATE, PWnd::onCreate),
ADD_MSG(WM_CLOSE, PWnd::onClose),
ADD_MSG(WM_DESTROY, PWnd::ondestroy),
ADD_MSG(WM_NCDESTROY, PWnd::onNcDestroy),
})
};
return &info;
}
我们用的时候只需要继承该类,添加更多的消息处理即可。
下面是WinApp类,该类比较简单,在主函数里需要调用几个重要的函数,参考了MFC的函数。
需要保存一个实例App对象,以便访问。
PWinApp.h
#pragma once
#include "PWnd.h"
class PWinApp;
extern PWinApp* g_pCurrentApp; //唯一实例
#define GET_WINAPP() (g_pCurrentApp)
class PWinApp
{
public:
PWinApp();
virtual ~PWinApp();
public:
virtual BOOL initInstance();
virtual int exitInstance();
virtual int run();
protected:
PWnd* _pMainWnd;
};
PWinApp.cpp
#include "PWinApp.h"
PWinApp* g_pCurrentApp = NULL;
PWinApp::PWinApp() : _pMainWnd(NULL)
{
g_pCurrentApp = this;
}
PWinApp::~PWinApp()
{
}
BOOL PWinApp::initInstance()
{
PWnd* pWnd = new PWnd;
pWnd->createWindowEx(0, L"MyClass", L"哈哈", WS_OVERLAPPEDWINDOW, 0, 0, 800, 800, NULL, NULL, GetModuleHandle(NULL));
_pMainWnd = pWnd;
pWnd->showWindow(SW_SHOW);
pWnd->updateWindow();
return TRUE;
}
int PWinApp::exitInstance()
{
delete _pMainWnd;
_pMainWnd = NULL;
return 0;
}
int PWinApp::run()
{
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0)) {
::TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
main函数示范:
#include "Win.h"
#include "PWinApp.h"
HINSTANCE g_hInst; // 当前实例
PWinApp app;
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
GET_WINAPP()->initInstance();
GET_WINAPP()->run();
return GET_WINAPP()->exitInstance();
}
PWnd示例
class PMainWnd : public PWnd
{
DECLARE_MSGMAP()
public:
LRESULT onPaint(WPARAM wParam, LPARAM lParam)
{
return ::DefWindowProc(_hWnd, WM_CLOSE, wParam, lParam);
}
LRESULT onCommand(WPARAM wParam, LPARAM lParam)
{
return ::DefWindowProc(_hWnd, WM_CLOSE, wParam, lParam);
}
};
IMPLEMENT_BEGIN_MSGMAP(PMainWnd, PWnd)
ADD_MSG(WM_PAINT, onPaint),
ADD_MSG(WM_COMMAND, onCommand)
IMPLEMENT_END_MSGMAP()