Delphi:在运行时查找从给定基类下降的类? [英] Delphi: At runtime find classes that descend from a given base class?
问题描述
在运行时,是否找到从特定基类下载的所有类?
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:在运行时,查找扩展基类的应用程序中的所有类
- 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
- 地址是否等于TObject的地址?如果是这样,这个地址是一个VMT,我们完成了!
- 读取TClass(address).ClassInfo;如果它被分配:
- Is the address equal to the address of TObject? If so, this address is a VMT and we're done!
- Read TClass(address).ClassInfo; If it's assigned :
- 它应该在代码段内(不,我不会详细介绍 - 只是谷歌)
- 此ClassInfo的最后一个字节(通过添加SizeOf(TTypeInfo)+ SizeOf(TTypeData)确定))也应该落入该代码段
- 此ClassInfo类型PTypeInfo)应该有它的种类字段设置为tkClass
- 在此ClassInfo上调用GetTypeData,导致一个PTypeData
- it should fall inside a code-segment (no, I won't go into details on that - just google it up)
- the last byte of this ClassInfo (determined by adding SizeOf(TTypeInfo) + SizeOf(TTypeData)) should also fall inside that code-segment
- this ClassInfo (which is of type PTypeInfo) should have it's Kind field set to tkClass
- Call GetTypeData on this ClassInfo, resulting in a PTypeData
- 这也应该是在有效的代码段内
- 最后一个字节(通过添加SizeOf(TTypeData确定))也应该落入该代码段
- 此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!)
See also
推荐答案
嗯,是的,有一种方法,但你不会喜欢它。 (显然,我需要一个这样的免责声明,以防止我的其他完全有帮助的评论被哦,所以知道的,但不是那么宽恕的高级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!) :
如果所有这些检查成立,测试地址是有效的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屋!