<meta content="Microsoft Word 14 (filtered)" name="Generator" />
The correct ways to identify folder paths to store files depends on the programming technology you use. This blog post shows how to do it in C++, C# and VB. NET, PowerShell, Windows Script Host (VBScript and JScript), and as a last resort, environment variables.
One of the more common programming mistakes that lead to compatibility problems is the incorrect specification of folder paths in programs. For example, it is not uncommon for programs to assume that the user’s profile is under “C:\Documents and Settings”. These default paths are always subject to change and have changed across different versions of Windows. User profiles were stored under %SystemDrive%\WINNT\Profiles, then under “%SystemDrive%\Documents and Settings”, and now under %SystemDrive%\Users. The “All Users” profile is now called “Public”, and what was in “%USERPROFILE%\Local Settings\Application Data” is now in “%USERPROFILE%\AppData\Local”. Also, part of what used to be under the “All Users” profile is now in a separate folder location (by default, C:\ProgramData).
How can programs work correctly when these paths keep changing? Well, applications that are written correctly don’t require any modification to get the correct folder locations on all versions of Windows. Some rules you should follow:
Here are the correct ways to identify folder locations using a variety of programming technologies:
Use the SHGetSpecialFolderPath function with CSIDL constants. For programs designed to run only on Windows Vista or newer, use the SHGetKnownFolderPath function with KNOWNFOLDERID constants. See the following links:
These two examples demonstrate retrieving the paths for the current user’s Documents folder and the computer’s shared Documents folder:
HRESULT hr;
TCHAR szPath[MAX_PATH];
hr = SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, szPath);
if (SUCCEEDED(hr))
{
...
}
hr = SHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, SHGFP_TYPE_CURRENT, szPath);
if (SUCCEEDED(hr))
{
...
}
Use the Environment.GetFolderPath method, passing in a Environment.SpecialFolder enumeration. The System.IO.Path.Combine method can be used to combine path parts. For example, the following C# code returns the path to a “MyData” subfolder in the current user’s Documents folder:
string sPath;
sPath = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"MyData");
This is the same code implemented in VB .NET:
Dim sPath As String
sPath = System.IO.Path.Combine( _
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), _
"MyData")
References:
Windows PowerShell is built on .NET and can invoke many .NET methods and resources from the PowerShell command line interface or from Notepad-editable script files. This is how to implement the earlier sample building a path to a “MyData” subfolder of the user’s Documents folder using PowerShell:
$sPath = [System.IO.Path]::Combine(
[Environment]::GetFolderPath([Environment+SpecialFolder]::MyDocuments),
"MyData")
You can invoke the native Windows SHGetFolderPath API from C# or VB .NET code using Platform Invoke (a.k.a., P/Invoke) methods. See http://pinvoke.net/default.aspx/shell32/SHGetFolderPath.html for examples. This may be useful because the native CSIDL enumeration includes many more folder locations than the .NET SpecialFolder enumeration did before .NET v4.
Windows Script Host defines a SpecialFolders collection that can be used from VBScript or JScript. The following JScript example outputs the path to the common (“all users”) desktop:
var oWsh = WScript.CreateObject("WScript.Shell");
var sDesk = oWsh.SpecialFolders("AllUsersDesktop");
WScript.Echo(sDesk);
And here is the same code in VBScript:
Dim oWsh, sDesk
Set oWsh = WScript.CreateObject("WScript.Shell")
sDesk = oWsh.SpecialFolders("AllUsersDesktop")
WScript.Echo sDesk
References:
If none of the above interfaces are available (for example, from a Cmd.exe batch file), Windows defines a relatively small number of environment variables that identify some file system locations. Using these environment variables, at least for partial paths, is better than hardcoding paths. The following table lists the filepath-related environment variables on my Windows 7 SP1 x64 system and their values. Note that these are just example values as found on a particular computer. Do not assume that the same path locations are the same on other computers. See the References for the meanings and intended purposes of these variables.
Environment variable name |
Example value |
ALLUSERSPROFILE |
C:\ProgramData |
APPDATA |
C:\Users\ username \AppData\Roaming |
CommonProgramFiles |
C:\Program Files\Common Files |
CommonProgramFiles(x86) |
C:\Program Files (x86)\Common Files |
CommonProgramW6432 |
C:\Program Files\Common Files |
ComSpec |
C:\Windows\system32\cmd.exe |
HOMEDRIVE |
C: |
HOMEPATH |
\Users\ username |
LOCALAPPDATA |
C:\Users\ username \AppData\Local |
ProgramData |
C:\ProgramData |
ProgramFiles |
C:\Program Files |
ProgramFiles(x86) |
C:\Program Files (x86) |
ProgramW6432 |
C:\Program Files |
PSModulePath |
C:\Windows\system32\WindowsPowerShell\v1.0\Modules\ |
PUBLIC |
C:\Users\Public |
SystemDrive |
C: |
SystemRoot |
C:\Windows |
TEMP |
C:\Users\ username \AppData\Local\Temp |
TMP |
C:\Users\ username \AppData\Local\Temp |
USERPROFILE |
C:\Users\ username |
windir |
C:\Windows |
References: