144 lines
2.8 KiB
C
144 lines
2.8 KiB
C
|
|
||
|
// 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 W> class CWndProcThunk;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#ifndef WNDPROCTHUNK_H_INCLUDED
|
||
|
#define WNDPROCTHUNK_H_INCLUDED
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
template<typename To, typename From> 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 W> 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<char *>(proc) - reinterpret_cast<char *>(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 W> 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<char *>(proc) - reinterpret_cast<char *>(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
|
||
|
|
||
|
|
||
|
|
||
|
|