The SHGetFolderPath Explorer

Home
Back To Tips Page

There are any number of interesting folders that don't really exist in Windows.  They are "virtual folders", a fiction of the Shell environment.  To access them, you need to use the actual path. 

The SHGetFolderPath Explorer allows you to see what code you would need to write to access these folders.

One of the questions is why you need to do this.  The table below captures some of the more common usages.

SHGetFolderPath parameter Usage
CSIDL_APPDATA
C:\Documents and Settings\userid\Application Data

Per-user application data.  In particular, user settings which are not saved in the Registry but in configuration files. Do not store such information in the executable directory, or in the Windows directory or any subdirectory of the Windows Directory.  In some installations, these directories will be write-protected, particularly under Vista.  And if you were to use them, the settings would end up being shared by all users, so any user would be changing the settings for other users.  This is not good practice.

CSIDL_COMMON_APPDATA
C:\Documents and Settings\All Users\Application Data

Per-installation application data.  Be careful because this can only typically be set at install time by someone with Administrator privileges.  Would hold per-site common settings shared by all users.  Would typically be modified only by an Administrative users.

CSIDL_MYPICTURES
C:\Documents and Settings\userid\My Documents\My Pictures

The canonical repository of pictures for the logged-in user.

CSIDL_PERSONAL
C:\Documents and Settings\userid\My Documents

The canonical repository of documents for the logged-in user.

CSIDL_WINDOWS
C:\WINDOWS

The %SYSTEMROOT% directory.  This represents the partition from which the current version of Windows was booted (note on multiboot or multiuser machines, you cannot depend on this being called "C:\Windows", and you must use this option to get the correct path.  This directory is rarely needed in practice; if you are using it, consider very carefully if you should be touching it at all.  Win16 programmers in particular developed extremely bad programming habits about relying on being able to read and write files in this directory.

This option replaces the GetWindowsDirectory API call, which is now considered deprecated.

CSIDL_SYSTEM
C:\WINDOWS\System32

The Windows System directory.  This is always relative to the CSIDL_WINDOWS path, and you cannot depend on what this value is on multiboot or multiuser machines. As with CSIDL_WINDOWS, it is extremely rare in practice that you would ever need this path, and you must consider very carefully why you are doing it.  It should not be used at all in most programs.

This option replaces the GetSystemDirectory API call, which is considered deprecated.

CSIDL_... There are many other CSIDL_ directory names, and their use is highly specialized.  Most programmers should stay away from most of them, unless you are actively writing a program to use or modify them.  The SHGetFolderPath Explorer allows you to see what they would be.  You can read about these in the SHGetFolderPath documentation

You will typically want to append your file name to the path thus obtained.  This is often most easily accomplished by using the PathAppend function which is defined in <shlwapi.h> (don't forget to link with shlwapi.lib).  For example, in the illustration shown below, the success path would be modified to add the PathAppend:

{ /* succeeded */
 ::PathAppend(p, _T("MyData.dat"));
 path.ReleaseBuffer();
 ... use path variable here
} /* succeeded */

This would take the result of CSIDL_APPDATA and append MyData.dat to it, making sure there was a \ inserted (if the first parameter string already ends in a \, no additional one is created).  For the example below, it would produce

C:\Documents and Settings\administrator.KIRTLAND2.000\Application Data\MyData.dat
|<------------------------from CSIDL_APPDATA------------------------>|^|<---+-->|
                (the first parameter to PathAppend)                   |     |
                 provided by PathAppend because one was not present---+     |
                                       the second parameter to PathAppend---+

Running SHGetFolderPath Explorer

The CSIDL dropdown selects which directory you want to examine or create.  The Environment window selects if the code being generated is going to be C or MFC-based code. The Path window (which is an edit control you can highlight and copy) shows the actual directory path retrieved, or, if there is an error encountered, displays an error message.

The most common error is that the specialized folder does not exist.  You can force one to be created by combining the CSIDL_CREATE flag in as part of the first parameter.  Although the code will show it, it will not actually do the creation unless you click the Create button to force the creation of the directory.

The Flags options allow you to choose which of the supported flag values you wish to select.

The Copy button will copy the entire contents of the Code display to the clipboard.  Note that the Code display includes text to be included in your stdafx.h file as well as the code that actually will retrieve the information, which you will place in your source program at the appropriate place.  If you want to just copy a piece of it, this is a read-only edit control and honors highlighting and Ctrl+C for doing the copy.

download.gif (1234 bytes)

Note that this project is for VS.NET 2003 and can build both Unicode and ANSI versions.

 

 

 

[Dividing Line Image]

The views expressed in these essays are those of the author, and in no way represent, nor are they endorsed by, Microsoft.

Send mail to newcomer@flounder.com with questions or comments about this web site.
Copyright © 2006 FlounderCraft, Ltd.,  All Rights Reserved.
Last modified: May 14, 2011