Как заставить мою программу искать определенные папки для зависимостей? - PullRequest
4 голосов
/ 27 октября 2010

Когда моя программа открывается, перед тем, как какой-либо из моих кодов действительно запустится, она автоматически попытается загрузить различные библиотеки DLL, функции которых она импортирует.Он выглядит в папке, в которой находится приложение, а затем в нескольких определенных местах, таких как \ Windows и \ Windows \ System32.

Если я хочу использовать некоторые пользовательские библиотеки DLL, но не хочу загромождатьвместе с ними в папке приложения, есть ли способ установить их в подпапку, а затем поместить в EXE-файл что-то, что подскажет, где искать?

Ответы [ 4 ]

3 голосов
/ 27 октября 2010

Вот все, что вам нужно знать о порядке поиска DLL .Будьте осторожны, чтобы не создавать проблемы с безопасностью.Если вы выполняете поиск в небезопасном месте, злоумышленник может поместить туда вредоносную DLL-библиотеку и заставить вашу программу загрузить и выполнить ее.

3 голосов
/ 27 октября 2010

Вы должны изменить PATH переменную окружения. Попробуйте использовать функцию SetDllDirectory(). В противном случае вам придется динамически загружать ваши DLL .

Также см. этот вопрос, чтобы избежать некоторых возможных проблем.

1 голос
/ 27 октября 2010

Как я уже сказал в моих комментариях к этому вопросу, если вы полагаетесь на статические зависимости и, следовательно, загружаетесь в Windows, то вы застряли на использовании стандартных способов поиска DLL в Windows. И если вы не хотите постоянно изменять путь окон, вы можете попробовать запустить приложение из файла bat / cmd и изменить путь непосредственно перед запуском приложения. AFAIK, который должен ограничивать изменение пути к экземпляру (длительности) cmd, начал выполнять файл bat / cmd.

Однако можно добиться большей гибкости, если вы сможете перейти на использование динамических зависимостей (удалить ваши bpls из необходимого списка?). Как и в случае с LoadLibrary, bpls, скомпилированные для использования пакетов времени выполнения, также могут загружаться динамически. Это то, на что полагаются большинство систем плагинов на основе Delphi bpl.

(Un). Загрузка bpls динамически выполняется с использованием (Un) LoadPackage. LoadPackage загружает пакет, указанный параметром Name (используя SafeLoadLibrary), проверяет наличие дубликатов модулей и вызывает блоки инициализации всех модулей, содержащихся в пакете.

Чтобы убедиться, что все процедуры Register в динамически загруженном bpl вызываются, вам нужно перечислить единицы измерения с помощью вызова GetPackageInfo, обеспечивающего функцию обратного вызова.

Кстати: примеры кода - это выдержки из системы плагинов, разработанной во время семинара динамических приложений Марком Миллером (разработчик / архитектор CodeRush) во время конференции 2001 года. Раньше код был онлайн, но я больше не могу его там найти ...

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;
1 голос
/ 27 октября 2010

Мне действительно нравится динамически загружаемая DLLS, и у меня просто есть модуль-обертка, чтобы я мог вызывать функции DLL, как если бы они были скомпилированы сразу. Я избегаю снижения производительности при загрузке / выгрузке все время, когда каждая функция-оболочка вызывает мой локальный LoadDLLLibrary, например:

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

Каждая из оболочек вызывает LoadDLLLibrary (которая фактически только что-то делает один раз), а затем вызывает 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 только один раз и выгружаю ее один раз. Очень удобно для библиотек DLL, которые загружаются динамически, но выполняются часто.

...