summaryrefslogtreecommitdiffstats
path: root/Tools/BiomeVisualiser/WndProcThunk.h
blob: da995eb5f88e091eee5eac7aeed5fd9949d62584 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143

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