14

特定のユニットが Delphi プログラムにコンパイルされているかどうかを判断できるようにしたいと考えています。たとえば、ユニット SomeUnitName は、一部のプログラムの一部であり、他のプログラムの一部ではありません。機能をつけたい

function IsSomeUnitNameInProgram: boolean;

(もちろん SomeUnitName では宣言されていません。なぜなら、その場合は常に含まれるからです) 実行時に、ユニットがプログラムにコンパイルされている場合は true を返し、そうでない場合は false を返します。

これまでの私の考えは、jcl デバッグ情報 (詳細なマップ ファイルからコンパイルされたもの) を使用して、基本的にすべてのプログラムに追加してこの情報を判別するというものでしたが、jcl が必要ない場合は、それを使用することをお勧めします。

コードを SomeUnitName に追加することはできません。

これは現在 Delphi 2007 用ですが、できれば Delphi XE2 でも動作するはずです。

何かご意見は?

@DavidHeffernanが尋ねたので、これに関するいくつかの背景:

これは、1 つのプログラムだけでなく、100 以上の異なるプログラムに適用されます。それらのほとんどは社内で使用されますが、顧客に配布されるものもあります。私たちはかなりの数のライブラリを使用しているため、いくつかはさまざまなオープン ソース ライセンスの下で他のライブラリを購入したため、すべてではなく実際にプログラムにコンパイルされたライブラリのみを表示する「クレジット」タブをアバウト ボックスに追加できるようにしたいと考えました。TOndrej からの回答のおかげで、これは私が望んでいたとおりに機能するようになりました。プログラムでライブラリが使用されている場合、コードは常にリンクされているユニットをチェックし、そこにある場合は、ライブラリ名、著作権、およびアバウト ボックスにリンクします。

4

2 に答える 2

20

ユニット名は、検索できる「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 で実装を分析し、ユニットが見つかったときに列挙を停止する独自のバージョンを作成できます。)

于 2012-08-24T08:22:58.887 に答える
5

この関数は、アプリケーションに含まれるユニット名のリストを返します。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;
于 2012-08-24T09:31:53.243 に答える