PctGL SERIES  
http://pctgl.cnblogs.com


GetClassProcAddress 的加强版出炉了

上面有人发了个帖子,说已有前人做出此题目。。。
我啥也不说了,踏踏实实的做我能做的就得了。。。

这次 GetClassProcAddress 有变化了,做为加强版,增加了大量代码,增加了 1 个参数

QUOTE:
Private Function GetClassProcAddress(ByVal SinceCount As Long, ByVal ParamsCount As Long) As Long
Dim mePtr As Long
Dim i As Long
Dim jmpAddress As Long
mePtr = ObjPtr(Me)
CopyMemory i, ByVal mePtr, 4
CopyMemory i, ByVal i + (SinceCount - 1) * 4 + &H1C, 4
CopyMemory jmpAddress, ByVal i + 1, 4
jmpAddress = i + jmpAddress + 5

ReDim TimerCallback(33)
TimerCallback(0) = &H55: TimerCallback(1) = &H8B: TimerCallback(2) = &HEC: TimerCallback(3) = &H83: TimerCallback(4) = &HEC
TimerCallback(5) = &H10: TimerCallback(6) = &H8B: TimerCallback(7) = &HFC: TimerCallback(8) = &H8D: TimerCallback(9) = &H75
TimerCallback(10) = &H8: TimerCallback(11) = &H33: TimerCallback(12) = &HC9: TimerCallback(13) = &HB1: TimerCallback(15) = &HFC
TimerCallback(16) = &HF3: TimerCallback(17) = &HA5: TimerCallback(18) = &H68: TimerCallback(23) = &HB8: TimerCallback(28) = &HFF
TimerCallback(29) = &HD0: TimerCallback(30) = &HC9: TimerCallback(33) = &H0

TimerCallback(32) = ParamsCount * 4
TimerCallback(14) = ParamsCount             ' mov cl,4(params)   >>> for rep movs
CopyMemory TimerCallback(19), mePtr         ' objptr(me)
CopyMemory TimerCallback(24), jmpAddress    ' call eax
If ParamsCount = 0 Then TimerCallback(31) = &HC3 Else TimerCallback(31) = &HC2
GetClassProcAddress = VarPtr(TimerCallback(0))
End Function

;// 使用说明:

1. 函数地址 = GetClassProcAddress ( 指定为哪个函数 [上面解释],想获取的函数的参数个数 )

2. 这个函数的实现前提,要求有个局部数组,也就是在类模块的声明部分声明一个数组,
   
   由于我这个是在写一个热键类中完成的,所以这个数组名就叫了 TimerCallBack,你可以随便修改为你想要的 100% 免责开源...

3. 函数返回值是一个 Long 型数据,并不是你指定的函数的真正地址,而是 TimerCallBack 数组的首元素地址, TimerCallBack

   中是一个小型的用汇编写的函数。

4. 返回值就是你可以进行子类化的函数地址,返回值可直接用于 SetWindowLong x,x,这里





再附上一个完整的使用实例,热键类
基本没注释。。。 对不起大家,我看不得绿油油的一片,看不懂的请跟贴提问吧




同时想问问,这个还不够 3 级精华?




;// ============================================================================================================================





大多数的编程语言都可以获取真实的函数地址,在汇编中,这个根本就不是问题,是正当的编程手段之一,windows也经常会应用这个称为回调

函数的东西,但VB编程受限制,只能获取标准模块中的函数地址,而且该函数地址不可在运行时获取属于静态连接

在进行对象编程时,经常用到类模块,最简单的类模块应用就是包装代码了,但遇到类似处理子类化窗口函数时经常会让你觉得很累,无法获取

类模块中指定的函数地址,于是... 你不得不绕到模块中,通过动态调用的方式实现回调函数,比起 SetWindowLong xxx,xxx,any proc address

简直太费脑筋了,而且很多新手还不能理解这种编程思路.也无法应用, 有些汇编高手开始从对象的底层做起一步一步的探索找到了 Thunk 的

解决方法,其实这个方法是MS首先做出来的,只不过被coders们加强了

利用所学的有限的知识我也做一下,争取解决他吧:

Private Function GetClassProcAddress(ByVal SinceCount As Long) As Long
'***************************************************************************************************
'   VB6 历史上最简单的获取类中指定函数地址的函数诞生了,can be get address of property to value ,too
'***************************************************************************************************
Dim i As Long, jmpAddress As Long
CopyMemory i, ByVal ObjPtr(Me), 4                                ' get vtable
CopyMemory i, ByVal i + (SinceCount - 1) * 4 + &H1C, 4           ' 查表
CopyMemory jmpAddress, ByVal i + 1, 4                            ' 获取的函数地址实际还是一个表,是一个跳转表
GetClassProcAddress = i + jmpAddress + 5                         ' 计算跳转相对偏移取实际地址
End Function

调用方法:

类模块中指定的函数地址 = GetClassProcAddress( 第几个函数 )

oo" 代码很少... 他能行吗? 没问题... 找到指定的函数地址是没问题的...

解释下这个函数,

参数 SinceCount , 是从某个类模块中最顶端的函数或属性算起,他是第几个函数

这个参数有讲究...
1. 当被查找的函数为 公用函数时,它的值就是自顶端算起的第几个函数,比如你在类模块中最顶端写的一个公用函数 WndProc,那么就传 1
     如果是第2个公用函数或属性那么就传 2 依次...  注意,计算的时候要算上公用属性,公用属性也要算上,当他是函数,算做一个

2. 当被查找的函数为 局部函数时,也就是说如果是 Private 修饰的函数,则此参数值为 所有公用函数个数 + 这是第 N 个私有函数
     也是从顶端算起,同样包括属性

说下原理,
对象是什么? 对象实际就是一个结构,VB,甚至 C++ 都不一定能让你真正深刻的理解最底层的对象构造,如果说 VB 能让你懂得什么叫继承

则 C++ 能让你知道对象还可以变异....对象原来是那么简单实现了那么高级的技术

再向底层看,用汇编构造对象,你就可以看到,对象原来就是一个结构,结构中包括所有公用函数,属性的地址指针,和连接,销毁函数指针等

那么,在返回到 VB,ObjPtr 可以得到对象的 vTable 指针,通过查询 vTable 就可以得到我们想要的函数指针,前提是我们要知道编译器是

按照什么样的顺序放置属性函数指针的,现在经过查询资料和测试,已经知道了,那就是 基址 + &H1C 所谓的基址其实就是vTable, &H1C就

是VB给结构添加的和必要的函数指针所占用的空间, 从vTable+&H1C 开始存储我们的函数地址,存储顺序如何,可以参照上面对 GetClassProcAddress

的参数 SinceCount 的解释.VB 把所有模块都单独的建立了一个表,每个表中又有单独的表表示他所包含的函数地址.

好了,函数和原理解释已经差不多了,再说说应用

很不幸的我要说,直接应用价值基本 = 0 , 郁闷啊... 为什么呢? 因为... 对象的函数他的第1个参数是vTable指针,第2个(暂时忘了,想起来再补)

于是你构造的函数有4个参数,但编译后该函数将有6个参数,那如果直接交给别人用,比如 APi 那还不出事吗...

会出事,但又不是不能弥补,加上少量的内嵌汇编代码,从新构造一个小函数,就可以完美的运行了,o... 还是很不错的选择

说了很多, 我也累了,就先打住了,总结起来,就是成功的用最简单的代码获取了类模块中指定的函数地址,从这个角度来说此文应该还是一精华文章吧?

等我有时间了,我会将弥补的汇编函数和 GetClassProcAddress 相结合,构造一个最简单化的代码,实现真正的类模块回调函数

 

posted on 2008-12-11 14:39  PctGL  阅读(2067)  评论(3编辑  收藏  举报