WEB开发网
开发学院软件开发VC Thunk技术的一个改进 阅读

Thunk技术的一个改进

 2010-08-15 20:46:25 来源:WEB开发网   
核心提示:原 理部分到此为止,下面举一个完整的,Thunk技术的一个改进(3),有实际意义的例子,在windows中,具体的思路是这样的:当系统需要一个回调函数地址的时候 ,我们传递一个thunk代码段的地址,回调函 数的使用是很常见的,比如窗口过程

原 理部分到此为止。下面举一个完整的,有实际意义的例子。在windows中,回调函 数的使用是很常见的。比如窗口过程,又比如定时器回调函数。这些函数,你写 好代码,但是却从不直接调用。相反,你把函数地址传递给系统,当系统检测到 某些事件发生的时候,系统来调用这些函数。这样当然很好,不过如果你想做一 个封装,将所有相关部分写成一个类,那问题就来了。

问题是,这些回调 函数的形式事先已经定义好了,你无法让一个类的成员函数成为一个回调函数, 因为类型不可能匹配。这不能怪微软,微软不可能将回调函数定义为一个类成员 函数(该定义为什么类?),而只能将回调函数定义为一个全局的函数。并且微 软其实很多时候也提供了补救措施,在回调函数中增加了一个void *的参数。这 个参数一般都用来传递类的this指针。这样一来,可以这样解决:给系统提供一 个全局函数作为回调函数,在该函数中通过额外的那个void *参数访问到类的对 象,从而直接调用到类成员函数。如此,你的封装一样可以完成,不过多了一次 函数调用而已。

但是,不是所有的回调函数都这么幸运,微软都给它们提 供了一个额外的参数。比如,定时器的回调函数就没有。

VOID CALLBACK TimerProc(
 HWND hwnd,     // handle to window
 UINT uMsg,     // WM_TIMER message
 UINT_PTR idEvent, // timer identifier
 DWORD dwTime    // current system time
);

四个参数,个个都有用途。没有地方可以让你传递那个this指针 。当然了,你实在要传也可以做到,比如将hwnd设置为一个结构体的指针,其中 包含原来的hwnd和一个this指针。在定时器回调函数中取出hwnd后强制转化为结 构体指针,取出原来的hwnd,取出this指针。现在就可以通过this指针自由的调 用类成员函数了。不过这种方法不是我想要的,我要的是一个通用,统一的解决 方法。通过在参数里面加塞夹带的方法,一般也是没有问题的,不过如果碰到一 个回调函数没有参数怎么办?另外,本来是封装为一个类的,结果还是要带着一 个全局函数,你难道不觉得有些不爽吗?

这正是thunk技术大显身手的地 方了。我们知道,所谓类成员函数,和对应的全局函数,其实就差一个this指针 。如果我们在系统调用函数之前正确处理好this指针,那系统就可以正确的调用 类成员函数。

具体的思路是这样的:当系统需要一个回调函数地址的时候 ,我们传递一个thunk代码段的地址。这个代码段做两件事:

1、准备好 this指针

2、调用成员函数

关键的代码如下(完整的工程在附件中 ):

void ThunkTemplate(DWORD& addr1,DWORD& addr2,int calltype=0)
{
  int flag = 0;
  DWORD x1,x2;
  if(flag)
  {
    __asm //__thiscall
    {
thiscall_1:    mov  ecx,-1;  //-1占位符,运行时将 被替换为this指针.
      mov  eax,-2;  //-2占位符,运行时将 被替换为CTimer::CallBcak的地址.
      jmp  eax;
thiscall_2: ;
    }
    __asm //__stdcall
     {
stdcall_1:  push dword ptr [esp]    ; //保存(复制 )返回地址到当前栈中
      mov  dword ptr [esp+4], -1 ; // 将this指针送入栈中,即原来的返回地址处
      mov  eax, - 2;
      jmp  eax          ; //跳转至目标消息处理 函数(类成员函数)
stdcall_2: ;
    }
  }
   if(calltype==0)//this_call
  {
    __asm
     {
      mov  x1,offset thiscall_1; //取 Thunk代码段 的地 址范围.
      mov  x2,offset thiscall_2 ;
    }
  }
  else
  {
    __asm
    {
      mov  x1,offset stdcall_1; 
      mov  x2,offset stdcall_2 ;
    }
  }
  addr1 = x1;
  addr2 = x2;
}

上一页  1 2 3 4  下一页

Tags:Thunk 技术 一个

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接