Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何确定一个单元是否已编译成Delphi程序?_Delphi_Delphi 2007 - Fatal编程技术网

如何确定一个单元是否已编译成Delphi程序?

如何确定一个单元是否已编译成Delphi程序?,delphi,delphi-2007,Delphi,Delphi 2007,我希望能够确定某个特定单元是否已编译成Delphi程序,例如,单元SomeUnitName是我的一些程序的一部分,而不是其他程序的一部分。我想要一个函数 function IsSomeUnitNameInProgram: boolean; (这当然不是在SomeUnitName中声明的,因为在这种情况下,它将始终包含在内)如果单元已编译到程序中,则在运行时返回true,否则返回false 到目前为止,我的想法是使用jcl调试信息(从一个详细的映射文件编译),我基本上将其添加到我的所有程序中以确

我希望能够确定某个特定单元是否已编译成Delphi程序,例如,单元SomeUnitName是我的一些程序的一部分,而不是其他程序的一部分。我想要一个函数

function IsSomeUnitNameInProgram: boolean;
(这当然不是在SomeUnitName中声明的,因为在这种情况下,它将始终包含在内)如果单元已编译到程序中,则在运行时返回true,否则返回false

到目前为止,我的想法是使用jcl调试信息(从一个详细的映射文件编译),我基本上将其添加到我的所有程序中以确定此信息,但如果不需要jcl,我更喜欢它

向SomeUnitName添加代码不是一个选项

这目前适用于Delphi 2007,但最好也适用于Delphi XE2

有什么想法吗

自@DavidHeffernan提出问题以来,这方面的一些背景资料如下:

这不仅适用于一个项目,也适用于100多个不同的项目。其中大部分在内部使用,但也有一些交付给客户。由于我们使用了相当多的库,有些库是在各种开源许可下购买的,所以我希望能够在about框中添加一个“credits”选项卡,该选项卡只显示实际编译到程序中的库,而不是所有库。多亏了TOndrej的回答,这项工作现在完全符合我的要求:
如果程序使用库,代码将检查始终链接的单元,如果存在库,则会将库名称、版权和指向库的链接添加到“关于”框中。

单元名称被编译到“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');

(枚举所有可能对具有多个单元的可执行文件无效的单元,在这种情况下,您可以在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;
函数单元名:t字符串;
变量
Lib:PLibModule;
重复数据库:TList;
TypeInfo:PPackageTypeInfo;
PInfo:GetPackageInfoTable;
利宾斯特:红衣主教;
u:整数;
s:字符串;
s8:UTF8String;
len:整数;
P:PByte;
开始
结果:=TStringList.Create;
重复数据库:=TList.Create;
Lib:=LibModuleList;
尝试
分配时(Lib)执行
开始
LibInst:=Lib^.Instance;
Typeinfo:=Lib^.Typeinfo;
如果未分配(类型信息),则
开始
PInfo:=GetProcAddress(LibInst,@getpackageinfo');
如果分配(PInfo),则
TypeInfo:=@PInfo^.TypeInfo;
结束;
如果(未分配(TypeInfo))或(重复数据库索引(LibInst)-1),则继续;
重复库添加(LibInst);
P:=指针(TypeInfo^.UnitNames);
对于u:=0到TypeInfo^.UnitCount-1 do
开始
len:=P^;
设定长度(s8,len);
如果len=0,则断开;
公司(P,1),;
动议(P^,s8[1],len);
公司(P,len),;
s:=UTF8ToString(s8);
如果Result.IndexOf(s)=-1,则
结果。添加(s)
结束
结束
最后
重复数据库。免费
结束
结束;
问题中建议了在中使用的示例

function IsSomeUnitNameInProgram: boolean;
var
  UnitNamesStrs: TStrings;
begin
UnitNamesStrs := UnitNames;
result := UnitNamesStrs.IndexOf('MyUnitName') <> -1;
UnitNamesStrs.Free
end;
函数是someunitnameinprogram:boolean;
变量
单位名称标准:t字符串;
开始
UnitNamesStrs:=单元名称;
结果:=unitnamestrs.IndexOf('MyUnitName')-1;
免费的
结束;

您在编译时就知道这一点。为什么要进行运行时检查。他可能有多个具有不同功能的程序生成版本。并且不依赖于条件编译。如果这是他自己的代码,他可以依赖一些选择加入注册方案,比如VCL RegisterClass或UnitVersioning lib。但如果不是他的单位…这正是我要找的。非常感谢。TOndrej的解决方案是正确的方法。这种方法的唯一优点是,您不必枚举所有包来获得聚合列表,而且它可能更高效一些。缺点是,它感觉有点黑客味,并且没有在其他编译器上验证过。回想起来,我应该添加一些“有趣的方法”形式的笑脸(;它感觉有点黑客味,但以简洁的方式显示了一些Delphi内部。顺便说一句:开始/结束没有缩进,但在开始括号后有空格,而不是结束括号后有空格?(我一直在学习,只是好奇为什么;不想发动一场代码格式化战争)。格式只是我的个人风格。可能有人想咬我一口,说它不受欢迎、不正统或诸如此类的东西。如果是StackOverflow,我真的不在乎受欢迎程度。我会按自己的方式做。如果有人反对我的格式选择,他们完全可以忽略我的答案。个人风格没有问题(我的风格也不完全符合Delphi RTL/VCL风格)。你得到了非常一致的风格。+1!