7

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.

robert4
  • 1,072
  • 15
  • 20
  • When you say native dll's - are you talking about 3rd party assemblies, framework assemblies or windows API dll's? – Jay Feb 11 '14 at 20:01
  • I suspect a bug in your code; if you post it we might be able to help. However, rather than messing around with PATH, I think it would be preferable to explicitly load the requisite DLLs yourself before loading the assembly. – Harry Johnston Feb 11 '14 at 20:02
  • @Jay: I'm talking about 3rd party assemblies – robert4 Feb 11 '14 at 21:52
  • @Harry Johnston: I cannot load all the requisite dlls in advance because they're too numerous and I don't know what are the preconditions of their loading. They belong to a complex native application that has a limited .NET API. – robert4 Feb 11 '14 at 21:55
  • `Environment.SetEnvironmentVariable` might (I've never checked) only set the CLR's copy of the environment variables rather than the native environment variables. You could try P/Invoking the Win32 `SetEnvironmentVariable` function instead. – Harry Johnston Feb 11 '14 at 22:15
  • @Harry Johnston: I checked it (with Reflector): it calls `kernel32!SetEnvironmentVariable()` with P/Invoke. Regarding the potential bug, I hope will be able to get back tomorrow with a simplified source-code. Thanks – robert4 Feb 12 '14 at 00:54

1 Answers1

6

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():

See also DLL Search Order.

Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
  • 1
    You are talking about changing the PATH in the registry and it won't be visible in the process. I know that, and I didn't to do that. I changed the PATH in the CMD.EXE process from which I started my .exe. That worked. Then I tried to change the PATH in my process, that had no effect (although changed). I also tried the above P/Invoke ways, as I described, with no help. – robert4 Feb 11 '14 at 21:52
  • 2
    I had a similar problem and it was resolved by using SetDllDirectory. Did not know about this before, thanks for your answer! – SWilliams Apr 28 '15 at 16:14