Подтвердить что ты не робот

Как определить, был ли блок скомпилирован в программу Delphi?

Я хочу иметь возможность определить, скомпилирована ли конкретная единица в программе Delphi, например. блок SomeUnitName является частью некоторых моих программ, но не других. Я хотел бы иметь функцию

function IsSomeUnitNameInProgram: boolean;

(который, конечно, не объявлен в SomeUnitName, потому что в этом случае он всегда будет включен), что во время выполнения возвращает true, если блок был скомпилирован в программу, а false, если нет.

Мои мысли до сих пор шли по линиям использования информации об отладке jcl (скомпилированной из подробного файла карты), который я в основном добавляю ко всем моим программам для определения этой информации, но я бы предпочел, если бы jcl не требовалось.

Добавление кода в SomeUnitName не является вариантом.

Это в настоящее время для Delphi 2007, но желательно также работать для Delphi XE2.

Любые мысли?

некоторый фон на этом, так как @DavidHeffernan спросил:

Это не только для одной программы, но и для более чем 100 различных. Большинство из них используются внутри страны, но некоторые из них также доставляются клиентам. Поскольку мы используем довольно много библиотек, некоторые покупают других в разных лицензиях с открытым исходным кодом, я хотел бы добавить вкладку "кредиты" в поле about, которое отображает только те библиотеки, которые фактически были скомпилированы в программу, а не все из них. Благодаря ответу от TOndrej, это работает именно так, как я хотел: Код проверяет единицу, которая всегда связана, если библиотека используется программой, и если она есть, она добавляет имя библиотеки, авторское право и ссылку на нее в поле about.

4b9b3361

Ответ 1

Имена модулей скомпилированы в ресурс "PACKAGEINFO", где вы можете найти его:

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;

Чтобы сделать это для текущего исполняемого файла, пройдите его HInstance:

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

(GetPackageInfo перечисляет все единицы, которые могут быть неэффективными для исполняемых файлов со многими единицами, в этом случае вы можете проанализировать реализацию в SysUtils и напишите свою собственную версию, которая перестает перечисляться, когда устройство найдено.)

Ответ 2

Эта функция вернет список имен узлов, включенных в приложение. Работает в Delphi 2010. Не проверяется для других компиляторов.

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;

Пример использования в предположении был предложен в вопросе...

function IsSomeUnitNameInProgram: boolean;
var
  UnitNamesStrs: TStrings;
begin
UnitNamesStrs := UnitNames;
result := UnitNamesStrs.IndexOf('MyUnitName') <> -1;
UnitNamesStrs.Free
end;