本帖最后由 yiyiyicz 于 2014-6-15 16:04 编辑
【相关资料】
类总是与VTable结构配对,以使得保持所有过程的地址。以下资料为“获得类模块中指定的函数地址”
大多数的编程语言都可以获取真实的函数地址。在汇编中,这个根本就不是问题,是正当的编程手段之一,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 相结合,构造一个最简单化的代码,实现真正的类模块回调函数
|