做为一个C++的oopfans,以前经常对win32的回调函数不能封装成类的成员函数而
头痛,以前的经常做法是把win32的回调函数做为全局函数或者是类的static成员函数,
不过static成员函数是不能访问类的数据成员的,其原因在于类成员函数都有一个隐藏
的this指针,这个指针一般是通过ECX寄存器传递到类成员函数内部(thiscall调用),或
者通过栈传递到成员函数内部(stdcall调用),本类通过thunk技术实现调用时修改ECX
或栈中的参数,以达到类成员函数可以做为回调函数的应用,目前作者通过这个类实现
了,以下回调函数的封装(完全封装成类的普通成员函数)
CreateThread的回调函数
DWORD WINAPI ThreadProc(LPVOIDlpParameter );
SetTimer的回调函数
VOID CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT_PTR idEvent, DWORD dwTime);
SetWindowsHookEx -> WH_JOURNALRECORD类型钩子的回调函数
LRESULT CALLBACK JournalRecordProc(int code,WPARAM wParam,LPARAM lParam);
欲索取demo源码,请致电作者,
MSN:ooopfans@mns.com
oofpans群:34064264
-------------------------------------------------------------------------------------------------------------
/*-======================- Copyright (c) 2006 -======================-
程序作者:
张鲁夺(zhangluduo) : 为所有爱我的人和我爱的人努力!
联系方式:
oopfans@msn.com
修改时间:
2007-01-05
功能描述:
利用thunk技术,以便把win32回调函数封装成类成员函数,本程序中所用到的
机器码是对应于x86平台的.
本类是thunk技术实现的,可以利用这个类把回调函数封装成类成员函数.使
用这个类的实例时,需要确保这个类的实例作用域为全局或其他类中的数据
成员。
-----------------------------------------------------------------
正确调用如下(一):
class T
{
private:
ZThunk m_thunk; // 将ZThunk声明为数据成员
public:
void MemberFunction()
{
m_thunk.CallBack(parameters ... ); // ok!
}
}
-----------------------------------------------------------------
正确调用如下(二):
ZThunk m_thunk; // 将ZThunk声明全局对像
class T
{
public:
void MemberFunction()
{
m_thunk.CallBack(parameters ... ); // ok!
}
}
-----------------------------------------------------------------
错误调用如下:
class T
{
public:
void MemberFunction()
{
ZThunk m_thunk; // 将ZThunk声明为局部对像,
// 不会有语法错误,但是下面的调用会失败!
m_thunk.CallBack(parameters ... ); // error!
}
}
-----------------------------------------------------------------
版权声明:
许可任何单位,个人随意使用,拷贝,修改,散布及出售这份代码,但是必须保
留此版权信息,以慰藉作者辛勤的劳动,及表明此代码的来源,如若此份代码
有任何BUG,请通知作者,以便弥补作者由于水平所限而导致的一些错误和不
足,谢谢!
此份代码是作者跟据一位网友[JERKII.SHANG (JERKII@HOTMAIL.COM)]的一
篇文章[一种实现Win32窗口过程函数(Window Procedure)的新方法--
基于Thunk实现的类成员消息处理函数]修改而成,在此对原作者开源的精神
致敬!
-======================- Copyright (c) 2006 -======================-*/
#ifndef _ZTHUNK
#define _ZTHUNK
class ZThunk
{
private:
unsigned char m_ThiscallCode[10];
unsigned char m_StdcallCode[16];
public:
enum CALLINGCONVENTIONS
{
STDCALL = 1,
THISCALL= 2
};
public:
template <class T>
void* CallBack(void* pThis,T MemberAddr,CALLINGCONVENTIONS WhichCalling=STDCALL)
{
// these codes only use in stdcall
if(WhichCalling==STDCALL)
{
// Encoded machine instruction Equivalent assembly languate notation
// --------------------------- -------------------------------------
// FF 34 24 push dword ptr [esp] ; Save (or duplicate) ; the Return Addr into stack
// C7 44 24 04 ?? ?? ?? ?? mov dword ptr [esp+4], pThis ; Overwite the old ; Return Addr with 'this pointer'
// E9 ?? ?? ?? ?? jmp target addr ; Jump to target message handler
char Buf[33]={0};
sprintf(Buf,"%d",MemberAddr);
unsigned long JmpAddr = (unsigned long) atol(Buf) - (unsigned long) &m_StdcallCode[0] - 16;
m_StdcallCode[11] = 0xE9;
*((unsigned long *) &m_StdcallCode[ 0]) = 0x002434FF;
*((unsigned long *) &m_StdcallCode[ 3]) = 0x042444C7;
*((unsigned long *) &m_StdcallCode[ 7]) = (unsigned long) pThis;
*((unsigned long *) &m_StdcallCode[12]) = JmpAddr;
return (void*)m_StdcallCode;
}
// these codes only use in thiscall
else if(WhichCalling==THISCALL)
{
// Encoded machine instruction Equivalent assembly languate notation
// --------------------------- -------------------------------------
// B9 ?? ?? ?? ?? mov ecx, pThis ; Load ecx with this pointer
// E9 ?? ?? ?? ?? jmp target addr ; Jump to target message handler
char Buf[33]={0};
sprintf(Buf,"%d",MemberAddr);
unsigned long JmpAddr = (unsigned long) atol(Buf) - (unsigned long) &m_ThiscallCode[0] - 10;
m_ThiscallCode[0] = 0xB9;
m_ThiscallCode[5] = 0xE9;
*((unsigned long *) &m_ThiscallCode[1]) = (unsigned long) pThis;
*((unsigned long *) &m_ThiscallCode[6]) = JmpAddr;
return (void*)m_ThiscallCode;
}return 0;
}
};
#endif
/******************************
调用示例
******************************/
m_hHook=SetWindowsHookEx(WH_JOURNALRECORD,
(HOOKPROC)m_thunk.CallBack(this,&ZPassword::JournalRecordProc,ZThunk::THISCALL),
/*AfxGetInstanceHandle()*/GetModuleHandle(SelfPath),0);