简单的WIN32窗口封装

封装窗口对象。
(注意。有些命名我是直接复制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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值