注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

火车的家

Put first thing first

 
 
 

日志

 
 

2012.11.19 怎么将c++的成员函数转为静态函数?  

2012-11-19 16:58:19|  分类: 技术博客 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

前几天读了一位网友的文章《如何让API回调你的VC类成员函数而不是静态函数》,写的很好,可惜很多细节都被略过不谈,所以我决定写这篇小文作为原文的补充。另外,本文写了一个独立的例子,示范了怎么将类成员函数转为消息函数传给windows。例子文件的链接: testwin

一共有4个补充:

1.成员函数调用与普通函数调用有什么区别?

区别是:调用成员函数时,ecx寄存器保存的是this指针。

2.关键代码段:

整篇文章的核心技术实际上就是下面两个关键代码段。

1)代码段1:

a. call 偏移量 //“偏移量”指向的是代码段2
b. LONG_PTR _this;//这个指针里保存了this指针
c. LONG_PTR _func;//这个指针里保存了成员函数的指针

这段代码包含一条指令和两个指针。代码段对应结构体_ACCallbackOpCodes。

在例子 testwin 中
wcex.lpfnWndProc = cb;//就是窗口消息函数的地址
实际上保存的是指向“代码段1”的地址。

2)代码段2:

代码段2包含以下4条指令,对应着STDACJMPProc函数。
a. POP ECX
//将栈里保存的this指针的偏移量pop到ecx里去
//问:this指针怎么会跑到栈里去了?
//答:这是因为call指令会把它的下一条指令压入栈。
//这也是为什么要把this指针放在call指令后面的原因。
//对于call的详细信息请参考汇编语言手册吧。
b. MOV EAX, DWORD PTR [ECX + 4] //成员函数的指针存入eax
c. MOV ECX, [ECX] //this指针存入ecx
d. JMP EAX //跳转到成员函数的起始地址

3.为什么要用VirtualAlloc函数?
先 举一个反例:如果在栈上分配一块内存,保存_ACCallbackOpCodes,那么就需要调用FlushInstructionCache函数,因为 _ACCallbackOpCodes需要动态更新某些参数,而cpu不会自动刷新这块内存(这样就必须调用FlushInstructionCache 来刷新)。但是如果用VirtualAlloc就不会有这个问题。

4.在CalcJmpOffset中,为什么要计算STDACJMPProc(也就是“代码段2”)相对于_ACCallbackOpCodes的偏移量?
我们知道_ACCallbackOpCodes的第一条指令是:
call STDACJMPProc(也就是“代码段2”);
但 是因为_ACCallbackOpCodes与“代码段2”不在同一个段,在执行call指令时,cs寄存器指向的是 _ACCallbackOpCodes所在段的段基址,所以想要跳转到“代码段2”上,就必须计算“代码段2”相对于 _ACCallbackOpCodes所在段的段基址的偏移量(这个段基址就是_ACCallbackOpCodes的首地址)。


5. 其他:

其实我觉得传一个全局函数给api并且把类的this指针和成员函数地址一块作为参数传给这个全局函数,然后让这个全局函数在内部调用成员函数,效果和本文的方法一样,而且还简单。不过这两种方法的区别是本文的方法每次都是传不同的函数地址给api,而全局函数的方法每次都是同一个函数指针,并且全局函数的方法需要api可以传回调函数的参数。另外,我觉得本文的方法还可以进一步简化,不就是向ecx写this指针和跳转到成员函数吗?为什么搞得这么复杂?还有,在linux平台上怎么实现这个方法也需要思考一下。

  评论这张
 
阅读(389)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017