首先建一个基于MFC对话框的工程.在dlg类中插入如下代码:
class CTestTimer01Dlg : public CDialog
{
//...........
private:
BYTE m_codeCmd[10] ; //代码命令
//mov 地址
//jmp 地址
void _InitCodeCmd(DWORD dwpThis, DWORD dwProcPtr);
DWORD _GetMessageProcPtr();
protected:
// Construction
int m_iTestShow;
//调用规则用默认的,即__thiscall
//用其它调用规则不行(可能__fastcall可以,但尽量不用)
virtual VOID _OnTimerSink(HWND hWnd, DWORD dwMsg , WPARAM wPa, LPARAM lPa);
//...........
}
// CTestTimer01Dlg message handlers
VOID CTestTimer01Dlg::_OnTimerSink(HWND hWnd, DWORD dwMsg , WPARAM wPa, LPARAM lPa)
{
++m_iTestShow;
InvalidateRect(NULL);
}
void CTestTimer01Dlg::_InitCodeCmd(DWORD dwpThis, DWORD dwProcPtr)
{
/*
这段机器码相当于如下汇编
--------------------------- -------------------------------------
B9 ?? ?? ?? ?? mov ecx, dwpThis ; Load ecx with this pointer
E9 ?? ?? ?? ?? jmp dwProcPtr ; Jump to target message handler
*/
m_codeCmd[0] = 0xB9; //mov命令,负责传递this指针
//成员函数一般是
//使用ECX传递this指针,即__thiscall调用,成员函数默认都是
//__fastcall调用:编译器会尽量 使用ECX传递参数
//使用栈传递this指针,即__stdcall或__cdecl调用
//_stdcall是被调函数自己恢复调用栈
//__cdecl是调用者恢复调用栈.可以用来实现不定长参数的函数
m_codeCmd[5] = 0xE9; //jmp命令
*((DWORD *) &m_codeCmd[1]) = (DWORD) dwpThis;
//跳转偏移量
DWORD dwDistance = (DWORD) dwProcPtr - (DWORD) &m_codeCmd[0] - 10;
*((DWORD *) &m_codeCmd[6]) = dwDistance;
}
DWORD CTestTimer01Dlg::_GetMessageProcPtr()
{
/*
typedef VOID (CTestTimer01Dlg::*pmf)(HWND hWnd, DWORD dwMsg , WPARAM wPa, LPARAM lPa);
pmf p = &CTestTimer01Dlg::_OnTimerSink;
DWORD off = 0;
_asm
{
mov eax, p
mov [off], eax
}
return off;
//vc6中无法通过编译
DWORD dwProcAddr = 0;
__asm
{
mov eax, offset CTestTimer01Dlg::_OnTimerSink
mov dword ptr [dwProcAddr], eax
}
return dwProcAddr;*/
//得到定时器回调的指针
//编译器不容许从CTestTimer01Dlg::_OnTimerSink强制转化到DWORD
//为了实现兼容,用union_cast实行转化
return union_cast<DWORD> (&CTestTimer01Dlg::_OnTimerSink);
}
BOOL CTestTimer01Dlg::OnInitDialog()
{
CDialog::OnInitDialog();
_InitCodeCmd((DWORD)this, _GetMessageProcPtr());
::SetTimer(NULL, 1, 500, (TIMERPROC)(void *)m_codeCmd);
//下面代码省略
}
这里用到了类型转化函数,union_cast,定义如下:
template <class ToType, class FromType>
ToType union_cast(FromType f)
{
union
{
FromType _f;
ToType _t;
} ut;
memset(&ut, 0, sizeof(ut));
ut._f = f;
return ut._t;
};
ps:WTL正是靠这种手法,实现了成员函数处理消息