Как определить, был ли модуль скомпилирован в программу Delphi?
Я хочу иметь возможность определить, был ли конкретный модуль скомпилирован в программу Delphi, например, модуль SomeUnitName является частью некоторых из моих программ, а не других. Я хотел бы иметь функцию
function IsSomeUnitNameInProgram: boolean;
(что, конечно, не объявлено в SomeUnitName, потому что в этом случае оно всегда будет включено), которое во время выполнения возвращает true, если модуль был скомпилирован в программу, и false, если нет.
Мои мысли до сих пор шли по пути использования отладочной информации jcl (скомпилированной из файла подробной карты), которую я в основном добавляю ко всем моим программам для определения этой информации, но я бы предпочел ее, если бы jcl не требовался.
Добавление кода в SomeUnitName не вариант.
Это в настоящее время для Delphi 2007, но предпочтительно должно работать и для Delphi XE2.
Какие-нибудь мысли?
некоторые сведения об этом, поскольку @DavidHeffernan спросил:
Это не только для одной программы, но и для более чем 100 разных. Большинство из них используются внутри страны, но некоторые также доставляются клиентам. Поскольку мы используем довольно много библиотек, некоторые покупают другие по различным лицензиям с открытым исходным кодом, я хотел иметь возможность добавить вкладку "кредиты" в поле about, которая отображает только те библиотеки, которые фактически скомпилированы в программу, а не все. Благодаря ответу TOndrej теперь это работает именно так, как я хотел: код проверяет блок, который всегда связан, если программа используется библиотекой, и если он там есть, он добавляет имя библиотеки, авторское право и ссылка на него в поле о.
2 ответа
Имена модулей скомпилированы в ресурс '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 и написать свою собственную версию, которая прекращает перечисление, когда модуль найден.)
Эта функция вернет список имен устройств, включенных в приложение. Работает в 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;