How to retrieve special folder paths, for e.g. my documents?

SHGetFolderPath is the API that we use to retrieve special folder paths.  Some examples of special folders are as follows…

  • My Documents
  • My Pictures
  • Windows directory
  • System directory
  • Program files
  • Internet history directory
  • Cookies directory
  • etc…

So here is a small useful function which retrieves path of any special directory documented for SHGetFolderPath API in MSDN.

[sourcecode language=’cpp’]CString GetSpecialFolderPath( const DWORD csidl )
{
   HANDLE ProcToken = NULL;
   VERIFY( OpenProcessToken( GetCurrentProcess(), TOKEN_READ, &ProcToken ));

   TCHAR szBuffer[MAX_PATH*2] = { 0 };
   SHGetFolderPath( NULL, csidl, ProcToken, SHGFP_TYPE_CURRENT, szBuffer );
   CString SpecialFolderPath = szBuffer;

   CloseHandle( ProcToken );

   return SpecialFolderPath;
}

// Usage
int main()
{
// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFC initialization failed") << endl; nRetCode = 1; } // Get my documents folder path const CString MyDocuments = GetSpecialFolderPath( CSIDL_PERSONAL ); ::MessageBox( NULL, MyDocuments, "MyDocuments Path", MB_OK | MB_ICONINFORMATION ); // Get Program files path const CString ProgramFiles = GetSpecialFolderPath( CSIDL_PROGRAM_FILES ); ::MessageBox( NULL, ProgramFiles, "Program files", MB_OK | MB_ICONINFORMATION ); // Get internet history path const CString HistoryFolder = GetSpecialFolderPath( CSIDL_HISTORY ); ::MessageBox( NULL, HistoryFolder, "History folder", MB_OK | MB_ICONINFORMATION ); return 0; }[/sourcecode] There may be times when a special folder might not be present, so for that case you can combine CSIDL_FLAG_CREATE with other CSIDL flags. For example if you want to create my documents folder if there is no such one present then we'll call "GetSpecialFolderPath" likewise... [sourcecode language='cpp']// You can be sure that my documents will be present this way CString MyDocuments = GetSpecialFolderPath( CSIDL_PERSONAL | CSIDL_FLAG_CREATE ); // Now create a file in this directory MyDocuments += "/Learning.txt"; // CreateFile [/sourcecode] Above function is extremely easy to use but internally it opens and closes a token handle, so if you want to retrieve multiple entries then you can provide a token handle which may increase performance. Return values from ShGetFolderPath is interpreted as follows... S_FALSE -> SHGetFolderPathA only. The CSIDL in nFolder is valid, but the folder does not exist. Note that the failure code is different for the ANSI and Unicode versions of this function. E_FAIL -> SHGetFolderPathW only. The CSIDL in nFolder is valid, but the folder does not exist. Note that the failure code is different for the ANSI and Unicode versions of this function. E_INVALIDARG -> The CSIDL in nFolder is not valid.

Appreciate your comments...