今天在网上头一次见到thunk,到底有什么用呢?主要是可以让程序使用类成员函数来代替静态的回调函数。那么什么时候需要这种代替呢?一般情况下是没有必要的。使用静态的成员函数就足够了。可是有一种情况,静态函数是不能重载和是虚函数的,因此限制继承的方便性。这时就可以使用thunk技术了。我没有去实践一下。具体的应用还要继续研究。
以下转自http://www.vckbase.com/bbs/prime/viewprime.asp?id=694
在网上看到很多 Thunk 的介绍,但是很少有几个实际的 Demo,这里用一个实例说明Thunk的用法。
以下是所使用的 Thunk。(CAuxStdThunk, 从网上找的,不知道作者,如有冒犯还请原谅。)
// AUX Thunk, 全局函数 -> 类成员函数
#pragma pack(push, 1)
template <class T>
class CAuxStdThunk
{
BYTE m_mov; // mov eax, %pThis
DWORD m_this; //
DWORD m_xchg_push; // xchg eax, [esp] : push eax
BYTE m_jmp; // jmp func
DWORD m_relproc; // relative jmp
public:
typedef void (_stdcall T::*TMFP)();
void Init(TMFP method, const T *pThis)
{
union {
DWORD func;
TMFP method;
} addr;
addr.method = method;
m_jmp = 0xE9;
m_mov = 0xB8;
m_this = (DWORD)(PVOID) pThis;
m_xchg_push = 0x50240487;
m_relproc = addr.func - (DWORD)(PVOID)(this + 1);
FlushInstructionCache(GetCurrentProcess(), this, sizeof(*this));
}
FARPROC GetThunk() const { return (FARPROC) this; }
};
#pragma pack(pop)
//
这里是 Timer,它通过 Thunk 定期向自己的所有者调用 OnTimer。
#ifndef Timer_H
#define Timer_H
#include <Windows.h>
#include "Thunk.h"
const DWORD INVALID_EVENT_ID = (DWORD)-1;
// CTimer need the Windows Message Loop
template <class Owner>
class CTimer
{
CAuxStdThunk<CTimer<Owner> > m_thunk; // Thunk 要放在类的最前面。
public:
CTimer(Owner *pOwner = 0)
: m_pOwner(pOwner),
m_nIDEvent(INVALID_EVENT_ID)
{
m_thunk.Init((CAuxStdThunk<CTimer<Owner> >::TMFP) (CTimer<Owner>::TimerHandler), this);
}
~CTimer()
{
Stop();
}
void SetOwner(Owner *pOwner) { m_pOwner = pOwner; }
void Stop()
{
if (m_nIDEvent != INVALID_EVENT_ID) {
KillTimer(NULL, m_nIDEvent);
}
}
BOOL Start(UINT_PTR nIDEvent, UINT nElapse)
{
Stop();
m_nIDEvent = SetTimer(NULL, nIDEvent, nElapse, (TIMERPROC) m_thunk.GetThunk());
return (m_nIDEvent != INVALID_EVENT_ID);
}
void _stdcall TimerHandler(HWND, UINT nMessage, UINT nIDEvent, DWORD dwTime)
{
if (m_pOwner) {
m_pOwner->OnTimer(nIDEvent, dwTime);
}
}
private:
Owner *m_pOwner;
UINT_PTR m_nIDEvent;
};
#endif
这里是使用 Timer 的方法。
#include <conio.h>
#include <iostream.h>
#include "Timer.h"
class CClock
{
public:
CClock()
{
m_timer1.SetOwner(this);
m_timer1.Start(0, 500);
m_timer2.SetOwner(this);
m_timer2.Start(0, 500);
}
void OnTimer(UINT nIDEvent, DWORD dwTime)
{
cout << "OnTimer " << nIDEvent << " " << dwTime << endl;
}
private:
CTimer<CClock> m_timer1;
CTimer<CClock> m_timer2;
};
int main()
{
CClock clock;
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
if (kbhit()) {
break;
}
DispatchMessage(&msg);
}
return 0;
}