forked from qt-creator/qt-creator
CDB: Add nagging about old version of Debugging Tools.
Add utility to figure out DLL/Product versions.
This commit is contained in:
@@ -31,6 +31,10 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
|
#include <QtCore/QVector>
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
#include <QtCore/QLibrary>
|
||||||
|
#include <QtCore/QTextStream>
|
||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
|
|
||||||
@@ -51,4 +55,60 @@ QTCREATOR_UTILS_EXPORT QString winErrorMessage(unsigned long error)
|
|||||||
return rc;
|
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
|
} // namespace Utils
|
||||||
|
@@ -42,5 +42,10 @@ namespace Utils {
|
|||||||
// code as returned by the GetLastError()-API.
|
// code as returned by the GetLastError()-API.
|
||||||
QTCREATOR_UTILS_EXPORT QString winErrorMessage(unsigned long error);
|
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
|
} // namespace Utils
|
||||||
#endif // WINUTILS_H
|
#endif // WINUTILS_H
|
||||||
|
@@ -236,7 +236,9 @@ static inline QString libPath(const QString &libName, const QString &path = QStr
|
|||||||
return rc;
|
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
|
// Load the dependent help lib first
|
||||||
const QString helpLibPath = libPath(QLatin1String(dbgHelpDllC), path);
|
const QString helpLibPath = libPath(QLatin1String(dbgHelpDllC), path);
|
||||||
@@ -252,6 +254,7 @@ bool DebuggerEngineLibrary::init(const QString &path, QString *errorMessage)
|
|||||||
*errorMessage = msgLibLoadFailed(engineLibPath, lib.errorString());
|
*errorMessage = msgLibLoadFailed(engineLibPath, lib.errorString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
*dbgEngDLL = engineLibPath;
|
||||||
// Locate symbols
|
// Locate symbols
|
||||||
void *createFunc = lib.resolve(debugCreateFuncC);
|
void *createFunc = lib.resolve(debugCreateFuncC);
|
||||||
if (!createFunc) {
|
if (!createFunc) {
|
||||||
@@ -317,9 +320,8 @@ bool CdbDebugEnginePrivate::init(QString *errorMessage)
|
|||||||
enum { bufLen = 10240 };
|
enum { bufLen = 10240 };
|
||||||
// Load the DLL
|
// Load the DLL
|
||||||
DebuggerEngineLibrary lib;
|
DebuggerEngineLibrary lib;
|
||||||
if (!lib.init(m_options->path, errorMessage))
|
if (!lib.init(m_options->path, &m_dbengDLL, errorMessage))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Initialize the COM interfaces
|
// Initialize the COM interfaces
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
hr = lib.debugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_cif.debugClient));
|
hr = lib.debugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_cif.debugClient));
|
||||||
@@ -587,9 +589,38 @@ void CdbDebugEnginePrivate::clearDisplay()
|
|||||||
manager()->registerHandler()->removeAll();
|
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)
|
void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp)
|
||||||
{
|
{
|
||||||
setState(AdapterStarting, Q_FUNC_INFO, __LINE__);
|
setState(AdapterStarting, Q_FUNC_INFO, __LINE__);
|
||||||
|
m_d->checkVersion();
|
||||||
if (m_d->m_hDebuggeeProcess) {
|
if (m_d->m_hDebuggeeProcess) {
|
||||||
warning(QLatin1String("Internal error: Attempt to start debugger while another process is being debugged."));
|
warning(QLatin1String("Internal error: Attempt to start debugger while another process is being debugged."));
|
||||||
setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__);
|
setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__);
|
||||||
|
@@ -57,7 +57,7 @@ class DebuggerEngineLibrary
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DebuggerEngineLibrary();
|
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
|
inline HRESULT debugCreate(REFIID interfaceId, PVOID *interfaceHandle) const
|
||||||
{ return m_debugCreate(interfaceId, interfaceHandle); }
|
{ return m_debugCreate(interfaceId, interfaceHandle); }
|
||||||
@@ -108,8 +108,9 @@ struct CdbDebugEnginePrivate
|
|||||||
const QSharedPointer<CdbOptions> &options,
|
const QSharedPointer<CdbOptions> &options,
|
||||||
CdbDebugEngine* engine);
|
CdbDebugEngine* engine);
|
||||||
bool init(QString *errorMessage);
|
bool init(QString *errorMessage);
|
||||||
~CdbDebugEnginePrivate();
|
~CdbDebugEnginePrivate();
|
||||||
|
|
||||||
|
void checkVersion();
|
||||||
void processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle);
|
void processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle);
|
||||||
void setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE hDebuggeeThread);
|
void setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE hDebuggeeThread);
|
||||||
|
|
||||||
@@ -177,6 +178,7 @@ struct CdbDebugEnginePrivate
|
|||||||
|
|
||||||
DebuggerStartMode m_mode;
|
DebuggerStartMode m_mode;
|
||||||
Utils::ConsoleProcess m_consoleStubProc;
|
Utils::ConsoleProcess m_consoleStubProc;
|
||||||
|
QString m_dbengDLL;
|
||||||
};
|
};
|
||||||
|
|
||||||
// helper functions
|
// helper functions
|
||||||
|
Reference in New Issue
Block a user