From 162be9a33849ba7bd9ef2c2ba76f490a5353f7b0 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@nokia.com> Date: Fri, 9 Oct 2009 17:33:24 +0200 Subject: [PATCH] CDB: Add nagging about old version of Debugging Tools. Add utility to figure out DLL/Product versions. --- src/libs/utils/winutils.cpp | 60 +++++++++++++++++++++ src/libs/utils/winutils.h | 5 ++ src/plugins/debugger/cdb/cdbdebugengine.cpp | 39 ++++++++++++-- src/plugins/debugger/cdb/cdbdebugengine_p.h | 6 ++- 4 files changed, 104 insertions(+), 6 deletions(-) diff --git a/src/libs/utils/winutils.cpp b/src/libs/utils/winutils.cpp index 7815d553fb9..4e7d31c3fcf 100644 --- a/src/libs/utils/winutils.cpp +++ b/src/libs/utils/winutils.cpp @@ -31,6 +31,10 @@ #include <windows.h> #include <QtCore/QString> +#include <QtCore/QVector> +#include <QtCore/QDebug> +#include <QtCore/QLibrary> +#include <QtCore/QTextStream> namespace Utils { @@ -51,4 +55,60 @@ QTCREATOR_UTILS_EXPORT QString winErrorMessage(unsigned long error) return rc; } +QTCREATOR_UTILS_EXPORT QString winGetDLLVersion(WinDLLVersionType t, + const QString &name, + QString *errorMessage) +{ + // Resolve required symbols from the version.dll + typedef DWORD (APIENTRY *GetFileVersionInfoSizeProtoType)(LPCTSTR, LPDWORD); + typedef BOOL (APIENTRY *GetFileVersionInfoWProtoType)(LPCWSTR, DWORD, DWORD, LPVOID); + typedef BOOL (APIENTRY *VerQueryValueWProtoType)(const LPVOID, LPWSTR lpSubBlock, LPVOID, PUINT); + + const char *versionDLLC = "version.dll"; + QLibrary versionLib(QLatin1String(versionDLLC), 0); + if (!versionLib.load()) { + *errorMessage = QString::fromLatin1("Unable load %1: %2").arg(QLatin1String(versionDLLC), versionLib.errorString()); + return QString(); + } + // MinGW requires old-style casts + GetFileVersionInfoSizeProtoType getFileVersionInfoSizeW = (GetFileVersionInfoSizeProtoType)(versionLib.resolve("GetFileVersionInfoSizeW")); + GetFileVersionInfoWProtoType getFileVersionInfoW = (GetFileVersionInfoWProtoType)(versionLib.resolve("GetFileVersionInfoW")); + VerQueryValueWProtoType verQueryValueW = (VerQueryValueWProtoType)(versionLib.resolve("VerQueryValueW")); + if (!getFileVersionInfoSizeW || !getFileVersionInfoW || !verQueryValueW) { + *errorMessage = QString::fromLatin1("Unable to resolve all required symbols in %1").arg(QLatin1String(versionDLLC)); + return QString(); + } + + // Now go ahead, read version info resource + DWORD dummy = 0; + const LPCTSTR fileName = reinterpret_cast<LPCTSTR>(name.utf16()); // MinGWsy + const DWORD infoSize = (*getFileVersionInfoSizeW)(fileName, &dummy); + if (infoSize == 0) { + *errorMessage = QString::fromLatin1("Unable to determine the size of the version information of %1: %2").arg(name, winErrorMessage(GetLastError())); + return QString(); + } + QByteArray dataV(infoSize + 1, '\0'); + char *data = dataV.data(); + if (!(*getFileVersionInfoW)(fileName, dummy, infoSize, data)) { + *errorMessage = QString::fromLatin1("Unable to determine the version information of %1: %2").arg(name, winErrorMessage(GetLastError())); + return QString(); + } + VS_FIXEDFILEINFO *versionInfo; + UINT len = 0; + if (!(*verQueryValueW)(data, TEXT("\\"), &versionInfo, &len)) { + *errorMessage = QString::fromLatin1("Unable to determine version string of %1: %2").arg(name, winErrorMessage(GetLastError())); + return QString(); + } + QString rc; + switch (t) { + case WinDLLFileVersion: + QTextStream(&rc) << HIWORD(versionInfo->dwFileVersionMS) << '.' << LOWORD(versionInfo->dwFileVersionMS); + break; + case WinDLLProductVersion: + QTextStream(&rc) << HIWORD(versionInfo->dwProductVersionMS) << '.' << LOWORD(versionInfo->dwProductVersionMS); + break; + } + return rc; +} + } // namespace Utils diff --git a/src/libs/utils/winutils.h b/src/libs/utils/winutils.h index 19b8986ce1b..8a73961ce3e 100644 --- a/src/libs/utils/winutils.h +++ b/src/libs/utils/winutils.h @@ -42,5 +42,10 @@ namespace Utils { // code as returned by the GetLastError()-API. QTCREATOR_UTILS_EXPORT QString winErrorMessage(unsigned long error); +// Determine a DLL version +enum WinDLLVersionType { WinDLLFileVersion, WinDLLProductVersion }; +QTCREATOR_UTILS_EXPORT QString winGetDLLVersion(WinDLLVersionType t, + const QString &name, + QString *errorMessage); } // namespace Utils #endif // WINUTILS_H diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index c7f04055708..1086adf8e55 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -236,7 +236,9 @@ static inline QString libPath(const QString &libName, const QString &path = QStr return rc; } -bool DebuggerEngineLibrary::init(const QString &path, QString *errorMessage) +bool DebuggerEngineLibrary::init(const QString &path, + QString *dbgEngDLL, + QString *errorMessage) { // Load the dependent help lib first const QString helpLibPath = libPath(QLatin1String(dbgHelpDllC), path); @@ -252,6 +254,7 @@ bool DebuggerEngineLibrary::init(const QString &path, QString *errorMessage) *errorMessage = msgLibLoadFailed(engineLibPath, lib.errorString()); return false; } + *dbgEngDLL = engineLibPath; // Locate symbols void *createFunc = lib.resolve(debugCreateFuncC); if (!createFunc) { @@ -317,9 +320,8 @@ bool CdbDebugEnginePrivate::init(QString *errorMessage) enum { bufLen = 10240 }; // Load the DLL DebuggerEngineLibrary lib; - if (!lib.init(m_options->path, errorMessage)) + if (!lib.init(m_options->path, &m_dbengDLL, errorMessage)) return false; - // Initialize the COM interfaces HRESULT hr; hr = lib.debugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_cif.debugClient)); @@ -587,9 +589,38 @@ void CdbDebugEnginePrivate::clearDisplay() manager()->registerHandler()->removeAll(); } +void CdbDebugEnginePrivate::checkVersion() +{ + static bool versionNotChecked = true; + // Check for version 6.11 (extended expression syntax) + if (versionNotChecked) { + versionNotChecked = false; + // Get engine DLL version + QString errorMessage; + const QString version = Utils::winGetDLLVersion(Utils::WinDLLProductVersion, m_dbengDLL, &errorMessage); + if (version.isEmpty()) { + qWarning("%s\n", qPrintable(errorMessage)); + return; + } + // Compare + const double minVersion = 6.11; + manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Version: %1").arg(version)); + if (version.toDouble() < minVersion) { + const QString msg = CdbDebugEngine::tr( + "<html>The installed version of the <i>Debugging Tools for Windows</i> (%1) " + "is rather old. Upgrading to version %2 is recommended " + "for the proper display of Qt's data types.</html>").arg(version).arg(minVersion); + Core::ICore::instance()->showWarningWithOptions(CdbDebugEngine::tr("Debugger"), msg, QString(), + QLatin1String(Constants::DEBUGGER_SETTINGS_CATEGORY), + CdbOptionsPage::settingsId()); + } + } +} + void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp) -{ +{ setState(AdapterStarting, Q_FUNC_INFO, __LINE__); + m_d->checkVersion(); if (m_d->m_hDebuggeeProcess) { warning(QLatin1String("Internal error: Attempt to start debugger while another process is being debugged.")); setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__); diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h index 73fb7d41fa0..b0a01d37896 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine_p.h +++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h @@ -57,7 +57,7 @@ class DebuggerEngineLibrary { public: DebuggerEngineLibrary(); - bool init(const QString &path, QString *errorMessage); + bool init(const QString &path, QString *dbgEngDLL, QString *errorMessage); inline HRESULT debugCreate(REFIID interfaceId, PVOID *interfaceHandle) const { return m_debugCreate(interfaceId, interfaceHandle); } @@ -108,8 +108,9 @@ struct CdbDebugEnginePrivate const QSharedPointer<CdbOptions> &options, CdbDebugEngine* engine); bool init(QString *errorMessage); - ~CdbDebugEnginePrivate(); + ~CdbDebugEnginePrivate(); + void checkVersion(); void processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle); void setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE hDebuggeeThread); @@ -177,6 +178,7 @@ struct CdbDebugEnginePrivate DebuggerStartMode m_mode; Utils::ConsoleProcess m_consoleStubProc; + QString m_dbengDLL; }; // helper functions -- GitLab