QStandardPaths: Replace deprecated Win32 SHGetSpecialFolderPath

SHGetSpecialFolderPath is declared 'unsupported' by Microsoft, and has
problems with non-ASCII characters. Replace it by the newer
SHGetKnownFolderPath.

To fix compilation with MinGW, we have to link in libuuid also in
the bootstrapped tools. The alternative is redefining all GUID's
(like we did for FOLDERID_Downloads), which is arguably less elegant.

Task-number: QTBUG-50570
Change-Id: If99be559bc72de3734ae1fa4d50f960659739898
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
bb10
Kai Koehne 2016-11-02 13:58:54 +01:00
parent aa7e764058
commit aa73a7026f
2 changed files with 31 additions and 51 deletions

View File

@ -47,17 +47,10 @@
#include <qcoreapplication.h>
#endif
const GUID qCLSID_FOLDERID_Downloads = { 0x374de290, 0x123f, 0x4565, { 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b } };
#include <qt_windows.h>
#include <shlobj.h>
#include <intshcut.h>
#ifndef CSIDL_MYMUSIC
#define CSIDL_MYMUSIC 13
#define CSIDL_MYVIDEO 14
#endif
#ifndef QT_NO_STANDARDPATHS
QT_BEGIN_NAMESPACE
@ -108,47 +101,31 @@ static inline void appendTestMode(QString &path)
path += QLatin1String("/qttest");
}
// Map QStandardPaths::StandardLocation to CLSID of SHGetSpecialFolderPath()
static int writableSpecialFolderClsid(QStandardPaths::StandardLocation type)
// Map QStandardPaths::StandardLocation to KNOWNFOLDERID of SHGetKnownFolderPath()
static GUID writableSpecialFolderId(QStandardPaths::StandardLocation type)
{
static const int clsids[] = {
CSIDL_DESKTOPDIRECTORY, // DesktopLocation
CSIDL_PERSONAL, // DocumentsLocation
CSIDL_FONTS, // FontsLocation
CSIDL_PROGRAMS, // ApplicationsLocation
CSIDL_MYMUSIC, // MusicLocation
CSIDL_MYVIDEO, // MoviesLocation
CSIDL_MYPICTURES, // PicturesLocation
-1, -1, // TempLocation/HomeLocation
CSIDL_LOCAL_APPDATA, // AppLocalDataLocation ("Local" path), AppLocalDataLocation = DataLocation
-1, // CacheLocation
CSIDL_LOCAL_APPDATA, // GenericDataLocation ("Local" path)
-1, // RuntimeLocation
CSIDL_LOCAL_APPDATA, // ConfigLocation ("Local" path)
-1, -1, // DownloadLocation/GenericCacheLocation
CSIDL_LOCAL_APPDATA, // GenericConfigLocation ("Local" path)
CSIDL_APPDATA, // AppDataLocation ("Roaming" path)
CSIDL_LOCAL_APPDATA, // AppConfigLocation ("Local" path)
static const GUID folderIds[] = {
FOLDERID_Desktop, // DesktopLocation
FOLDERID_Documents, // DocumentsLocation
FOLDERID_Fonts, // FontsLocation
FOLDERID_Programs, // ApplicationsLocation
FOLDERID_Music, // MusicLocation
FOLDERID_Videos, // MoviesLocation
FOLDERID_Pictures, // PicturesLocation
GUID(), GUID(), // TempLocation/HomeLocation
FOLDERID_LocalAppData, // AppLocalDataLocation ("Local" path), AppLocalDataLocation = DataLocation
GUID(), // CacheLocation
FOLDERID_LocalAppData, // GenericDataLocation ("Local" path)
GUID(), // RuntimeLocation
FOLDERID_LocalAppData, // ConfigLocation ("Local" path)
GUID(), GUID(), // DownloadLocation/GenericCacheLocation
FOLDERID_LocalAppData, // GenericConfigLocation ("Local" path)
FOLDERID_RoamingAppData,// AppDataLocation ("Roaming" path)
FOLDERID_LocalAppData, // AppConfigLocation ("Local" path)
};
Q_STATIC_ASSERT(sizeof(clsids) / sizeof(clsids[0]) == size_t(QStandardPaths::AppConfigLocation + 1));
return size_t(type) < sizeof(clsids) / sizeof(clsids[0]) ? clsids[type] : -1;
};
// Convenience for SHGetSpecialFolderPath().
static QString sHGetSpecialFolderPath(int clsid, QStandardPaths::StandardLocation type, bool warn = false)
{
QString result;
wchar_t path[MAX_PATH];
if (Q_LIKELY(clsid >= 0 && SHGetSpecialFolderPath(0, path, clsid, FALSE))) {
result = convertCharArray(path);
} else {
if (warn) {
qErrnoWarning("SHGetSpecialFolderPath() failed for standard location \"%s\", clsid=0x%x.",
qPrintable(displayName(type)), clsid);
}
}
return result;
Q_STATIC_ASSERT(sizeof(folderIds) / sizeof(folderIds[0]) == size_t(QStandardPaths::AppConfigLocation + 1));
return size_t(type) < sizeof(folderIds) / sizeof(folderIds[0]) ? folderIds[type] : GUID();
}
// Convenience for SHGetKnownFolderPath().
@ -178,7 +155,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
QString result;
switch (type) {
case DownloadLocation:
result = sHGetKnownFolderPath(qCLSID_FOLDERID_Downloads, type);
result = sHGetKnownFolderPath(FOLDERID_Downloads, type);
if (result.isEmpty())
result = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
break;
@ -187,7 +164,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
// Although Microsoft has a Cache key it is a pointer to IE's cache, not a cache
// location for everyone. Most applications seem to be using a
// cache directory located in their AppData directory
result = sHGetSpecialFolderPath(writableSpecialFolderClsid(AppLocalDataLocation), type, /* warn */ true);
result = sHGetKnownFolderPath(writableSpecialFolderId(AppLocalDataLocation), type, /* warn */ true);
if (!result.isEmpty()) {
appendTestMode(result);
appendOrganizationAndApp(result);
@ -196,7 +173,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
break;
case GenericCacheLocation:
result = sHGetSpecialFolderPath(writableSpecialFolderClsid(GenericDataLocation), type, /* warn */ true);
result = sHGetKnownFolderPath(writableSpecialFolderId(GenericDataLocation), type, /* warn */ true);
if (!result.isEmpty()) {
appendTestMode(result);
result += QLatin1String("/cache");
@ -213,7 +190,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
break;
default:
result = sHGetSpecialFolderPath(writableSpecialFolderClsid(type), type, /* warn */ isConfigLocation(type));
result = sHGetKnownFolderPath(writableSpecialFolderId(type), type, /* warn */ isConfigLocation(type));
if (!result.isEmpty() && isConfigLocation(type)) {
appendTestMode(result);
if (!isGenericConfigLocation(type))
@ -233,7 +210,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
// type-specific handling goes here
if (isConfigLocation(type)) {
QString programData = sHGetSpecialFolderPath(CSIDL_COMMON_APPDATA, type);
QString programData = sHGetKnownFolderPath(FOLDERID_ProgramData, type);
if (!programData.isEmpty()) {
if (!isGenericConfigLocation(type))
appendOrganizationAndApp(programData);

View File

@ -134,7 +134,10 @@ macx {
include(../../3rdparty/zlib_dependency.pri)
}
win32:LIBS += -luser32 -lole32 -ladvapi32 -lshell32
win32 {
LIBS += -luser32 -lole32 -ladvapi32 -lshell32
mingw: LIBS += -luuid
}
load(qt_module)