Saturday, 17 June 2017

Current Directory

The Current Directory (or Working Directory or Current Working Directoy) of a process is one of those topics that I seem to clearly understand, but after a while I partially forget and have to strive to rebuild it in my head, so I'll do a dump it here after that last build. I'm talking only about Windows, I guess the behaviour in Linux and the different UI Shells will be similar.

Every windows process has an associated Current Directory. This is the folder that the process will use as root for any relative path that it tries to access. You can see it with Process Explorer. So, how does a process get its working directory assigned?

The CreateProcess Win32 API function has a parameter to set the Current Directory. If NULL, the Current Directory of the parent process will be inherited. Higher level mechanisms used to create processes (and that ultimately make use of CreateProcess) will usually give you the option to provide the Current dDrectory (like in .Net with ProcessStartInfo).

OK, the above is good to know when we are writing a program that will launch another process, but how have the writers of common OS components handle this? meaning, how does this work when a program is started from the command line or Windows Explorer?

The Windows command line. cmd.exe has as Current Directory the folder where it is currently located. If you do a cd, the Current Directory will get updated accordingly. When you start a process from the command line, the process will inherit the Current Directory from cmd. This means that if you do this:

c:\Temp>cd c:\myAppFolder
c:\myAppFolder> myApp.exe

myApp.exe will have as working directory c:\myAppFolder

But if you do this:

c:\Temp>c:\myAppFolder\myApp.exe

myApp.exe will have as working directory c:\Temp

Windows Explorer. There are several ways in which you can launch a process from Windows Explorer (explorer.exe). Browsing to the folder containing the .exe file and double clicking on it, or typing the path to the exe in the Windows->Run window, is the same, Explorer will set up as Current Directory the folder where the .exe file is located.

An additional way to launch process from Windows Explorer is through a shortcut. If you check the properties of a shortcut you'll see a Start in field. If filled, that value will be used as Current Directory. If emtpy, Explorer will set the program's Current Directory to the folder where the shortcut is located (quite commonly the Desktop).

A process can easily change its working directory while running, by using the SetCurrentDirectory Windows API function. From .Net you can use the Directory.SetCurrentDirectory method.

As far as I know there is not a public API for changing the Current Directory of another process. The option that I've seen is pretty hackerish, injecting a dll in that process and invoking SetCurrentDirectory from its entry point.

As far as I know, by default Windows Services get as Current Directory C:\Windows\System32\, I guess because they inherit it from services.exe

Finally, there's an interesting quirk to bear in mind with .NET applications. The standard configuration system (the old school System.Configuration.ConfigurationManager, previous to the introduction in .Net Core of the much more advanced Microsoft.Extensions.Configuration) is pretty smart and does not use the Current Directory to locate the myApp.config file that has to be located next to myApp.exe, it will get the folder containing our binary and search the app.config in it, so in terms of configuration you don't care about the Current Directory and whether your app is started via explorer or from the command line or from another process. If you move to using a different kind of config file placed also next to your binary, you'll have to start to consider that the Current Directory could have different values and is not a reliable way to get the file.

No comments:

Post a Comment