Delphi:在运行时找到从给定基类下降的类?

前端之家收集整理的这篇文章主要介绍了Delphi:在运行时找到从给定基类下降的类?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在运行时,是否存在查找从特定基类下降的所有类的方法

例如,假装有一个类:

TLocalization = class(TObject)
...
public
   function GetLanguageName: string;
end;

或者假装有一个班级:

TTestCase = class(TObject)
...
public
   procedure Run; virtual;
end;

或者假装有一个班级:

TPlugIn = class(TObject)
...
public
   procedure Execute; virtual;
end;

或者假装有一个班级:

TTheClassImInterestedIn = class(TObject)
...
public
   procedure Something;
end;

在运行时,我想找到从TTestCase下降的所有类,以便我可以使用它们.

是否可以查询RTTI以获取此类信息?

另外:德尔福有没有办法走每一堂课?然后我可以简单地打电话:

RunClass: TClass;

if (RunClass is TTestCase) then
begin
   TTestCase(RunClass).Something;
end;

也可以看看

> Finding all classes that derive from a given base class in python
> Java: At runtime,find all classes in app that extend a base class

解决方法

嗯,是的,有办法,但你不会喜欢它. (显然,我需要这样一个免责声明,以防止我的其他完全有帮助的评论被那些知识渊博的,但不那么宽容的’高级’SO成员贬低.)

仅供参考:以下描述是我在Delphi 5最新版本时实际编写的一段代码的高级概述.最大的.从那以后,该代码被移植到更新的Delphi版本(目前直到Delphi 2010)并且仍然有效!

对于初学者,您需要知道一个类只不过是VMT和附带函数的组合(可能还有一些类型信息,具体取决于编译器版本和设置).您可能知道,类(由TClass类型标识)只是指向该类VMT的内存地址的指针.换句话说:如果您知道类的VMT的地址,那么它也是TClass指针.

有了这条知识牢记在你的脑海中,你实际上可以扫描你的可执行内存,并为每个地址测试它是否看起来像’VMT.似乎是VMT的所有地址都可以添加到列表中,从而可以完整地概述可执行文件中包含的所有类! (实际上,这甚至可以让您访问仅在单元的实现部分中声明的类,以及从作为二进制文件分发的组件和库链接的类!)

当然,有一些地址似乎是一个有效的VMT,但实际上是一些随机的其他数据(或代码) – 但是我已经提出了测试,这在我身上从未发生过(大约6年)在十多个主动维护的应用程序中运行此代码).

所以这是你应该做的检查(按照这个确切的顺序!):

>地址是否等于TObject的地址?如果是这样,这个地址是VMT,我们就完成了!
>读取TClass(地址).ClassInfo;如果已分配:

>它应该属于一个代码段(不,我不会详细介绍它 – 只是google it up)
>此ClassInfo的最后一个字节(通过添加SizeOf(TTypeInfo)SizeOf(TTypeData)确定)也应该属于该代码
>此ClassInfo(类型为PTypeInfo)应将其Kind字段设置为tkClass
>在此ClassInfo上调用GetTypeData,生成一个PTypeData

>这也应该属于有效的代码
>它的最后一个字节(通过添加SizeOf(TTypeData)确定)也应该属于该代码
>在这个TypeData中,它的ClassType字段应该等于被测试的地址.

>现在读取偏移量vmtSelfPtr上的VMT,并测试是否会导致测试地址(应指向自身)
>读取vmtClassName并检查它是否指向有效的类名(检查指针再次驻留在有效段中,字符串长度是否可接受,并且IsValidIdent应返回True)
>读取vmtParent – 它也应该属于有效的代码
>现在转换为TClass并读取ClassParent – 它也应该属于有效的代码
>读取vmtInstanceSize,它应该是> = TObject.InstanceSize和< = MAX_INSTANCE_SIZE(你要确定)
>从它的ClassParent读取vmtInstanceSize,它也应该是> = TObject.InstanceSize和< =先前读取的实例大小(父类永远不能大于子类)
>或者,您可以检查索引0及更高版本中的所有VMT条目是否都是有效的代码指针(尽管确定VMT中的条目数有点问题…但没有指标).
>使用ClassParent递归这些检查. (这应该达到上面的TObject测试,或者悲惨地失败!)

如果所有这些检查都成立,则测试地址是有效的VMT(就我而言)并且可以添加到列表中.

祝你好好实现这一切,我花了大约一个星期来做到这一点.

请告诉你它是如何工作的.干杯!

原文链接:https://www.f2er.com/delphi/103016.html

猜你在找的Delphi相关文章