How to adjust %PATH% for dynamically loaded native

2019-02-14 08:09发布

问题:

I'm loading dynamically a .NET assembly that depends on several bunches of native .dlls located in various folders. But Windows finds those DLLs only if their folders are in the PATH environment variable when my application is started.

I would like to modify my PATH variable from my program to allow finding the necessary libraries. According to MSDN "the search order is as follows: ... The directories that are listed in the PATH environment variable."

Which instance of the PATH environment variable is used?

Every process has an instance.
I tried Environment.SetEnvironmentVariable("PATH", ...) but it did not help. I also tried SetDefaultDllDirectories() together with AddDllDirectory() but these made no difference either.

The symptom is that when %PATH% contains the necessary folders when starting my .exe (from a CMD prompt – it is a console application), ProcessMonitor shows that the native .dlls are probed in all the PATH folders, and are eventually found.

But when %PATH% does not contain the necessary folders at the time of starting, then the native .dlls are probed in the .exe folder and in SYSTEM32 only (although %PATH% contains far more), regardless of the above-mentioned SetEnvironmentVariable()/SetDefaultDllDirectories()/AddDllDirectory() calls.

What is going here? What am I doing wrong? Why I cannot adjust the PATH for my process effectively?

Note: The AppDomain.AssemblyResolve event cannot help me because it's not fired when native .dlls load other native .dlls.

回答1:

That is because each process inherits its environment from the process that spawned it. And it didn't occur to the dit at Microsoft that something like PATH might change during the course of execution, so the CLR never refreshes the environment during process execution (and doesn't provide a means for the process to do so itself). See http://social.msdn.microsoft.com/Forums/vstudio/en-US/acf2d0f3-143e-4ba5-acdc-76a70a5c9830/environment-variables-refresh?forum=csharpgeneral for details.

Since the loader is resolving references to unmanaged DLLs via the normal Win32 way, you should probably look at P/Invoking these Win32 functions to alter the DLL search order used by the Win32 LoadLibrary() and LoadLibraryEx():

  • SetDllDirectory().

    Adds a directory to the search path used to locate DLLs for the application.

  • AddDllDirectory().

    Adds a directory to the process DLL search path.

  • SetDefaultDllDirectories().

    Specifies a default set of directories to search when the calling process loads a DLL.

  • RemoveDllDirectory().

    Removes a directory that was added to the process DLL search path by using AddDllDirectory.

See also DLL Search Order.