How do I determine if a unit has been compiled into a Delphi program?

后端 未结 2 549
囚心锁ツ
囚心锁ツ 2020-12-29 09:08

I want to be able to determine if a particular unit has been compiled into a Delphi program, e.g. the unit SomeUnitName is part of some of my programs but not of others. I w

相关标签:
2条回答
  • 2020-12-29 09:23

    This function will return the list of unit names included in an application. Works in Delphi 2010. Not verified for other compilers.

    function UnitNames: TStrings;
    var
      Lib: PLibModule;
      DeDupedLibs: TList<cardinal>;
      TypeInfo: PPackageTypeInfo;
      PInfo: GetPackageInfoTable;
      LibInst: Cardinal;
      u: Integer;
      s: string;
      s8: UTF8String;
      len: Integer;
      P: PByte;
    begin
    result := TStringList.Create;
    DeDupedLibs := TList<cardinal>.Create;
    Lib := LibModuleList;
    try
      while assigned( Lib) do
        begin
        LibInst := Lib^.Instance;
        Typeinfo := Lib^.TypeInfo;
        if not assigned( TypeInfo) then
          begin
          PInfo := GetProcAddress( LibInst, '@GetPackageInfoTable');
          if assigned( PInfo) then
            TypeInfo := @PInfo^.TypeInfo;
          end;
        if (not assigned( TypeInfo)) or (DeDupedLibs.IndexOf( LibInst) <> -1) then continue;
        DeDupedLibs.Add( LibInst);
        P := Pointer( TypeInfo^.UnitNames);
        for u := 0 to TypeInfo^.UnitCount - 1 do
          begin
          len := P^;
          SetLength( s8, len);
          if len = 0 then Break;
          Inc( P, 1);
          Move( P^, s8[1], len);
          Inc( P, len);
          s := UTF8ToString( s8);
          if Result.IndexOf( s) = -1 then
            Result.Add( s)
          end
        end
    finally
      DeDupedLibs.Free
      end
    end;
    

    Example to use in the was suggested in the question...

    function IsSomeUnitNameInProgram: boolean;
    var
      UnitNamesStrs: TStrings;
    begin
    UnitNamesStrs := UnitNames;
    result := UnitNamesStrs.IndexOf('MyUnitName') <> -1;
    UnitNamesStrs.Free
    end;
    
    0 讨论(0)
  • 2020-12-29 09:25

    Unit names are compiled into the 'PACKAGEINFO' resource where you can look it up:

    uses
      SysUtils;
    
    type
      PUnitInfo = ^TUnitInfo;
      TUnitInfo = record
        UnitName: string;
        Found: PBoolean;
      end;
    
    procedure HasUnitProc(const Name: string; NameType: TNameType; Flags: Byte; Param: Pointer);
    begin
      case NameType of
        ntContainsUnit:
          with PUnitInfo(Param)^ do
            if SameText(Name, UnitName) then
              Found^ := True;
      end;
    end;
    
    function IsUnitCompiledIn(Module: HMODULE; const UnitName: string): Boolean;
    var
      Info: TUnitInfo;
      Flags: Integer;
    begin
      Result := False;
      Info.UnitName := UnitName;
      Info.Found := @Result;
      GetPackageInfo(Module, @Info, Flags, HasUnitProc);
    end;
    

    To do this for the current executable pass it HInstance:

    HasActiveX := IsUnitCompiledIn(HInstance, 'ActiveX');
    

    (GetPackageInfo enumerates all units which may be inefficient for executables with many units, in that case you can dissect the implementation in SysUtils and write your own version which stops enumerating when the unit is found.)

    0 讨论(0)
提交回复
热议问题