您现在的位置:首页 >> 基础算法 >> window基础 >> 内容

Delphi检测对象有方法时是否为纯虚函数(3)

时间:2011/9/3 15:37:10 点击:

关于我和creation-zy的代码可能需要解释一下。
首先要懂一些关于RTTI的原理:
1. Abstract只可以作用于动态方法和虚方法
2. 如果是虚方法, Delphi在对象的RTTI中为它保存一个VMT(虚方法表), 该表是所有虚方法的指针列表.
3. 如果是动态方法, Delphi为对象保留一个全局的DMT(动态方法表), 这是全部动态方法的指针列表.
4. 如果虚方法方法被定义成Abstract, 则Delphi在编译期将VMT中这个方法的指针直接设为
_AbstractError()这个系统函数的指针.
5. 如果动态方法被定义成Abstract, Delphi在编译期将DMT中它的指针设成_AbstractError
由于上述缘故, 所以所有的"未被重新实现过的Abstract的地址指针都将恒为_AbstractError". 基于
这个缘故, creation-zy用指针地址检测的方法来判定一个方法是否是未被实现过的Abstract. 我也用同
样的原理来取_AbstractError()指针.
此外, creation-zy用汇编指令"DWord(P)"的技巧来取一个对象方法的指针, 这是一个技巧, 因为Delphi
进行类型检测的缘故. 在普通的代码中是无法用的.
他的思路的确独到. 我的代码只是一个补充, 并没有跳出他的思想框架. 哈哈.
接下来. 请有识之士来解决第二个问题, 也就是"IsAbstract()函数与类类定义直接相关"的问题.
谢谢.
随便说一声,我用了三个小时来看你的代码,并查相关资料,并写我的修正. 哈哈, 有难度!
——要知道,前两个月我都在研究RTTI。^-^
  大哥,我也没学过汇编呀!上面的代码如果被方家看到,我肯定被唾沫淹死了。你在调试程序的时候
经常用Ctrl+Alt+C打开CPU窗口看看,简单的比较、跳转还是不难学会的。(惭愧!我至今还不会用汇编
操纵数组,上面的应用已经把我的能耐榨干了 :( )
to aimingoo:
  呵呵,恭喜解决了一个问题。目前我对第二个问题还没有解决办法(我手头没有讲RTTI、类型转换方面
的参考手册),只能提供几个可能有帮助的思路:
1.一般说来,凡是包含未实现的方法的类都不应该被实例化(即创建)!
2.如果确实有这个需要,完全可以将abstract过程用一个不作任何事的空方法取代。
3.用Delphi的函数Overload,定义若干个可以接受不同参数的IsAbstract函数——如你所说,会比较烦。
4.如果可能,将这些过程统一定义为 procedure (A:array of const); ——以不变应万变!
5.根据获得的_AbstractError的地址,在运行初始化时直接改写它的机器代码,让它什么也不做(够狠吧)
下面的代码我没有运行通过——Win2000不让我改写自己进程的代码段。

DelphiCode: 
procedure DoNothing1;
begin
end;
procedure DoNothing2;
begin
end;
procedure TForm1.Button2Click(Sender: TObject);
var
  PP1,PP2:DWord;
begin
  //PByte(AbstractErrorAddr)^:=$90; 唉!这里都通不过...
  PP1:=DWord(@DoNothing1);
  PP2:=DWord(@DoNothing2);
  Caption:=Format('%8x %8x',[PP1,PP2]);
  System.Move(Pointer(PP1)^,AbstractErrorAddr^,PP2-PP1); //出错 555555555555555
end;
昨晚我看了几个小时,总算掌握了基本语法了(半道出家的和尚,经都不会念呀.小僧惭愧) ok ,it seems as if I get it. because On exit, eax holds the result of the function, or in the case of a procedure, convention states it holds the value of any relevant error code you may define. So,AbstractErrorAddr in following codes can holds the the error code,right? procedure GetAbstractErrorAddr(P:ObjProc); asm mov EAX, DWord(P) mov AbstractErrorAddr, EAX end; 至于你说的四个方法: 1.一般说来,凡是包含未实现的方法的类都不应该被实例化(即创建)! ==> 哈哈,我明白,但我现在的确有这个需要。 2.如果确实有这个需要,完全可以将abstract过程用一个不作任何事的空方法取代。 ==> 哈,这个我也明白,我现在的确是这样做的,但我的想法是一个技术探讨。想要知道到底能否实现而已。 3.用Delphi的函数Overload,定义若干个可以接受不同参数的IsAbstract函数——如你所说,会比较烦。 ==> 不说啦,你也明白苦衷的啦。 4.如果可能,将这些过程统一定义为 procedure (A:array of const); ——以不变应万变! ==> 这个,好象也不成吧???array of const应该也不能接受对象方法参数的吧? 5.根据获得的_AbstractError的地址,在运行初始化时直接改写它的机器代码,让它什么也不做(够狠吧) ==> 太狠太狠。我得思之考之~~~~我准备做一个测试代码。但是,黑黑,我认为成功的可能性不会太大。
而且,会影响到内核的啦。
哎~~~~~~“根据获得的_AbstractError的地址,在运行初始化时直接改写它的机器代码”的方法我已经搞定了。
今天上午就搞定了。但是想了想,决定写篇文章再发上来。
而且,如果用这种方法,事实上也得不到
 if IsNotAbstract(aClass.aAbstractMethod) then aClass.aAbstractMethod
这样的效果。
我在想有没有别的方法。中午跟公司的一个同事讨论了一下,有一些想法,但还是没有好
的完全解决的办法。这个我会在文章中提出来。
哎~~~~~真是头痛的问题呀。:(
用汇编指令"DWord(P)"的技巧来取一个对象方法的指针, 这是一个技巧, 因为Delphi
进行类型检测的缘故. 在普通的代码中是无法用的.
如果用类引用而不是对象引用来获得一个方法的地址,那@返回的就是
该对象方法的代码指针, yDDD的贴子已写了
呵呵,这个贴子从昨天我一直在看,偷学了很多
我试了下,@后接虚拟方法,动态方法都可得到它的地址, 唯有抽象方法得不到AbstractError的地址
@TExample.AbstractMethod,看了一下CPU窗口,好像delphi另外插入了一句指令
JMP @AbstractError, 而@TExample.AbstractMethod返回是这条指令的地址
而如果判断这个内容是不是 JMP @AbstractError地址,我觉得应该可以
不过具体的指令码,不太明白
我试了几个抽象函数
E96B06FBFF
E96706FBFF
E96306FBFF
E95F06FBFF
E95706FBFF
E93306FBFF
那么我写了如下
DelphiCode: 
function IsAbstract(P: Pointer): Boolean;
type
  PInstruction = ^TInstruction;
  TInstruction = record
    I1: Byte;
    I2: Byte;
    I3: WORD;
    I4: Byte
  end;
begin
  Result := (PInstruction(P).I1 = $E9) and
            (PInstruction(P).I3 = $FB06) and
            (PInstruction(P).I4 = $FF);
end;

上一页1234下一页

作者:网络 来源:转载
共有评论 0相关评论
发表我的评论
  • 大名:
  • 内容:
  • 盒子文章(www.2ccc.com) © 2024 版权所有 All Rights Reserved.
  • 沪ICP备05001939号