Shalom Craimer
Shalom Craimer

Reputation: 21449

Adding a directory temporarily to Windows 7's DLL search paths

I want to temporarily add a directory to the DLL search paths - is there a correct way to do this under Windows 7?

Scenario

I've got a C# application, let's call it WonderApp.

WonderApp needs to call a C++ DLL, located in C:\MyPath. So as part of WonderApp's Program.Main(), I added the following command:

Environment.SetEnvironmentVariable("PATH",
   "C:\\MyPath;" + Environment.GetEnvironmentVariable("PATH"));

According to this article, adding a directory to the PATH should also add it to the directories search for DLLs.

The solution works fine in Windows XP: if I add the directory to the PATH, the DLL loads and the program works just fine. If I don't add the directory, the DLL doesn't load, failing with a "not found" error.

However, this doesn't work for Windows 7.

So I figured, let's try using SetDllDirectory(). Like this:

[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetDllDirectory(string lpPathName);

And, later on:

 bool success = SetDllDirectory(Util.Paths.GetApplicationDataDir());

The value of success is true, but the DLL still fails to load.

Finally, if I set the PATH to include C:\MyPath manually, before running the application - it all works! The DLL loads, and runs just fine.

So, to re-iterate:

Is there a correct way to temporarily add a directory to the DLL search paths under Windows 7?

UPDATE: Using Process Explorer, I checked the application's run-time Environment, and "C:\MyPath" was indeed in the PATH! Furthermore, I saw that Helper.dll was in the list of open handles (as a DLL, not just a file) - and it still claimed not to find it.

Upvotes: 7

Views: 6074

Answers (3)

Rich
Rich

Reputation: 15448

You can add custom DLL loading logic to a C# app using the 'AssemblyResolve' event.

This page has a good summary, with code samples: http://support.microsoft.com/kb/837908

Just as you did, I have found that changing the PATH environment variable of a running C# app does not affect the DLL search behaviour. Perhaps the AppDomain caches the PATH value at startup? You can use the AssemblyResolve event to work around this.

See also How to add folder to assembly search path at runtime in .NET?

Upvotes: 2

Shalom Craimer
Shalom Craimer

Reputation: 21449

My solution is simple, but I feel ridiculous resorting to it.

I've written another assembly, "Shell", that modifies the Environment, runs WonderApp, and exits.

By modifying the PATH before running the main application (WonderApp), the main application's DLL search-path includes the directories added to the modified PATH.

It looks like this:

namespace shell
{
   static class program
   {
      [dllimport("kernel32.dll", charset = charset.auto, setlasterror = true)]
      public static extern bool setenvironmentvariable(string lpname, string lpvalue);

      private static string joinargstosinglestring(string[] args)
      {
         string s = string.empty;
         for (int i = 0; i < args.length; ++i)
         {
            if (!string.isnullorempty(s))
            {
               s += " ";
            }
            s += "\"" + args[i] + "\"";
         }
         return s;
      }

      [stathread]
      static void main(string[] args)
      {    
         string pathbefore = environment.getenvironmentvariable("path");
         string wewant = util.paths.getapplicationdatadir() + ";" + pathbefore;
         setenvironmentvariable("path", wewant);

         Process process = Process.Start(".\\WonderApp.exe", joinArgsToSingleString(args));
      }
   }
}

I wish I could find a better solution!

Upvotes: 0

MQS
MQS

Reputation: 413

I am thinking it has to do with permission problems.

Try turning off UAC and running your code again. Check to see if updating the path worked.

If it did, at least you know where to start...

Upvotes: 1

Related Questions