// WndProcThunk.h // Interfaces to the CWndProcThunk class responsible for WNDPROC class-thunking // For details, see http://www.hackcraft.net/cpp/windowsThunk/thiscall/ // Also available is a CDlgProcThunk class doing the same work for DIALOGPROC // MD: Made NX-compat by allocating the code structure using VirtualAlloc(..., PAGE_EXECUTE_READWRITE) // fwd: template class CWndProcThunk; #ifndef WNDPROCTHUNK_H_INCLUDED #define WNDPROCTHUNK_H_INCLUDED template inline To union_cast(From fr) throw() { union { From f; To t; } uc; uc.f = fr; return uc.t; } #pragma warning(push) #pragma warning(disable : 4355) #if defined(_M_IX86) #pragma pack(push,1) template class CWndProcThunk { typedef ::LRESULT (W::* WndProc)(::HWND, ::UINT, ::WPARAM, ::LPARAM); typedef CWndProcThunk ThisClass; struct SCode { BYTE m_mov; // mov ECX, m_this W * m_this; // BYTE m_jmp; // jmp m_relproc ptrdiff_t m_relproc; // relative jmp }; SCode * Code; public: ThisClass(WndProc proc, W * obj) { Code = (SCode *)VirtualAlloc(NULL, sizeof(SCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE); Code->m_mov = 0xB9, Code->m_this = obj, Code->m_jmp = 0xE9, Code->m_relproc = union_cast(proc) - reinterpret_cast(Code) - sizeof(*Code); ::FlushInstructionCache(::GetCurrentProcess(), Code, sizeof(*Code)); } virtual ~CWndProcThunk() { VirtualFree(Code, sizeof(*Code), MEM_RELEASE); Code = NULL; } operator ::WNDPROC() const {return reinterpret_cast<::WNDPROC>(Code); } operator ::LONG_PTR() const {return reinterpret_cast<::LONG_PTR>(Code); } } ; template class CDlgProcThunk { typedef ::BOOL (W::* DlgProc)(::HWND, ::UINT, ::WPARAM, ::LPARAM); typedef CDlgProcThunk ThisClass; struct SCode { BYTE m_mov; // mov ECX, m_this W * m_this; // BYTE m_jmp; // jmp m_relproc ptrdiff_t m_relproc; // relative jmp }; SCode * Code; public: CDlgProcThunk(DlgProc proc, W * obj) { Code = (SCode *)VirtualAlloc(NULL, sizeof(SCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE); Code->m_mov = 0xB9, Code->m_this = obj, Code->m_jmp = 0xE9, Code->m_relproc = union_cast(proc) - reinterpret_cast(Code) - sizeof(*Code); ::FlushInstructionCache(::GetCurrentProcess(), Code, sizeof(*Code)); } virtual ~CDlgProcThunk() { VirtualFree(Code, sizeof(*Code), MEM_RELEASE); Code = NULL; } operator ::DLGPROC() const {return reinterpret_cast<::DLGPROC>(Code); } operator ::LONG_PTR() const {return reinterpret_cast<::LONG_PTR>(Code); } } ; #pragma pack(pop) #else // _M_IX86 #error Only X86 supported #endif #endif // WNDPROCTHUNK_H_INCLUDED