Subversion Repositories decoder

Rev

Blame | Last modification | View Log | RSS feed

  1. {Copyright:      Heiko Behrens, Hagen Reddmann
  2.  Author:         Heiko Behrens (Initiator and Developer), Hagen Reddmann
  3.  Descriptions:   TypeInfoEx allows RTTI retrieval of all modules (BPLs, Dlls) in a
  4.                  comfortable and reversed way.
  5.  Versions:       Delphi 5 and above, testet on D5
  6.  Remarks:        this Copyright must be included
  7.  
  8.  
  9.  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
  10.  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  11.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  12.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
  13.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  14.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  15.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  16.  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  17.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  18.  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  19.  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  20.  
  21. }
  22. unit TypInfoEx;
  23.  
  24. interface
  25.  
  26. uses TypInfo;
  27.  
  28. type
  29.   TTypeInfoArray = array of PTypeInfo;
  30.   TTypeInfoEnumCallback = function(AUserData: Pointer; ATypeInfo: PTypeInfo): Boolean; register;
  31.   TTypeInfoEnumMethod = function(ATypeInfo: PTypeInfo): Boolean of object;
  32.   TTypeInfoSortCallback = function(AUserData: Pointer; ATypeInfo1, ATypeInfo2: PTypeInfo): Integer; register;
  33.   TTypeInfoSortMethod = function(ATypeInfo1, ATypeInfo2: PTypeInfo): Integer of object;
  34.  
  35. const
  36.   allModules = 0;
  37.  
  38. // enumeriert über alle RTTI Records eines Modules oder aller geladenen Module, gibt gefundene PTypeInfo zurück falls ACallback TRUE ergibt
  39. // falls ACallback =nil gibt die Funktion den ersten RTTI Record zurück
  40. function EnumTypeInfo(ACallback: TTypeInfoEnumCallback; AModule: LongWord = allModules; AUserData: Pointer = nil): PTypeInfo; overload;
  41. // enumeriert über alle RTTI Records eines TTypeInfoArray's, gibt gefundene PTypeInfo zurück falls ACallback TRUE ergibt
  42. function EnumTypeInfo(const ATypeInfoArray: TTypeInfoArray; ACallback: TTypeInfoEnumCallback; AUserData: Pointer = nil): PTypeInfo; overload;
  43. function EnumTypeInfo(const ACallback: TTypeInfoEnumMethod; AModule: LongWord = allModules): PTypeInfo; overload;
  44. // erzeugt ein Array aller PTypeInfo's die ACallback mit TRUE filtert
  45. // falls ACallback =nil gibt die Funktion alle RTTI Record's zurück
  46. function CollectTypeInfo(ACallback: TTypeInfoEnumCallback; AModule: LongWord = allModules; AUserData: Pointer = nil): TTypeInfoArray; overload;
  47. function CollectTypeInfo(const ACallback: TTypeInfoEnumMethod; AModule: LongWord = allModules): TTypeInfoArray; overload;
  48. function CollectTypeInfo(const ATypeInfoArray: TTypeInfoArray; ACallback: TTypeInfoEnumCallback; AUserData: Pointer = nil): TTypeInfoArray; overload;
  49. function CollectTypeInfo(const ATypeInfoArray: TTypeInfoArray; const ACallback: TTypeInfoEnumMethod): TTypeInfoArray; overload;
  50. // erzeugt ein Array aller PTypeInfo's die ein Interface darstellen
  51. function CollectInterfaces(AModule: LongWord = allModules): TTypeInfoArray;
  52. // erzeugt ein Array aller PTypeInfo's die ein Interface darstellen und durch die Klasse AClass impelemntiert werden
  53. function CollectInterfaceTypesOfClass(AClass: TClass = nil; AModule: LongWord = 0): TTypeInfoArray; overload;
  54. function CollectInterfaceTypesOfClass(const ATypeInfoArray: TTypeInfoArray; AClass: TClass = nil): TTypeInfoArray; overload;
  55. // sucht TypeInfo des Interfaces das die AGUID hat
  56. function FindTypeInfo(const ATypeInfoArray: TTypeInfoArray; const AGUID: TGUID): PTypeInfo; overload;
  57. function FindTypeInfo(const AGUID: TGUID; AModule: LongWord = allModules): PTypeInfo; overload;
  58. // sucht TypeInfo mit dem TypeName
  59. function FindTypeInfo(const ATypeName: String; AModule: LongWord = allModules): PTypeInfo; overload;
  60. function FindTypeInfo(const ATypeInfoArray: TTypeInfoArray; const ATypeName: String): PTypeInfo; overload;
  61. // sucht Klasse mit dem AClassName
  62. function FindClassByName(const AClassName: String; AModule: LongWord = allModules): TClass; overload;
  63. function FindClassByName(const ATypeInfoArray: TTypeInfoArray; const AClassName: String): TClass; overload;
  64. // sucht alle TypInfo's aller Klasse die von der Klasse AInheritsFrom abgeleitet wurden
  65. function FindClasses(AInheritsFrom: TClass; AModule: LongWord = allModules): TTypeInfoArray; overload;
  66. function FindClasses(const ATypeInfoArray: TTypeInfoArray; AInheritsFrom: TClass): TTypeInfoArray; overload;
  67. // wandelt ATypeInfo einer Klasse in deren Klassentyp um
  68. function TypeInfoToClass(ATypeInfo: PTypeInfo): TClass;
  69. // gibt das Modul zurück in dem ATypeInfo residiert
  70. function FindHInstanceOfTypeInfo(ATypeInfo: PTypeInfo): LongWord;
  71. function ModuleHasType(AModule: LongWord; ATypeInfo: PTypeInfo): Boolean;
  72. // sortiert ATypeInfoArray per ACallback
  73. function SortTypeInfoArray(var ATypeInfoArray: TTypeInfoArray; ACallback: TTypeInfoSortCallback; AUserData: Pointer = nil): Boolean; overload;
  74. function SortTypeInfoArray(var ATypeInfoArray: TTypeInfoArray; const ACallback: TTypeInfoSortMethod): Boolean; overload;
  75.  
  76. implementation
  77.  
  78. uses SysUtils;
  79.  
  80. function CompareGUID(const GUID1, GUID2: TGUID): Integer;
  81. // can be used to sort a list of GUIDs
  82. asm
  83.         MOV   ECX,EAX
  84.         MOV   EAX,[ECX + 0]
  85.         SUB   EAX,[EDX + 0]
  86.         JNZ   @Exit
  87.         MOV   EAX,[ECX + 4]
  88.         SUB   EAX,[EDX + 4]
  89.         JNZ   @Exit
  90.         MOV   EAX,[ECX + 8]
  91.         SUB   EAX,[EDX + 8]
  92.         JNZ   @Exit
  93.         MOV   EAX,[ECX + 12]
  94.         SUB   EAX,[EDX + 12]
  95. @Exit:
  96. end;
  97.  
  98. function DoEnumTypeInfo(AModule: LongWord; ACallback: TTypeInfoEnumCallback; AUserData: Pointer): PTypeInfo; overload;
  99. // copyright (c) 1998 Hagen Reddmann
  100.  
  101.   function GetBaseOfCode(AModule: LongWord; var ACodeStart, ACodeEnd: PChar): Boolean; register;
  102.   // get Codesegment pointers, check if module is a valid PE
  103.   asm
  104.            PUSH  EDI
  105.            PUSH  ESI
  106.            AND   EAX,not 3
  107.            JZ    @@2
  108.            CMP   Word Ptr [EAX],'ZM';
  109.            JNE   @@1
  110.            MOV   ESI,[EAX + 03Ch]
  111.            CMP   Word Ptr [ESI + EAX],'EP'
  112.            JNE   @@1
  113.            MOV   EDI,[EAX + ESI + 014h + 008h]
  114.            ADD   EAX,[EAX + ESI + 014h + 018h]
  115.            ADD   EDI,EAX
  116.            MOV   [EDX],EAX
  117.            MOV   [ECX],EDI
  118.            XOR   EAX,EAX
  119.     @@1:   SETE  AL
  120.     @@2:   POP   ESI
  121.            POP   EDI
  122.   end;
  123.  
  124. type
  125.   PLongWord = ^LongWord;
  126.   PByte = ^Byte;
  127. var
  128.   P,E,K,N: PChar;
  129.   L: Integer;
  130. begin
  131.   Result := nil;
  132.   try
  133.     if GetBaseOfCode(AModule, P, E) then
  134.       while P < E do
  135.       begin
  136.         LongWord(P) := LongWord(P) and not 3;
  137.         K := P + 4;
  138.         if (PLongWord(P)^ = LongWord(K)) and (TTypeKind(K^) >= Low(TTypeKind)) and (TTypeKind(K^) <= High(TTypeKind)) then
  139.         begin
  140.           L := PByte(K + 1)^;  // length Info.Name
  141.           N := K + 2;          // @Info.Name[1]
  142.           if (L > 0) and (N^ in ['_', 'a'..'z', 'A'..'Z']) then  // valid ident ??
  143.           begin
  144.             repeat
  145.               Inc(N);
  146.               Dec(L);
  147.             until (L = 0) or not (N^ in ['_', 'a'..'z', 'A'..'Z', '0'..'9']);
  148.             if L = 0 then // length and ident valid
  149.               if not Assigned(ACallback) or ACallback(AUserData, Pointer(K)) then // tell it and if needed abort iteration
  150.               begin
  151.                 Result := Pointer(K);
  152.                 Exit;
  153.               end else K := N;
  154.           end;
  155.         end;
  156.         P := K;
  157.       end;
  158.   except
  159.   end;
  160. end;
  161.  
  162. function EnumTypeInfo(ACallback: TTypeInfoEnumCallback; AModule: LongWord; AUserData: Pointer): PTypeInfo;
  163. type
  164.   PModulesEnumData = ^TModulesEnumData;
  165.   TModulesEnumData = packed record
  166.     ACallback: TTypeInfoEnumCallback;
  167.     AUserData: Pointer;
  168.     AResult: PTypeInfo;
  169.   end;
  170.  
  171.   function DoEnum(AModule: LongWord; AData: PModulesEnumData): Boolean; register;
  172.   begin
  173.     with AData^ do
  174.     begin
  175.       AResult := DoEnumTypeInfo(AModule, ACallback, AUserData);
  176.       Result := AResult = nil;
  177.     end;
  178.   end;
  179.  
  180. var
  181.   Data: TModulesEnumData;
  182. begin
  183.   Data.ACallback := ACallback;
  184.   Data.AUserData := AUserData;
  185.   Data.AResult := nil;
  186.   if AModule = allModules then EnumModules(TEnumModuleFuncLW(@DoEnum), @Data)
  187.     else Data.AResult := DoEnumTypeInfo(AModule, ACallback, AUserData);
  188.   Result := Data.AResult;
  189. end;
  190.  
  191. function EnumTypeInfo(const ATypeInfoArray: TTypeInfoArray; ACallback: TTypeInfoEnumCallback; AUserData: Pointer): PTypeInfo;
  192. var
  193.   I: Integer;
  194. begin
  195.   Result := nil;
  196.   for I := Low(ATypeInfoArray) to High(ATypeInfoArray) do
  197.     if not Assigned(ACallback) or ACallback(AUserData, ATypeInfoArray[I]) then
  198.     begin
  199.       Result := ATypeInfoArray[I];
  200.       Break;
  201.     end;
  202. end;
  203.  
  204. function EnumTypeInfo(const ACallback: TTypeInfoEnumMethod; AModule: LongWord): PTypeInfo;
  205. begin
  206.   if not Assigned(ACallback) then Result := EnumTypeInfo(nil, AModule)
  207.     else Result := EnumTypeInfo(TMethod(ACallback).Code, AModule, TMethod(ACallback).Data);
  208. end;
  209.  
  210. type
  211.   PCollectEnumData = ^TCollectEnumData;
  212.   TCollectEnumData =  packed record
  213.     ACallback: TTypeInfoEnumCallback;
  214.     AUserData: Pointer;
  215.     ACount: Cardinal;
  216.     AResult: TTypeInfoArray;
  217.   end;
  218.  
  219. function DoCollect(AData: PCollectEnumData; ATypeInfo: PTypeInfo): Boolean; register;
  220. begin
  221.   with AData^ do
  222.     if not Assigned(ACallback) or ACallback(AUserData, ATypeInfo) then
  223.     begin
  224.       if ACount mod 256 = 0 then SetLength(AResult, ACount + 256);
  225.       AResult[ACount] := ATypeInfo;
  226.       Inc(ACount);
  227.     end;
  228.   Result := False;
  229. end;
  230.  
  231. function CollectTypeInfo(ACallback: TTypeInfoEnumCallback; AModule: LongWord; AUserData: Pointer): TTypeInfoArray;
  232. var
  233.   Data: TCollectEnumData;
  234. begin
  235.   Data.ACallback := ACallback;
  236.   Data.AUserData := AUserData;
  237.   Data.ACount := 0;
  238.   Data.AResult := nil;
  239.   EnumTypeInfo(@DoCollect, AModule, @Data);
  240.   SetLength(Data.AResult, Data.ACount);
  241.   Result := Data.AResult;
  242. end;
  243.  
  244. function CollectTypeInfo(const ACallback: TTypeInfoEnumMethod; AModule: LongWord): TTypeInfoArray;
  245. begin
  246.   if not Assigned(ACallback) then Result := CollectTypeInfo(nil, AModule)
  247.     else Result := CollectTypeInfo(TMethod(ACallback).Code, AModule, TMethod(ACallback).Data);
  248. end;
  249.  
  250. function CollectTypeInfo(const ATypeInfoArray: TTypeInfoArray; ACallback: TTypeInfoEnumCallback; AUserData: Pointer): TTypeInfoArray;
  251. var
  252.   Data: TCollectEnumData;
  253.   I: Integer;
  254. begin
  255.   Data.ACallback := ACallback;
  256.   Data.AUserData := AUserData;
  257.   Data.ACount := 0;
  258.   Data.AResult := nil;
  259.   for I := Low(ATypeInfoArray) to High(ATypeInfoArray) do
  260.     DoCollect(@Data, ATypeInfoArray[I]);
  261.   SetLength(Data.AResult, Data.ACount);
  262.   Result := Data.AResult;
  263. end;
  264.  
  265. function CollectTypeInfo(const ATypeInfoArray: TTypeInfoArray; const ACallback: TTypeInfoEnumMethod): TTypeInfoArray;
  266. begin
  267.   if not Assigned(ACallback) then Result := CollectTypeInfo(ATypeInfoArray, nil)
  268.     else Result := CollectTypeInfo(ATypeInfoArray, TMethod(ACallback).Code, TMethod(ACallback).Data);
  269. end;
  270.  
  271. function FindHInstanceOfTypeInfo(ATypeInfo: PTypeInfo): LongWord;
  272. begin
  273.   Result := FindHInstance(ATypeInfo);
  274. end;
  275.  
  276. function ModuleHasType(AModule: LongWord; ATypeInfo: PTypeInfo): Boolean;
  277. begin
  278.   Result := AModule = FindHInstanceOfTypeInfo(ATypeInfo);
  279. end;
  280.  
  281. function CollectInterfaces(AModule: LongWord): TTypeInfoArray;
  282.  
  283.   function DoCollect(Dummy: Pointer; ATypeInfo: PTypeInfo): Boolean; register;
  284.   begin
  285.     Result := ATypeInfo.Kind = tkInterface;
  286.   end;
  287.  
  288. begin
  289.   Result := CollectTypeInfo(@DoCollect, AModule);
  290. end;
  291.  
  292. function DoGUID(AGUID: PGUID; ATypeInfo: PTypeInfo): Boolean; register;
  293. begin
  294.   if ATypeInfo.Kind <> tkInterface then Result := False else
  295.     with GetTypeData(ATypeInfo)^ do
  296.       Result := (ifHasGuid in IntfFlags) and (CompareGUID(GUID, AGUID^) = 0);
  297. end;
  298.  
  299. function FindTypeInfo(const ATypeInfoArray: TTypeInfoArray; const AGUID: TGUID): PTypeInfo;
  300. begin
  301.   Result := EnumTypeInfo(ATypeInfoArray, @DoGUID, @AGUID);
  302. end;
  303.  
  304. function FindTypeInfo(const AGUID: TGUID; AModule: LongWord): PTypeInfo;
  305. begin
  306.   Result := EnumTypeInfo(@DoGUID, AModule, @AGUID);
  307. end;
  308.  
  309. function DoTypeName(AName: PChar; ATypeInfo: PTypeInfo): Boolean; register;
  310. begin
  311.   Result := AnsiCompareText(AName, ATypeInfo.Name) = 0;
  312. end;
  313.  
  314. function FindTypeInfo(const ATypeName: String; AModule: LongWord): PTypeInfo;
  315. begin
  316.   Result := EnumTypeInfo(@DoTypeName, AModule, PChar(ATypeName));
  317. end;
  318.  
  319. function FindTypeInfo(const ATypeInfoArray: TTypeInfoArray; const ATypeName: String): PTypeInfo;
  320. begin
  321.   Result := EnumTypeInfo(ATypeInfoArray, @DoTypeName, PChar(ATypeName));
  322. end;
  323.  
  324. function TypeInfoToClass(ATypeInfo: PTypeInfo): TClass;
  325. begin
  326.   if not Assigned(ATypeInfo) or (ATypeInfo.Kind <> tkClass) then Result := nil
  327.     else Result := GetTypeData(ATypeInfo).ClassType;
  328. end;
  329.  
  330. function FindClassByName(const AClassName: String; AModule: LongWord): TClass;
  331. begin
  332.   Result := TypeInfoToClass(FindTypeInfo(AClassName, AModule));
  333. end;
  334.  
  335. function FindClassByName(const ATypeInfoArray: TTypeInfoArray; const AClassName: String): TClass;
  336. begin
  337.   Result := TypeInfoToClass(FindTypeInfo(ATypeInfoArray, AClassName));
  338. end;
  339.  
  340. function DoClass(AInheritsFrom: TClass; ATypeInfo: PTypeInfo): Boolean; register;
  341. begin
  342.   Result := (ATypeInfo.Kind = tkClass) and GetTypeData(ATypeInfo).ClassType.InheritsFrom(AInheritsFrom);
  343. end;
  344.  
  345. function FindClasses(AInheritsFrom: TClass; AModule: LongWord): TTypeInfoArray;
  346. begin
  347.   Result := CollectTypeInfo(@DoClass, AModule, AInheritsFrom);
  348. end;
  349.  
  350. function FindClasses(const ATypeInfoArray: TTypeInfoArray; AInheritsFrom: TClass): TTypeInfoArray;
  351. begin
  352.   Result := CollectTypeInfo(ATypeInfoArray, @DoClass, AInheritsFrom);
  353. end;
  354.  
  355. function DoClassGUID(AClass: TClass; ATypeInfo: PTypeInfo): Boolean; register;
  356. begin
  357.   if (AClass = nil) or (ATypeInfo.Kind <> tkInterface) then Result := False else
  358.     with GetTypeData(ATypeInfo)^ do
  359.       Result := (ifHasGuid in IntfFlags) and (AClass.GetInterfaceEntry(GUID) <> nil);
  360. end;
  361.  
  362. function CollectInterfaceTypesOfClass(AClass: TClass; AModule: LongWord): TTypeInfoArray;
  363. begin
  364.   Result := CollectTypeInfo(@DoClassGUID, AModule, AClass);
  365. end;
  366.  
  367. function CollectInterfaceTypesOfClass(const ATypeInfoArray: TTypeInfoArray; AClass: TClass): TTypeInfoArray;
  368. begin
  369.   Result := CollectTypeInfo(ATypeInfoArray, @DoClassGUID, AClass);
  370. end;
  371.  
  372. function SortTypeInfoArray(var ATypeInfoArray: TTypeInfoArray; ACallback: TTypeInfoSortCallback; AUserData: Pointer): Boolean;
  373.  
  374.   procedure QuickSort(L,R: Integer);
  375.   var
  376.     I,J: Integer;
  377.     M,T: PTypeInfo;
  378.   begin
  379.     I := L;
  380.     repeat
  381.       L := I;
  382.       J := R;
  383.       M := ATypeInfoArray[(L + R) shr 1];
  384.       repeat
  385.         while ACallback(AUserData, ATypeInfoArray[I], M) < 0 do Inc(I);
  386.         while ACallback(AUserData, ATypeInfoArray[J], M) > 0 do Dec(J);
  387.         if I > J then Break;
  388.         T := ATypeInfoArray[I];
  389.         ATypeInfoArray[I] := ATypeInfoArray[J];
  390.         ATypeInfoArray[J] := T;
  391.         Inc(I);
  392.         Dec(J);
  393.       until I > J;
  394.       if L < J then QuickSort(L, J);
  395.     until I >= R;
  396.   end;
  397.  
  398. begin
  399.   Result := Assigned(ACallback) and (High(ATypeInfoArray) > 0);
  400.   if Result then QuickSort(0, High(ATypeInfoArray));
  401. end;
  402.  
  403. function SortTypeInfoArray(var ATypeInfoArray: TTypeInfoArray; const ACallback: TTypeInfoSortMethod): Boolean;
  404. begin
  405.   Result := Assigned(ACallback) and SortTypeInfoArray(ATypeInfoArray, TMethod(ACallback).Code, TMethod(ACallback).Data);
  406. end;
  407.  
  408.  
  409. {
  410. procedure Test;
  411.  
  412.   function DoPrint(AUserData: Pointer; ATypeInfo: PTypeInfo): Boolean; register;
  413.   begin
  414.     WriteLn(ATypeInfo.Name);
  415.     Result := False;
  416.   end;
  417.  
  418.   function DoSort(Dummy: Pointer; ATypeInfo1, ATypeInfo2: PTypeInfo): Integer; register;
  419.   begin
  420.     Result := AnsiCompareText(ATypeInfo1.Name, ATypeInfo2.Name);
  421.   end;
  422.  
  423. var
  424.   L: TTypeInfoArray;
  425. begin
  426.   L := CollectTypeInfo(nil);
  427.   SortTypeInfoArray(L, @DoSort);
  428.   EnumTypeInfo(L, @DoPrint);
  429. end;
  430. }
  431.  
  432. end.
  433.