Deciphering the MSI Directory table, part 6 (standard directories)

Before picking up this series of blog entries on the Directory table again, I went back and re-read all the previous entries to make sure I remembered the details told up to this point.  It was then that I realized the last entry on this series as posted over 11 months ago.  What disturbed me even more than the fact that I didn't realize I had dropped this series for so long (I thought I had posted in the last three months) was this quote:

The first paragraph of part 1 surprised me because it reminded me how long I've been operating under frustration.

For some people this blog series will be deciphering the MSI Directory table.  For me this blog series will provide guide posts for a path I should never follow again.  But enough of that.  Let's get to the point and talk about standard directories in the Directory table.

As always I'm going to start with some example data.  If this stuff doesn't look familiar (that's okay, it's been almost a year) I suggest going back and (re)reading part 5.  Here's a Directory table modified from our part 5.

 Directory           Directory_Parent      DefaultDirs
s72                 S72                   l255
Directory           Directory
TARGETDIR                                 SourceDir
ProgramFilesFolder  TARGETDIR             PFiles
FirstFolder         ProgramFilesFolder    One

Based on what we've learned thus far, you should expect that Directory table to create the following layouts:

 Target layout
ProgramFilesFolder = TARGETDIR\PFiles\
FirstFolder        = TARGETDIR\PFiles\One\

Source layout
ProgramFilesFolder = SourceDir\PFiles\
FirstFolder        = SourceDir\PFiles\One\

You'd be half correct.  The source layout would look exactly like that.  However, the target layout would be quite different.  The magic is in the ProgramFilesFolder identifier.  That's because ProgramFilesFolder is what I call a standard directory.  The MSI SDK has the full list of standard directories.

So how does it work? 

Well, when the Windows Installer scans the Directory table, it converts the standard directory identifiers into the appropriate paths on the machine.  For example, ProgramFilesFolder turns into the value returned by ::SHGetFolderPath() for CSIDL_PROGRAM_FILES which is usually something like "C:\Program Files\".  The LocalAppDataFolder identifier is the value returned for CSIDL_LOCAL_APPDATA which is usually something like "C:\Documents and Settings\username\Local Settings\Application Data\".

That means that our target layout actually looks something like this:

 Target layout
ProgramFilesFolder = ProgramFiles\
FirstFolder        = ProgramFiles\One\

Note: "ProgramFiles" is intended to represent wherever "C:\Program Files\" actually exists on the user's machine. You should never expect ProgramFiles to be on the C: drive or even in "Program Files". I say this because the "Program Files" string is localized, that'll getcha' for sure.

This means that the FirstFolder directory will always be under ProgramFilesFolder.  Next time we'll see how to allow the user to configure where your application gets installed.  In the meantime, I would encourage you to take a look at that list of standard directories the Windows Installer provides you.