#include "stdafx.h"
template<typename ObjectType> class Delegate { // Type Definitions public: typedef LRESULT (ObjectType::*CallType)(HWND, UINT, WPARAM, LPARAM);
// Constructor public: Delegate(ObjectType* pObject, CallType pCallee) : m_pObject(pObject), m_pCallee(pCallee) { }
// Destrcutor public: ~Delegate() { }
// Thunk Structure public: /* Adjust pack size */ #pragma pack(push,1) struct Thunk { /* push ebp */ BYTE m_pushebp; /* mov ebp, esp */ BYTE m_movebp; BYTE m_esp;
/* mov eax, dword ptr [ebp + 8] */ BYTE m_moveax1; BYTE m_ebpplus1; BYTE m_offset1; /* push eax */ BYTE m_pusheax1;
/* mov eax, dword ptr [ebp + 12] */ BYTE m_moveax2; BYTE m_ebpplus2; BYTE m_offset2; /* push eax */ BYTE m_pusheax2;
/* mov eax, dword ptr [ebp + 16] */ BYTE m_moveax3; BYTE m_ebpplus3; BYTE m_offset3; /* push eax */ BYTE m_pusheax3;
/* mov eax, dword ptr [ebp + 20] */ BYTE m_moveax4; BYTE m_ebpplus4; BYTE m_offset4; /* push eax */ BYTE m_pusheax4;
/* mov eax, this*/ BYTE m_moveax5; void* m_this;
/* push eax */ BYTE m_pusheax5;
/* mov eax, helper*/ BYTE m_moveax6; void* m_helper;
/* call eax */ BYTE m_call; BYTE m_calleax;
/* pop ebp */ BYTE m_popebp; /* ret 10h */ BYTE m_ret; DWORD m_10h; }; /* Reset pack size */ #pragma pack(pop)
// Properties protected: Thunk m_Thunk; ObjectType* m_pObject; CallType m_pCallee;
// Methods public: operator WNDPROC(void) { void* pf;
__asm { mov eax, Delegate<ObjectType>::Helper mov pf, eax }
/* push ebp */ m_Thunk.m_pushebp = 0x55; /* mov ebp, esp */ m_Thunk.m_movebp = 0x8B; m_Thunk.m_esp = 0xEC; /* mov eax dword ptr [ebp + 20] */ m_Thunk.m_moveax1 = 0x8B; m_Thunk.m_ebpplus1 = 0x45; m_Thunk.m_offset1 = 20;
/* push eax */ m_Thunk.m_pusheax1 = 0x50;
/* mov eax dword ptr [ebp + 16] */ m_Thunk.m_moveax2 = 0x8B; m_Thunk.m_ebpplus2 = 0x45; m_Thunk.m_offset2 = 16;
/* push eax */ m_Thunk.m_pusheax2 = 0x50;
/* mov eax dword ptr [ebp + 12] */ m_Thunk.m_moveax3 = 0x8B; m_Thunk.m_ebpplus3 = 0x45; m_Thunk.m_offset3 = 12;
/* push eax */ m_Thunk.m_pusheax3 = 0x50;
/* mov eax dword ptr [ebp + 8] */ m_Thunk.m_moveax4 = 0x8B; m_Thunk.m_ebpplus4 = 0x45; m_Thunk.m_offset4 = 8;
/* push eax */ m_Thunk.m_pusheax4 = 0x50;
/* mov eax, this */ m_Thunk.m_moveax5 = 0xB8; m_Thunk.m_this = this;
/* push eax */ m_Thunk.m_pusheax5 = 0x50;
/* mov eax, Delegate::Helper */ m_Thunk.m_moveax6 = 0xB8; m_Thunk.m_helper = pf; /*call eax*/ m_Thunk.m_call = 0xFF; m_Thunk.m_calleax = 0xD0;
/* pop ebp */ m_Thunk.m_popebp = 0x5D; /* ret 10h */ m_Thunk.m_ret = 0xC2; m_Thunk.m_10h = 0x10;
return (LRESULT(CALLBACK*)(HWND, UINT, WPARAM, LPARAM))&m_Thunk; }
HRESULT CALLBACK Helper(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) { return (m_pObject->*m_pCallee)(hWnd, uMessage, wParam, lParam); } };
class CWindow { public: virtual LRESULT WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) { if(uMessage==WM_DESTROY) { ::PostQuitMessage(0); }
return ::DefWindowProc(hWnd, uMessage, wParam, lParam); } };
class CMyWindow : public CWindow { public: virtual LRESULT WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) { if(uMessage==WM_LBUTTONDOWN) { ::MessageBox(hWnd, "ok", "ok", MB_OK); }
return CWindow::WndProc(hWnd, uMessage, wParam, lParam); } };
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { CMyWindow theWindow;
CWindow* pWindow = &theWindow;
Delegate<CWindow> theDelegate(pWindow, CWindow::WndProc);
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX); wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH); wcex.hCursor = ::LoadCursor(NULL, IDC_ARROW); wcex.hIcon = ::LoadIcon(NULL, IDI_APPLICATION); wcex.hIconSm = wcex.hIcon; wcex.hInstance = ::GetModuleHandle(NULL);
// Replaced with a member function delegation wcex.lpfnWndProc = theDelegate;
wcex.lpszClassName = "TestClass"; wcex.lpszMenuName = NULL; wcex.style = CS_VREDRAW | CS_HREDRAW;
::RegisterClassEx(&wcex);
HWND hWnd = ::CreateWindow("TestClass", "TestWindow", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 320, 240, NULL, NULL, ::GetModuleHandle(NULL), NULL);
::UpdateWindow(hWnd);
MSG msg;
while(::GetMessage(&msg, NULL, 0, 0)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); }
::ExitProcess(0); }

|