#1 2026-07-10 08:07:55

zed
Member
Registered: 2015-02-26
Posts: 123

Usage of SetDllDirectoryW within the framework

In my application, I encountered an issue with mORMot 2: dynamically loading libcurl via LibCurlInitialize([giAll], 'libcurl-4.dll') results in a call to SetDllDirectoryW(nil). This breaks subsequent LoadLibrary calls for loading third-party DLLs. The problem arises because my application calls SetDllDirectoryW at startup to set a global DLL directory.

After analyzing the DLL loading algorithm in mORMot 2, I would like to propose a few improvements:

1. When loading libcurl, use the TryFromExecutableFolder option instead of forcibly appending the absolute path Executable.ProgramFilePath + dllname (which, by the way, is done without checking whether dllname is relative or absolute).

// mormot.lib.curl
procedure LibCurlInitialize
...
  curl := TLibCurl.Create;
  {$ifdef OSWINDOWS}
  curl.TryFromExecutableFolder := True;                     // << fix
  {$endif OSWINDOWS}
  curl.TryLoadResolve([    
    //{$ifdef OSWINDOWS}
    // first try the libcurl.dll in the local executable folder
    //Executable.ProgramFilePath + dllname,           // << fix
    //{$endif OSWINDOWS}
    // search standard library in path
    dllname
    ...

2. Inside TryLoadLibrary, invoke LibrarySetDirectory only if the path differs from Executable.ProgramFilePath.

// mormot.core.os
function TSynLibrary.TryLoadLibrary
...
  if (nwd <> '') and (nwd <> Executable.ProgramFilePath) then                       // << fix
  begin
    GlobalLock; // SetDllDirectoryW() is for the whole process not thread
    if not LibrarySetDirectory(nwd) then // as documented on microsoft.com
    begin
      GlobalUnLock;
      nwd := '';
    end;
  end else 
    nwd := '';                            // << fix

3. Add a global variable LibraryUseSetDllDirectory to mormot.core.os to allow completely disabling SetDllDirectoryW within the framework.

// mormot.core.os
var
  LibraryUseSetDllDirectory: boolean; // = False by default

Last edited by zed (2026-07-10 08:12:53)

Offline

#2 2026-07-24 17:35:01

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 15,564
Website

Re: Usage of SetDllDirectoryW within the framework

Sorry for being late, but I looked back at this post.
And I am confused.

1) has no difference with the existing code.

2) I don't think it is how it is supposed to work

3) this I can understand: if you call LibrarySetDirectory() manually, then you don't want to have the framework code interferring...
BUT what I don't get is that LibrarySetDirectory() is recursive and we properly call LibrarySetDirectory(nil) with GlobalLock/Unlock to ensure it won't conflict anywhere.

So my first fix/improvement is to add a TSynLibrary.DisableLibrarySetDirectory property for each instance:
https://github.com/synopse/mORMot2/commit/a573d477f

Then a new DefaultDisableLibrarySetDirectory global variable, used as default for TSynLibrary.DisableLibrarySetDirectory property value on Windows:
https://github.com/synopse/mORMot2/commit/d26c74a04

Offline

#3 2026-07-26 09:03:36

zed
Member
Registered: 2015-02-26
Posts: 123

Re: Usage of SetDllDirectoryW within the framework

Thank you!

The issue is that calling SetDllDirectoryW(nil) resets the DLL search path to the default, not to the value that was set previously. In other words, I call SetDllDirectoryW('DirA'), then mORMot calls SetDllDirectoryW('DirB') followed by SetDllDirectoryW(nil), and as a result Windows no longer searches my "DirA".

This is a limitation of the legacy SetDllDirectory API, which is exactly why the newer AddDllDirectory / RemoveDllDirectory APIs were introduced.

Offline

Board footer

Powered by FluxBB