
// 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




