QWindow.h
#pragma once #define QWIN_DECLARE_MESSAGE_MAP() BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); #define QWIN_BEGIN_MESSAGE_MAP(cls) BOOL cls::ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ #define QWIN_END_MESSAGE_MAP() return FALSE;} #define QWIN_MESSAGE_MAP(id,fun) if(uMsg==id){return fun(hWnd,uMsg,wParam,lParam);} #define QWIN_CHAIN_MESSAGE_MAP(id,cls) if(uMsg==id){return cls::ProcessWindowMessage(hWnd,uMsg,wParam,lParam);} #define QWIN_DECLARE_EMPTY_MSG_MAP() BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){return FALSE;} #define QWIN_COMMAND_CODE_MAP(code,fun) if(uMsg == WM_COMMAND && code == HIWORD(wParam)){return fun(hWnd,uMsg,wParam,lParam);} #define QWIN_COMMAND_ID_MAP(id,fun) if(uMsg == WM_COMMAND && id == LOWORD(wParam)){return fun(hWnd,uMsg,wParam,lParam);} #define QWIN_COMMAND_MAP(id,code,fun) if(uMsg == WM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)){return fun(hWnd,uMsg,wParam,lParam);} #define QWIN_DECLARE_WND_CLASS(WndClassName) \ public:\ static WNDCLASSEX& GetWndClassInfo() \ { \ static WNDCLASSEX wc = \ { \ sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, (WNDPROC)CQWindow::StartWindowProc, \ 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL \ }; \ return wc; \ } #define QWIN_DECLARE_WND_SUPER_CLASS(cls,ClassName,WndClassName) \ public: \ WNDPROC cls##ComponentProc; \ public: \ static WNDCLASSEX& GetWndClassInfoEx(cls* c) \ { \ static WNDCLASSEX wc={0}; \ ::GetClassInfoEx(_WinModule.GetInstance(),WndClassName,&wc); \ c->cls##ComponentProc=wc.lpfnWndProc; \ wc.lpfnWndProc = (WNDPROC)CQWindow::StartWindowProc; \ wc.lpszClassName =ClassName; \ wc.cbSize=sizeof(WNDCLASSEX); \ return wc; \ } #define QWIN_REFLECTION_WND_SUPER_CLASS(cls) else{::CallWindowProc(cls##ComponentProc,hWnd,uMsg,wParam,lParam);return FALSE;} #pragma pack(push,1) struct _WndProcThunk { DWORD m_mov; // mov dword ptr [esp+0x4], pThis (esp+0x4 is hWnd) DWORD m_this; BYTE m_jmp; // jmp WndProc DWORD m_relproc; // relative jmp }; #pragma pack(pop) class WndProcThunk { public: _WndProcThunk thunk; void Init(WNDPROC proc, void* pThis) { thunk.m_mov = 0x042444C7; //C7 44 24 04 thunk.m_this = (DWORD)pThis; thunk.m_jmp = 0xe9; thunk.m_relproc = (int)proc - ((int)this+sizeof(_WndProcThunk)); ::FlushInstructionCache(GetCurrentProcess(), &thunk, sizeof(thunk)); } WNDPROC GetWndProc() { return (WNDPROC)&(thunk); } }; struct IMessageMap { virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)=0; }; class CQWindow; class CQWinModule; extern CQWinModule _WinModule; class CQWinModule { private: HINSTANCE m_hInst; CQWindow *m_pWindow; DWORD m_dwThreadID; public: CQWinModule(){m_dwThreadID=::GetCurrentThreadId();} ~CQWinModule(){Term();} void Init(HINSTANCE hInstance){m_hInst=hInstance;} void Term(){m_hInst=NULL;} void SetInstance(HINSTANCE hInstance){Init(hInstance);} void AddCreateWndData(CQWindow* pWindow){m_pWindow=pWindow;} HINSTANCE GetInstance(){return m_hInst;} CQWindow* GetCurrentWindow(){return m_pWindow;} }; class CQWindow:public IMessageMap { public: CQWindow(void); ~CQWindow(void); public: static LRESULT CALLBACK StandardWindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { CQWindow* pThis=(CQWindow*)hWnd; if(uMsg==WM_NCDESTROY) ::PostQuitMessage(0); if(!pThis->ProcessWindowMessage(pThis->m_hWnd,uMsg,wParam,lParam)) return ::DefWindowProc(pThis->m_hWnd,uMsg,wParam,lParam); else return 0; } static LRESULT CALLBACK StartWindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { CQWindow* pThis=_WinModule.GetCurrentWindow(); pThis->m_hWnd=hWnd; pThis->thunk.Init(StandardWindowProc,pThis); WNDPROC proc=pThis->thunk.GetWndProc(); ::SetWindowLong(hWnd,GWL_WNDPROC,(LONG)proc); return proc(hWnd,uMsg,wParam,lParam); } public: BOOL UpdateWindow(void); BOOL ShowWindow(int cCmd); virtual LRESULT SendMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); virtual LRESULT PostMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); virtual BOOL Create(LPCTSTR szClassName, LPCTSTR szTitle, HINSTANCE hInstance, HWND hWndParent = 0, DWORD dwStyle = WS_OVERLAPPEDWINDOW, DWORD dwExStyle = 0, HMENU hMenu = 0, int x = CW_USEDEFAULT, int y = CW_USEDEFAULT, int nWidth = CW_USEDEFAULT, int nHeight = CW_USEDEFAULT); virtual BOOL ProcessWindowMessage(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); public: HWND m_hWnd; WndProcThunk thunk; }; template<class TC>class CQWindowImpl :public CQWindow { public: WNDPROC tx; public: CQWindowImpl(void){} public: ~CQWindowImpl(void){} public: int RegCls() { tx=CQWindow::StartWindowProc; m_cls=TC::GetWndClassInfo(); PerRegistercls(&m_cls); return RegisterClassEx(&m_cls); } int RegSuperCls() { m_cls=TC::GetWndClassInfoEx((TC*)this); PerRegistercls(&m_cls); return RegisterClassEx(&m_cls); } virtual int PerRegistercls(WNDCLASSEX* cls){return 0;} public: WNDCLASSEX m_cls; WNDPROC m_OldlpfnWndProc; };
QWindow.cpp
#include "StdAfx.h" #include "QWindow.h" CQWinModule _WinModule; CQWindow::CQWindow(void) { } CQWindow::~CQWindow(void) { } BOOL CQWindow::Create(LPCTSTR szClassName, LPCTSTR szTitle, HINSTANCE hInstance, HWND hWndParent /* = 0 */, DWORD dwStyle /* = WS_OVERLAPPEDWINDOW */, DWORD dwExStyle /* = 0 */, HMENU hMenu /* = 0 */, int x /* = CW_USEDEFAULT */, int y /* = CW_USEDEFAULT */, int nWidth /* = CW_USEDEFAULT */, int nHeight /* = CW_USEDEFAULT */) { _WinModule.AddCreateWndData(this); m_hWnd =::CreateWindowEx(dwExStyle, szClassName, szTitle, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance,NULL); return m_hWnd != NULL; } BOOL CQWindow::UpdateWindow(void) { return ::UpdateWindow(m_hWnd); } BOOL CQWindow::ShowWindow(int cCmd) { return ::ShowWindow(m_hWnd,cCmd); } LRESULT CQWindow::SendMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) { return ::SendMessage(m_hWnd,uMsg,wParam,lParam); } LRESULT CQWindow::PostMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) { return ::PostMessage(m_hWnd,uMsg,wParam,lParam); } BOOL CQWindow::ProcessWindowMessage(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { return FALSE; }