57

I've got a C# project (call it MainProj) which references several other DLL projects. By adding these projects to MainProj's references, it will build them and copy their resulting DLL's to MainProj's working directory.

What I'd like to do is have these referenced DLL's be located in a subdirectory of MainProj's working directory, i.e. MainProj/bin/DLLs, rather than the working directory itself.

I'm not a very experienced C# programmer, but coming from the C++ world, I'm assuming one approach would be to remove the project references and explicitly load the required DLL's by path and filename (i.e. in C++, LoadLibrary). What I'd prefer to do however, if there's a way, would be to set some sort of "reference binary path", so they'd all be auto-copied to this subdir when I build (and then be referenced from there without me needing to explicitly load each). Is such a thing possible?

If not, what's the preferred method in C# to accomplish what I'm after (i.e. something with Assembly.Load / Assembly.LoadFile / Assembly.LoadFrom? Something in AppDomain perhaps, or System.Environment?)

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
J23
  • 3,061
  • 6
  • 41
  • 52

3 Answers3

89

From this page (untested by me):

Somewhere in your program's initialization (before you access any classes from a referenced assembly) do this:

AppDomain.CurrentDomain.AppendPrivatePath(@"bin\DLLs");

Edit: This article says AppendPrivatePath is considered obsolete, but also gives a workaround.

Edit 2: Looks like the easiest and most kosher way to do this is in the app.config file (see here):

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="bin\DLLs" />
    </assemblyBinding>
  </runtime>
</configuration>
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Aaron
  • 2,013
  • 16
  • 22
  • 1
    App.config method works great, but it seems to need the xml namespace xmlns="urn:schemas-microsoft-com:asm.v1" or it will not work. I can't believe they dont have this method in the link that Rami posted. – Despertar May 12 '12 at 04:30
  • Uhmm...how can this be done in C++ way? ( I'm using MinGW with Code::Blocks ) – mr5 May 27 '13 at 11:03
  • 2
    no,both of them doesn't work ,but this post:http://stackoverflow.com/questions/11410940/loading-dlls-from-path-specified-in-setdlldirectory-in-c-sharp,works. – zionpi Jun 07 '13 at 05:46
  • 1
    @zionpi, you are talking bout unmanaged (C) DLLs. The other Solutions work with managed (.NET) DLLs – oo_dev Sep 08 '14 at 11:05
  • 7
    One limitation of this method is that the folder specified in privatePath must be a subfolder of the application's base folder (where the exe is located). See http://stackoverflow.com/questions/9536256/using-an-absolute-path-in-probing-privatepath. Trying to specify a folder outside of that parent will fail. – Steve In CO Aug 10 '15 at 14:52
  • I added this to my App.config – sliders_alpha Nov 04 '16 at 11:20
  • The MSDN KB posted by Rami A. is incorrect, although it has a link at the bottom to the correct page. The one posted above is for using the element. This one also includes the use of the element: https://msdn.microsoft.com/en-us/library/4191fzwb(vs.71).aspx – tbradt Feb 08 '18 at 19:18
  • Are AppConfig settings baked into a .exe at compile time, or do I need to distribtue the AppConfig file with the binary? – FoxDeploy Jun 20 '18 at 15:20
30

From Tomek answer at: Loading dlls from path specified in SetdllDirectory in c#

var dllDirectory = @"C:/some/path";
Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";" + dllDirectory)

It works perfectly for me!

Community
  • 1
  • 1
Pedro77
  • 5,176
  • 7
  • 61
  • 91
  • Can we give a reason for down voting as well? It'd be nice to know why. – Hexum064 Sep 15 '14 at 15:21
  • Because this will load the DLLs dynamically. The referenced DLLs will still be loaded from the same folder as the executable. Any DLLs loaded AFTER this call will be loaded from the folder provided in this call. – Anshul Sep 15 '14 at 19:16
  • It works and I don't need to copy GB of dlls to my bin folder. It has some drawbacks, but may be useful in some cases. – Pedro77 Sep 15 '14 at 19:47
  • Modifying the App.config file didn't work for me. Your answer is the only one that worked for my winform project. – Maxter Feb 28 '23 at 15:01
13

Here is an other way to proceed without using obsolete AppendPrivatePath. It catches a kind of event "associated dll not found" (so it will be called only if the dll is not found in the default directory).

Works for me (.NET 3.5, not tested other versions)

/// <summary>
/// Here is the list of authorized assemblies (DLL files)
/// You HAVE TO specify each of them and call InitializeAssembly()
/// </summary>
private static string[] LOAD_ASSEMBLIES = { "FooBar.dll", "BarFooFoz.dll" };

/// <summary>
/// Call this method at the beginning of the program
/// </summary>
public static void initializeAssembly()
{
    AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs args)
    {
        string assemblyFile = (args.Name.Contains(','))
            ? args.Name.Substring(0, args.Name.IndexOf(','))
            : args.Name;

        assemblyFile += ".dll";

        // Forbid non handled dll's
        if (!LOAD_ASSEMBLIES.Contains(assemblyFile))
        {
            return null;
        }

        string absoluteFolder = new FileInfo((new System.Uri(Assembly.GetExecutingAssembly().CodeBase)).LocalPath).Directory.FullName;
        string targetPath = Path.Combine(absoluteFolder, assemblyFile);

        try
        {
            return Assembly.LoadFile(targetPath);
        }
        catch (Exception)
        {
            return null;
        }
    };
}

PS: I did not managed to use AppDomainSetup.PrivateBinPath, it is too laborious.

56ka
  • 1,463
  • 1
  • 21
  • 37
  • This worked great for me. I am working with a dll and am not the author of the exe, so I needed a way to do this without modifying the config file. Thanks! – Christopher Haws Jan 11 '16 at 01:34