Where did my StartupPath go?

So somebody has just asked where Application.StartupPath has disappeared in WPF. This is available in Windows Forms, but not available in WPF. A common technique to get the startup path is to use Assembly.GetEntryAssembly().Location, but there’s a problem with GetEntryAssembly if your app is fired off from an unmanaged application, such as a COM application for instance.

We have a couple of applications where our executable is fired off as a result of unmanaged processing – primarily when processing image data that’s been collected and checkpointed by some native code. We’ve found that GetEntryAssembly is null in this instance, whereas the following method works fine.

Now one way that you could add this in would be to add a reference to System.Windows.Forms into your project and then call it from there – however, there’s a way that you can do it without needing to go anywhere near WinForms just by adding a few lines of code. Here it is – in all its glory.

public static class Utility
{
  [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
  public static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);

  private static string startupPath;
  private static HandleRef NullHandleRef = new HandleRef();

  public static string StartupPath()
  {
    if (startupPath == null)
    {
      StringBuilder buffer = new StringBuilder(260);
      GetModuleFileName(NullHandleRef, buffer, buffer.Capacity);
      startupPath = Path.GetDirectoryName(buffer.ToString());
    }
    new FileIOPermission(FileIOPermissionAccess.PathDiscovery, startupPath).Demand();
    return startupPath;
  }
}

As you can see, the code merely wraps up a call to GetModuleFileName, it’s that simple.

Note – since posting this, one of my fellow WPF Disciples handed over the following code which should work as well:

startupPath = (Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly()).Location

6 thoughts on “Where did my StartupPath go?

  1. mihailik

    >> Assembly.GetExecutingAssembly()

    I’d not trust your fellows that much. With an odd second or two of contemplating one might have guessed the meaning of Get Executing Assembly phrase.

  2. mihalik,

    I was that fellow, and there’s nothing wrong with that code. I understand precisely what GetExecutingAssembly does. Note that it’s a fallback when GetEntryAssembly returns null, and yes, there’s edge cases in which this solution won’t work.

    The AppDomain solution was discussed as well. That solution works so long as you’ve got a single AppDomain, so it has edge cases it fails for as well. Peter actually has the only solution that will always work. The other two solutions are nice to know about if you want to avoid interop, but you have to know when they will fail and why.

  3. mihailik

    wekempf,

    GetExecutingAssembly is as good a fallback as Environment.GetTempPath() — returning a valid path to an arbitrary folder.

    The beauty of AppBase is that its meaning is exactly ‘application path’ for all purposes. Whoever creates an AppDomain decides on it, and it works consistently and uniformly throughout .NET API from BCL to WinForms to ASP.NET.

    However, if one is to seek where a process image lives, there is a perfectly canonic path to enlightenment, which is Process class.

  4. mihalik,

    You’re being argumentative, and rather insulting to boot, when comparing GetExecutingAssembly as equivalent to Environment.GetTempPath. Hard to have a reasonable discourse under those circumstances, so I’ll bow out of this conversation. You’re the smarter man, and all that rot.

  5. Hi,

    There’s no need to use P/Invoke to get the Startup Path with WPF… You could just check the BaseDirectory property of the AppDomain.CurrentDomain.

    string startupPath = AppDomain.CurrentDomain.BaseDirectory;

    Regards,
    Caio Proiete

Leave a comment