Delphi:在运行时查找从给定基类下降的类? [英] Delphi: At runtime find classes that descend from a given base class?

查看:138
本文介绍了Delphi:在运行时查找从给定基类下降的类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在运行时,是否找到从特定基类下载的所有类?

Is there at way, at runtime, to find all classes that descend from a particular base class?

例如,假装有一个类:

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 ,以便我可以与他们一起做东西。

At runtime i want to find all classes that descend from TTestCase so that i may do stuff with them.

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

Can the RTTI be queried for such information?

或者:在Delphi中有没有办法走每个课?我可以直接调用:

Alternatively: Is there a way in Delphi to walk every class? i can then simply call:

RunClass: TClass;

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



另见




  • 查找导出的所有类从python中的给定基类

  • Java:在运行时,查找扩展基类的应用程序中的所有类

  • See also

    • 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成员。)

      Well, yes, there is a way, but you're not going to like it. (Appearantly, I need a disclaimer like this, to prevent my otherwise perfectly helpfull comment getting downvoted by the oh-so knowledgable, but not so forgiving 'senior' SO members.)

      FYI:以下描述是当Delphi 5是最新版本时,我实际写的一段代码的高级概述。最大的从那时起,该代码被移植到更新的Delphi版本(目前直到Delphi 2010),并且仍然可以工作!

      FYI : The following description is a high-level overview of a piece of code I actually wrote when Delphi 5 was the latest & greatest. Since then, that code was ported over to newer Delphi versions (currently up until Delphi 2010) and still works!

      对于初学者,你需要知道一个类是什么不仅仅是VMT和附带功能的组合(也可能是某些类型信息,具体取决于编译器版本和设置)。您可能知道,类型为TClass的类只是指向该类VMT的内存地址的指针。换句话说:如果你知道一个类的VMT的地址,那就是TClass指针。

      For starters, you need to know that a class is nothing more than a combination of a VMT and the accompanying functions (and maybe some type-info, depending on compiler-version and -settings). As you probably know, a class - as identified by the type TClass - is just a pointer to the memory address of that classes' VMT. In other words : If you known the address of the VMT of a class, that's the TClass pointer as well.

      由于这些知识坚定地在你心中,你实际上可以扫描您的可执行内存,并且对于每个地址测试,如果它看起来像一个VMT。似乎是VMT的所有地址都可以添加到列表中,从而完整地概述了可执行文件中包含的所有类。 (实际上,这甚至可以让您访问在单元的实现部分中单独声明的课程,以及作为二进制文件分发的组件和图书馆链接的课程!)

      With that piece of knowledge stuck firmly in your mind, you can actually scan your executable memory, and for each address test if it 'looks like' a VMT. All addresses that seem to be a VMT can than be added to a list, resulting in a complete overview of all classes contained in your executable! (Actually, this even gives you access to classes declared solely in the implementation-section of a unit, and classes linked-in from components & libraries that are distributed as binaries!)

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

      Sure, there's a risk that some addresses seem to be a valid VMT, but are actually some random other data (or code) - but with the tests I've come up with, this has never happened to me yet (in about 6 years running this code in more than ten actively maintained applications).

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

      So here's the checks you should do (in this exact order!) :


      1. 地址是否等于TObject的地址?如果是这样,这个地址是一个VMT,我们完成了!

      2. 读取TClass(address).ClassInfo;如果它被分配:
      1. Is the address equal to the address of TObject? If so, this address is a VMT and we're done!
      2. Read TClass(address).ClassInfo; If it's assigned :

      1. 它应该在代码段内(不,我不会详细介绍 - 只是谷歌)

      2. 此ClassInfo的最后一个字节(通过添加SizeOf(TTypeInfo)+ SizeOf(TTypeData)确定))也应该落入该代码段

      3. 此ClassInfo类型PTypeInfo)应该有它的种类字段设置为tkClass

      4. 在此ClassInfo上调用GetTypeData,导致一个PTypeData
      1. it should fall inside a code-segment (no, I won't go into details on that - just google it up)
      2. the last byte of this ClassInfo (determined by adding SizeOf(TTypeInfo) + SizeOf(TTypeData)) should also fall inside that code-segment
      3. this ClassInfo (which is of type PTypeInfo) should have it's Kind field set to tkClass
      4. Call GetTypeData on this ClassInfo, resulting in a PTypeData

      1. 这也应该是在有效的代码段内

      2. 最后一个字节(通过添加SizeOf(TTypeData确定))也应该落入该代码段

      3. 此TypeData它的ClassType字段应等于要测试的地址。



    • 现在阅读VMT-to-be在偏移量vmtSelfPtr,并测试这是否导致正在测试的地址(应该指向自己)

    • 读取vmtClassName并检查它是否指向有效的类名ck指针,再次驻留在有效段中,字符串长度可以接受,IsValidIdent应该返回True)

    • 读取vmtParent - 它也应该在有效的代码段

    • 现在转换为一个TClass并读取ClassParent - 它也应该属于有效的代码段

    • 读取vmtInstanceSize,它应该是> = TObject.InstanceSize和< = MAX_INSTANCE_SIZE(您的确定)

    • 从它的ClassParent读取vmtInstanceSize,它也应该是> = TObject.InstanceSize和< =以前读取的实例大小(父类不能大于子类)

    • 您可以检查所有来自索引号0及以上的VMT条目是有效的代码指针(尽管确定VMT中的条目数量有一些问题...没有任何指标)。

    • 使用ClassParent重新执行这些检查。 (这应该达到上面的TObject测试,或者惨败!)

    • Now read the VMT-to-be at the offset vmtSelfPtr and test if this results in the address being tested (should point to itself)
    • Read vmtClassName and check if that points to a valid classname (check pointer to reside in a valid segment again, that the string length is acceptable, and IsValidIdent should return True)
    • Read vmtParent - it should also fall in a valid code segment
    • Now cast to a TClass and read ClassParent - it should also fall in a valid code segment
    • Read vmtInstanceSize, it should be >= TObject.InstanceSize and <= MAX_INSTANCE_SIZE (yours to determine)
    • Read vmtInstanceSize from it's ClassParent, it should also be >= TObject.InstanceSize and <= the previously read instance size (parent classes can never be larger than child classes)
    • Optionally, you could check if all VMT entries from index 0 and upwards are valid code pointers (although it's a bit problematic to determine the number of entries in a VMT... there's no indicator for this).
    • Recurse these checks with the ClassParent. (This should reach the TObject test above, or fail miserably!)
    • 如果所有这些检查成立,测试地址是有效的VMT(就我而言),可以添加到列表中。

      If all these checks hold, the test-address is a valid VMT (as far as I'm concerned) and can be added to the list.

      祝你好运,实现这一切,花了大约一个星期才能得到这个权利。

      Good luck implementing this all, it took me about a week to get this right.

      请告诉你如何运作。干杯!

      Please tell how it works out for you. Cheers!

      这篇关于Delphi:在运行时查找从给定基类下降的类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆