28

I'm a .NET user, and my goal is as simple as finding the absolute path of the directory of my main executing assembly (the EXE file).

I have several candidates:

  • Assembly.GetExecutingAssembly().CodeBase
  • Assembly.GetExecutingAssembly().Location
  • AppDomain.CurrentDomain.BaseDirectory

If to judge by the .NET documentation - I'm leaning towards CodeBase. Can anyone shed light over all three in a bit more specific terms than the .NET documentation? An example to demonstrate the difference perhaps?

shA.t
  • 16,580
  • 5
  • 54
  • 111
tsemer
  • 2,959
  • 3
  • 29
  • 26
  • I've found [this post](http://knitinr.blogspot.it/2008/07/systemreflection-get-this-assembly.html) as a good explanation of the different Assembly methods. – mcont Apr 15 '15 at 12:07

5 Answers5

17

I would use GetEntryAssembly() instead of GetExecutingAssembly().

To see why, do this:

  • Create a new Console Project
  • Add a class library project (ClassLibrary1) to the solution and reference it from the Console Project.

Put this in ClassLibrary1:

namespace ClassLibrary1
{
    using System;
    using System.IO;
    using System.Reflection;

    public class Class1
    {
        public void GetInfo(int n)
        {
            Assembly asm = Assembly.GetEntryAssembly();
            Console.WriteLine("[GetEntryAssembly {0}] Location:{1}", n, Path.GetDirectoryName(asm.Location));
            asm = Assembly.GetExecutingAssembly();
            Console.WriteLine("[GetExecutingAssembly() {0}] Location:{1}", n, Path.GetDirectoryName(asm.Location));
        }
    }
}

Put this in console's Program.cs:

namespace ConsoleApplication4
{
    using System;
    using System.IO;
    using System.Reflection;
    using ClassLibrary1;

    class Program
    {
        static void Main(string[] args)
        {
            Assembly asm = Assembly.GetEntryAssembly();
            Console.WriteLine("[GetEntryAssembly() 1] Location:{0}", Path.GetDirectoryName(asm.Location));
            asm = Assembly.GetExecutingAssembly();
            Console.WriteLine("[GetExecutingAssembly() 1] Location:{0}", Path.GetDirectoryName(asm.Location));

            Class1 obj1 = new Class1();
            obj1.GetInfo(2);

            asm = Assembly.LoadFile(@"C:\temp\ClassLibrary1.dll");
            Type t = asm.GetType("ClassLibrary1.Class1");
            object obj2 = asm.CreateInstance("ClassLibrary1.Class1");
            t.GetMethod("GetInfo").Invoke(obj2, new object[] { 3 });

            Console.ReadKey();
        }
    }
}

Build the solution, copy ClassLibrary1.dll to c:\temp and run.

As you will see, GetExecutingAssembly() may trick you in certain conditions.

One last note, if your app is a Windows Forms one, you can just use Application.ExecutablePath.

shA.t
  • 16,580
  • 5
  • 54
  • 111
Sorin Comanescu
  • 4,829
  • 3
  • 29
  • 38
  • Good one, thanks, I adopt the change! But how about Assembly.CodeBase vs AppDomain.BaseDirectory? – tsemer Oct 29 '09 at 14:08
  • 17
    It'd be nice if you posted the output instead of making one compile and run it to see your point :-) – Pat Nov 04 '10 at 23:15
  • 17
    Assembly.GetEntryAssembly is not reliable, specifically it will return null if the application started in an unmanaged context instead of a managed context. The result must be null checked. – clemahieu May 03 '11 at 15:44
  • outpout is : [GetEntryAssembly() 1] Location:C:\Users\bob\Documents\Visual Studio 2017\Projects\myapp\myapp\bin\Debug [GetExecutingAssembly() 1] Location:C:\Users\bob\Documents\Visual Studio 2017\Projects\myapp\myapp\bin\Debug [GetEntryAssembly() 2] Location:C:\Users\bob\Documents\Visual Studio 2017\Projects\myapp\myapp\bin\Debug [GetExecutingAssembly()2] Location:C:\Users\bob\Documents\Visual Studio 2017\Projects\myapp\myapp\bin\Debug [GetEntryAssembly() 3] Location:C:\Users\bob\Documents\Visual Studio 2017\Projects\myapp\myapp\bin\Debug [GetExecutingAssembly() 3] Location:C:\temp – Antoine Meltzheim Sep 11 '17 at 12:24
16

I'm not sure about AppDomain.CurrentDomain.BaseDirectory, but the difference between Assembly.GetExecutingAssembly().CodeBase and Assembly.GetExecutingAssembly().Location was explained in this blog post.

The CodeBase is a URL to the place where the file was found, while the Location is the path from where it was actually loaded. For example, if the assembly was downloaded from the internet, its CodeBase may start with "http://", but its Location may start with "C:\". If the file was shadow copied, the Location would be the path to the copy of the file in the shadow-copy dir.

It’s also good to know that the CodeBase is not guaranteed to be set for assemblies in the GAC. Location will always be set for assemblies loaded from disk, however.

So it seems your best bet is Location if you need the real directory the file was executed from.

René
  • 9,880
  • 4
  • 43
  • 49
8

Unfortunately, all the methods above can fail if you use a virtualization like XenoCode postbuild. I have tested many methods and found another solution here. I've found that only the

System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".exe"

returns the correct filename of the executable. So combining the filename with the path from Assembly.GetEntryAssembly().Location you will get the correct path of the executable.

Community
  • 1
  • 1
Alexander Zwitbaum
  • 4,776
  • 4
  • 48
  • 55
0

From: http://msdn.microsoft.com/en-us/library/system.reflection.assembly.codebase.aspx

Assembly.CodeBase

To get the absolute path to the loaded manifest-containing file, use the Assembly.Location property instead.

If the assembly was loaded as a byte array, using an overload of the Load method that takes an array of bytes, this property returns the location of the caller of the method, not the location of the loaded assembly.

For AppDomain.CurrentDomain.BaseDirectory, I honestly have no idea about the differences from a practical point of view.

o.k.w
  • 25,490
  • 6
  • 66
  • 63
  • I actually need where the exe file was intended to be executed from, and not it's actual location, so I guess I'll stick with CodeBase :) thanks for the pointer though. – tsemer Oct 29 '09 at 14:07
-4

Use System.Linq

string MainExecutablePath= (System.Diagnostics.Process.GetProcesses().First(P =>P.MainWindowTitle == "MainExecutable'sWindowName")).MainModule.FileName.ToString();
  • 5
    Thanks for you answer. Improvements: Linq can be replaced with `GetCurrentProcess()` (as mentioned by @Shurup), and FileName is already a string so no need for `ToString()` :) So: `System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName` – tsemer Feb 19 '14 at 10:02