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;
}