Introduction
A number of times we need to define static functions in a class to pass them to API Calls like Window Proc, Thread Proc, etc.
Typically we define a static/global function and pass this
as one parameter and recast that parameter into object again.
In these cases, we can define a thunk that generates the Static Procedure at
runtime, and pass the generated Proc to the API Function.
All we need to set this
correctly at runtime and jump to required address.
Code listing
The following class CThunk
does the same thing.
#if defined(_M_IX86)
#pragma pack(push,1)
template <typename F1,typename F2, typename T1>
class CThunk
{
public:
struct _ProcThunk
{
BYTE m_movcx;
DWORD m_pThis;
BYTE m_jmp;
DWORD m_relproc;
};
_ProcThunk thunk;
void Init(F2 proc, T1 * pClass)
{
#ifdef _DEBUG
long pthis;
_asm { mov dword ptr [pthis],ecx };
assert(pthis == (long) this);
#endif
thunk.m_movcx = 0xB9;
thunk.m_pThis= (DWORD)pClass;
thunk.m_jmp = 0xe9;
thunk.m_relproc =
*((int *) &proc) - ((int)this+sizeof(_ProcThunk));
FlushInstructionCache(GetCurrentProcess(),
&thunk, sizeof(thunk));
}
F1 GetStaticProc()
{
return reinterpret_cast<F1> (&thunk);
}
};
#pragma pack(pop)
#else
#error Only X86 supported
#endif
Usage
The following code shows the usage of CThunk
class for threads Proc.
This class can be used in other places where Static procs are required. In this
code CThunk
class is used to create a thunk for the _beginthread
API Call.
typedef void( __cdecl *THREADPROC )( void * );
class CThreadTest
{
protected:
typedef LRESULT (CThreadTest::*FTN)
(LPVOID lpThreadParameter);
CThunk<THREADPROC,FTN,CThreadTest> m_th;
HANDLE m_hThread;
public:
int m_y;
CThreadTest()
{
m_th.Init(CThreadTest::ThreadFunction,this);
}
LRESULT ThreadFunction(LPVOID lpThreadParameter)
{
int ntime =(int) lpThreadParameter;
printf("%d",m_y);
Sleep(ntime);
return 0;
}
BOOL Create (int nSleeptime)
{
THREADPROC tp =m_th.GetStaticProc();
m_hThread = (HANDLE)_beginthread(tp, 0,
(LPVOID)nSleeptime);
return TRUE;
}
void WaitForThread()
{
WaitForSingleObject(m_hThread,INFINITE);
}
};
int main(int argc, char* argv[])
{
CThreadTest t1;
t1.m_y=100;
t1.Create(1000);
t1.WaitForThread();
return 0;
}