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