利用Thunk让C 成员函数变回调函数计算机等级考试

文章作者 100test 发表时间 2009:07:09 21:49:59
来源 100Test.Com百考试题网


  Windows API经常需要回调函数,而在C 开发中面向对象当行其道,若能让C 类的成员函数成为回调函数,简直就是大善!但是C 成员函数都隐含了一个this指针用于指向当前的对象。要实现回调确实不容易。
  我大约一年前就接触到Thunk技术,甚至也看过利用Thunk实现将成员函数变成回调函数的例子。但是我实在没了解过C 汇编后的样子,很容易钻了牛角尖,看都看不懂,直接用他们的程序又不敢,毕竟出错后不好处理。前端时间偶尔想起Thunk技术,对未懂技术老这样悬着很可能影响自己的程序员生涯的,于是决心闭关参悟(没办法,资质差啊),终于弄明白了。那种感觉啊,就像诚信礼佛的人突然见到如来一样,或者换了贴近自己的比喻:就像千年色鬼见到美女一样的兴奋。 我忍不住的模仿小说中的修真人士突悟大道后的感叹:原来如此!
  下面的分享一下我的收获,基本上是出入门径的写给初学者的,大侠千万要止步,小弟皮薄!
  稍微研究了一下C 汇编后的代码,一般调用C 的成员函数之前,都是使用ECX寄存器保存对象的指针,好在C 成员函数的调用约定__thiscall的参数压栈顺序和堆栈平衡的维护都是和回调函数的调用约定__stdcall一样,所以只需要构造汇编将对象指针保存在ECX寄存器后JMP到成员函数的执行地址就可以了。先写个C 结构拼凑这两条汇编码:
  #pragma pack( push, 1 )
  struct  MemFunToStdCallThunk
  {
  BYTE       m_mov.
  DWORD     m_this.
  BYTE       m_jmp.
  DWORD     m_relproc.
  BOOL  Init( DWORD_PTR proc, void* pThis )
  {
  m_mov = 0xB9.
  m_this = PtrToUlong(pThis).
  m_jmp = 0xe9.
  m_relproc = DWORD((INT_PTR)proc - ((INT_PTR)this sizeof(MemFunToStdCallThunk))).
  ::FlushInstructionCache( ::GetCurrentProcess(), this, sizeof(MemFunToStdCallThunk) ).
  return TRUE.
  }
  void* GetCodeAddress()
  {
  return this.
  }
  }.
  #pragma  pack( pop )
  这个结构相当于两条汇编语句:
  mov ecx, pThis
  jmp [偏移地址]
  使用:
  class  CTestClass
  {
  private:
  int  m_nBase.
  MemFunToStdCallThunk  m_thunk.
  void  memFun( int m, int n )
  {
  int  nSun = m_nBase m n.
  CString str.
  str.Format( _T("%d"), nSun ).
  AtlMessageBox( NULL, _U_STRINGorID( str ) ).
  }
  public:
  CTestClass()
  {
  m_nBase  = 10.
  }
  void  Test()
  {
  //UnionCastType:利用联合将函数指针转换成DWORD_PTR
  m_thunk.Init( UnionCastType<.DWORD_PTR>.(&.CTestClass::memFun), this ).
  StdCallFun fun = (StdCallFun)m_thunk.GetCodeAddress().
  ATLASSERT( fun != NULL ).
  fun( 1, 3 ).
  }
  }.
  MemFunToStdCallThunk的Init方法接受成员函数指针和对象指针后就构造成2条汇编码,当调用fun(1,3)时,
  首先将参数3和1压入堆栈,之后跳转到m_thunk处,也就是那构造的2条汇编码处,将对象指针保存到ECX寄存器,之后跳转到指定的成员函数处执行。一切OK了。
  UnionCastType方法的代码如下:
  template<. typename TDst, typename TSrc >.
  TDst  UnionCastType( TSrc src )
  {
  union
  {
  TDst  uDst.
  TSrc  uSrc.
  }uMedia.
  uMedia.uSrc  =  src.
  return uMedia.uDst.
  }

  编辑特别推荐:

  全国计算机等级考试(等考)指定教材

  全国计算机等级考试学习视频

  全国计算机等级考试网上辅导招生

  全国计算机等级考试时间及科目预告

  百考试题教育全国计算机等级考试在线测试平台

  全国计算机等级考试资料下载

  全国计算机等级考试论坛



相关文章


C 内存泄漏检测拾遗计算机等级考试
利用Thunk让C 成员函数变回调函数计算机等级考试
C 实现不可被拷贝的类计算机等级考试
探讨C 实现一个不可被继承的类计算机等级考试
澳大利亚华人论坛
考好网
日本华人论坛
华人移民留学论坛
英国华人论坛