4

プログラムを開くと、コードが実際に実行される前に、プログラムがインポートする関数を持つさまざまなDLLを自動的にロードしようとします。アプリが含まれているフォルダーを検索し、次に\Windowsや\Windows\System32などの特定の場所を検索します。

いくつかのカスタムDLLを使用したいが、アプリのフォルダーをそれらで乱雑にしたくない場合、それらをサブフォルダーにインストールしてから、どこを見ればよいかを指示する何かをEXEに入れる方法はありますか?

4

4 に答える 4

3

PATH環境変数を変更する必要があります。関数を使ってみてくださいSetDllDirectory()。それ以外の場合は、DLL を動的にロードする必要があります。

また、この質問を参照して、さらに起こりうる問題を回避してください。

于 2010-10-27T17:38:03.293 に答える
3

DLL の検索順序について知っておくべきことはすべてここにあります。セキュリティ上の問題を引き起こさないように注意してください。セキュリティで保護されていない場所を検索すると、攻撃者はそこに悪意のある DLL を配置し、プログラムにそれをロードして実行させることができます。

于 2010-10-27T17:49:48.210 に答える
1

質問へのコメントで述べたように、静的な依存関係に依存しているためにWindowsでロードしている場合は、Windowsがdllを検索する標準的な方法を使用することに固執します。また、Windowsのパスを永続的に変更したくない場合は、bat / cmdファイルからアプリを実行して、アプリを起動する直前にパスを変更してみてください。cmdインスタンス(の期間)へのパスの変更を制限する必要があるAFAIKは、bat/cmdファイルの実行を開始しました。

ただし、動的依存関係の使用に変更できる場合は、より柔軟性を得ることができます(必要なリストからbplsを削除しますか?)。LoadLibraryと同様に、ランタイムパッケージを使用するようにコンパイルされたbplsも動的にロードできます。これは、ほとんどのdelphibplベースのプラグインシステムが依存しているものです。

(Un)bplsの動的なロードは、(Un)LoadPackageを使用して行われます。LoadPackageは、Nameパラメーターで指定されたパッケージを(SafeLoadLibraryを使用して)ロードし、重複するユニットをチェックして、パッケージに含まれるすべてのユニットの初期化ブロックを呼び出します。

動的にロードされたbpl内のすべてのRegisterプロシージャが呼び出されるようにするには、コールバック関数を提供するGetPackageInfo呼び出しを使用してユニットを列挙する必要があります。

ところで:コードサンプルは、2001年の会議でMark Miller(CodeRushの開発者/アーキテクト)が動的アプリケーションワークショップで開発したプラグインシステムからの抜粋です。コードは以前はオンラインでしたが、もう見つかりません...

var
  localModuleHandle: HModule;
begin
  try
    localModuleHandle := LoadPackage(packageName);

    //GetPackageInfo accesses the given package's info table and enumerates
    //  all the contained units and required packages 
    Flags := ufAllUnits;
    GetPackageInfo(localModuleHandle, Pointer(localModuleHandle), Flags, PackageIsLoadingProc);
  except
    on e: Exception do
      Application.MessageBox(PChar(e.Message), PChar(sError), MB_OK + MB_ICONWARNING);
  end;  
end;

procedure PackageIsLoadingProc(const Name: string; NameType: TNameType;
                               Flags: Byte; Param: Pointer);
type
  TRegisterProc = procedure;
var
  RegisterProc: TRegisterProc;
  localName: String;
begin
//  Flags:
//  ufMainUnit = $01;
//  ufPackageUnit = $02;
//  ufWeakUnit = $04;
//  ufOrgWeakUnit = $08;
//  ufImplicitUnit = $10;
//  ufWeakPackageUnit = ufPackageUnit or ufWeakUnit;

  if NameType = ntContainsUnit then
    begin
      localName := LowerCase(Name);
      if Length(localName) > 0 then
        localName[1] := UpCase(localName[1]);

      @RegisterProc := GetProcAddress(HModule(Param), 
                                      PChar('@' + localName + '@Register$qqrv'));
      if @RegisterProc <> nil then
        RegisterProc;
    end;
end;
于 2010-10-27T19:35:34.287 に答える
1

私は動的に読み込まれる DLL が実際に好きで、ラッパー ユニットがあるだけなので、DLL 関数をあたかもコンパイルされているかのように呼び出すことができます
。このような:

function LoadDLLLibrary: Boolean;
begin
  if MyDLLLib = 0 then
    MyDLLLib := LoadLibrary('path to my dll');   // Only load it once.
  Result := MyDLLLib <> 0;
end;

各ラッパーは LoadDLLLibrary を呼び出し (実際には 1 回だけ実行します)、次に GetProcAddress を呼び出します。こんな感じです:

procedure DoSomeDLLStuff;
var
  DLLProc: TExecuteDoSomeDLLStuffProc;
begin
  LoadDLLLibrary;
  try
    if MyDLLLib <> 0 then
    begin
      DLLProc := GetProcAddress(MyDLLLib , PROC_SomeDLLSTuff);
      DLLProc;  // run it
    end;
  finally
    // No need to unload, it'll get unloaded in finalization.
  end;
end;

しかもどん底まで……。

initialization
  MyDLLLib := 0;

finalization
  UnLoadDLLLibrary;  // Final unload, as we let it stick around instead of freeing it all the time.
end.

したがって、最終的には、DLL を 1 回だけロードし、1 回アンロードします。動的に読み込まれるが、頻繁に実行される DLL に非常に便利です。

于 2010-10-27T18:19:20.440 に答える