Discovering Well-Known directory locations
The Qt documentation, and in particular QDir, provide some helper methods to determine the location of certain directories in a portable manner. The current user's home directory, the root directory and finally the current temporary directory are all available via static factory methods on QDir. Additionally, the Qt docs mention in their Mac notes how to access the bundle path.
OS-X
On OS-X the most useful routine is FSFindFolder, a Carbon function which has existed in various forms since MacOS 7. It accepts a long list of constant codes, and a disk / domain specifier, which is used to specify the scope of the query. The standard domains are:
- User domain
- System domain
- Network domain
Note, the equivalent Cocoa functionaliy is provided by NSSearchPathForDirectoriesInDomains, but interfacing with the Carbon function is simpler, especially from C++ code.
QDir result;
FSRef fs;
OSErr err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, true, &fs);
if (err != noErr) {
qWarning() << "error doing FSFindFolder:" << err;
return QDir();
}
CFURLRef dirURL = CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &fs);
char fsRepr[1024];
if (!CFURLGetFileSystemRepresentation(dirURL, true, (UInt8*) fsRepr, 1024)) {
qWarning() << "error invoking CFURLGetFileSystemRepresentation";
return QDir();
}
result.setPath(QString::fromUtf8(fsRepr));
CFRelease(dirURL);
Some interesting locations:
- kApplicationSupportFolderType - corresponds to the Application Support folder in Library
- kTrashFolderType - current user's trash directory
- kDesktopFolderType
Windows
SHGetFolderPath and SHGetFolderLocation are the critical calls, available from Windows 2000 / ME and upwards. The required functionality can sometimes be provided on earlier versions of Windows via the re-distributable shfolder.dll. Like FSFindFolder on Mac, the calls accept a large list of symbolic constants and maps them to either a concrete path or to a 'virtual folder ID' (in the case of SHGetFolderLocation). Only a subset of locations can be mapped to a concrete path (see the MSDN docs), but in general the 'useful' ones can be - something like the Neighbourhood Network is a good example of a virtual location that can't be mapped to a path.
QDir result;
WCHAR fsRepr[MAX_PATH];
int flags; //
if (S_OK != SHGetFolderPathW(NULL, csidl, flags, SHGFP_TYPE_CURRENT, fsRepr));
{
qWarning() << "error doing SHGetFolderPath:";
return QDir();
}
result.setPath(QString::fromWCharArray(fsRepr));
Some interesting examples:
- CSIDL_DESKTOPDIRECTORY - current user's Desktop
- CSIDL_BITBUCKET - the recycle bin
- CSIDL_PROFILE - the 'Documents & Settings' directory of the current user
- CSIDL_COMMON_APPDATA - the 'All Users\Application Data' directory.
- CSIDL_MYPICTURES - current user's pictures / photos directory.
Linux & Unix
There is not (at present) a standard runtime configuration for directory locations; the closest equivalent are the well-known locations defined as standards and conventions. FreeDesktop.org defines various standards, notably the Linux Standards Base and the Base Directory Specification, but adherance to these is variable. Practical compliance with such schemes generally means best-effor: trying them first, and falling back gracefully (and silently) to hard-coded locations (such as /usr/local/share).
