zhangluduo

I' a oop fans

通过thunk技术实现win32回调函数的完全封装

做为一个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);

posted on 2007-01-28 21:19 张鲁夺 阅读(976) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航:   博客园   博客园最新博文   博问   管理


<2026年6月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

导航

统计

常用链接

留言簿

文章档案

搜索

最新评论