Utils: Fix getting a case sensitive path on windows.

Until now we used GetShortPathName which relies on having 8.3 paths.
This short path names are converted into long names which also corrects
the case. The 8.3 paths can be manually deactivated via the fsutil. When
this is done GetShortPathName does not return a convertible path string.

If the case isn't corrected on windows we are opening multiple editors for
the same file. For example, when reaching a breakpoint when using cdb or
opening an entry from the issue panel generated by the msvc compile.

Task-number: QTCREATORBUG-11199
Change-Id: Ic04055685e0e9bbe0d45cde20563929b7370695d
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
Reviewed-by: Eike Ziller <eike.ziller@digia.com>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
This commit is contained in:
David Schulz
2013-12-04 07:37:07 +01:00
committed by Daniel Teske
parent 50d93a6567
commit 0eea7ca90b
2 changed files with 10 additions and 43 deletions

View File

@@ -40,6 +40,7 @@
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include <qt_windows.h> #include <qt_windows.h>
#include <shlobj.h>
#endif #endif
namespace Utils { namespace Utils {
@@ -241,55 +242,21 @@ bool FileUtils::makeWritable(const FileName &path)
return QFile::setPermissions(fileName, QFile::permissions(fileName) | QFile::WriteUser); return QFile::setPermissions(fileName, QFile::permissions(fileName) | QFile::WriteUser);
} }
#ifdef Q_OS_WIN
static QString getShortPathName(const QString &name)
{
if (name.isEmpty())
return name;
// Determine length, then convert.
const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(name.utf16()); // MinGW
const DWORD length = GetShortPathNameW(nameC, NULL, 0);
if (length == 0)
return name;
QScopedArrayPointer<TCHAR> buffer(new TCHAR[length]);
GetShortPathNameW(nameC, buffer.data(), length);
const QString rc = QString::fromUtf16(reinterpret_cast<const ushort *>(buffer.data()), length - 1);
return rc;
}
static QString getLongPathName(const QString &name)
{
if (name.isEmpty())
return name;
// Determine length, then convert.
const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(name.utf16()); // MinGW
const DWORD length = GetLongPathNameW(nameC, NULL, 0);
if (length == 0)
return name;
QScopedArrayPointer<TCHAR> buffer(new TCHAR[length]);
GetLongPathNameW(nameC, buffer.data(), length);
const QString rc = QString::fromUtf16(reinterpret_cast<const ushort *>(buffer.data()), length - 1);
return rc;
}
#endif // Q_OS_WIN
// makes sure that capitalization of directories is canonical on Windows. // makes sure that capitalization of directories is canonical on Windows.
// This mimics the logic in QDeclarative_isFileCaseCorrect // This mimics the logic in QDeclarative_isFileCaseCorrect
QString FileUtils::normalizePathName(const QString &name) QString FileUtils::normalizePathName(const QString &name)
{ {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
QString canonicalName = getShortPathName(name); const QString nativeSeparatorName(QDir::toNativeSeparators(name));
if (canonicalName.isEmpty()) const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(nativeSeparatorName.utf16()); // MinGW
PIDLIST_ABSOLUTE file;
HRESULT hr = SHParseDisplayName(nameC, NULL, &file, 0, NULL);
if (FAILED(hr))
return name; return name;
canonicalName = getLongPathName(canonicalName); TCHAR buffer[MAX_PATH];
if (canonicalName.isEmpty()) if (!SHGetPathFromIDList(file, buffer))
return name; return name;
// Upper case drive letter return QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const ushort *>(buffer)));
if (canonicalName.size() > 2 && canonicalName.at(1) == QLatin1Char(':'))
canonicalName[0] = canonicalName.at(0).toUpper();
return canonicalName;
#else // Filesystem is case-insensitive only on Windows #else // Filesystem is case-insensitive only on Windows
return name; return name;
#endif #endif

View File

@@ -18,6 +18,6 @@ lessThan(QT_MAJOR_VERSION, 5) {
} }
} }
win32: LIBS += -luser32 win32: LIBS += -luser32 -lshell32
# PortsGatherer # PortsGatherer
win32: LIBS += -liphlpapi -lws2_32 win32: LIBS += -liphlpapi -lws2_32