From de09a6dc2ba4de8b0d363e664c268a23c4e92b75 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 4 Oct 2013 12:34:28 +0200 Subject: Improve the AxSelect-Dialog. Give it a tooltip listing DLL, version and word size. For 64 bit executables, append the 32 bit controls as disabled controls at the end to make them visible. Task-number: QTBUG-33711 Change-Id: I2800a78cfc826bd08c591f491bb42f22eeda5b25 Reviewed-by: Andy Shaw --- src/activeqt/container/qaxselect.cpp | 220 +++++++++++++++++++++++++++-------- 1 file changed, 169 insertions(+), 51 deletions(-) diff --git a/src/activeqt/container/qaxselect.cpp b/src/activeqt/container/qaxselect.cpp index 4751d55..bd1e14c 100644 --- a/src/activeqt/container/qaxselect.cpp +++ b/src/activeqt/container/qaxselect.cpp @@ -45,71 +45,176 @@ #include #include +#include +#include +#include #include #include +#include +#include + QT_BEGIN_NAMESPACE -class ControlList : public QAbstractListModel +struct Control +{ + inline Control() : wordSize(0) {} + int compare(const Control &rhs) const; + QString toolTip() const; + + QString clsid; + QString name; + QString dll; + QString version; + unsigned wordSize; +}; + +inline int Control::compare(const Control &rhs) const { + // Sort reverse by word size to ensure that disabled 32bit controls + // are listed last in 64bit executables. + if (wordSize > rhs.wordSize) + return -1; + if (wordSize < rhs.wordSize) + return 1; + if (const int n = name.compare(rhs.name)) + return n; + if (const int c = clsid.compare(rhs.clsid)) + return c; + if (const int d = dll.compare(rhs.dll)) + return d; + if (const int v = version.compare(rhs.version)) + return v; + return 0; +} + +QString Control::toolTip() const +{ + QString result; + QTextStream str(&result); + str << "" + << "" + << "" + << ""; + if (!dll.isEmpty()) + str << ""; + if (!version.isEmpty()) + str << ""; + str << "
" << QAxSelect::tr("Name:") << "" << name << "
" << QAxSelect::tr("CLSID:") << "" << clsid << "
" << QAxSelect::tr("Word size:") << "" << wordSize << "
" << QAxSelect::tr("DLL:") << "" << dll << "
" << QAxSelect::tr("Version:") << "" << version << "
"; + result.replace(QStringLiteral(" "), QStringLiteral(" ")); + return result; +} + +inline bool operator<(const Control &c1, const Control &c2) { return c1.compare(c2) < 0; } +inline bool operator==(const Control &c1, const Control &c2) { return !c1.compare(c2); } + +class FindByClsidPredicate : public std::unary_function { public: - ControlList(QObject *parent=0) - : QAbstractListModel(parent) - { - HKEY classes_key; - RegOpenKeyEx(HKEY_CLASSES_ROOT, L"CLSID", 0, KEY_READ, &classes_key); - if (!classes_key) - return; - - DWORD index = 0; - LONG result = 0; - wchar_t buffer[256]; - DWORD szBuffer = sizeof(buffer) / sizeof(wchar_t); - FILETIME ft; - do { - result = RegEnumKeyEx(classes_key, index, buffer, &szBuffer, 0, 0, 0, &ft); - szBuffer = sizeof(buffer) / sizeof(wchar_t); + explicit FindByClsidPredicate(const QString &clsid) : m_clsid(clsid) {} + inline bool operator()(const Control &c) const { return m_clsid == c.clsid; } + +private: + const QString m_clsid; +}; + +static LONG RegistryQueryValue(HKEY hKey, LPCWSTR lpSubKey, LPBYTE lpData, LPDWORD lpcbData) +{ + LONG ret = ERROR_FILE_NOT_FOUND; + HKEY hSubKey = NULL; + RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &hSubKey); + if (hSubKey) { + ret = RegQueryValueEx(hSubKey, 0, 0, 0, lpData, lpcbData); + RegCloseKey(hSubKey); + } + return ret; +} + +static bool querySubKeyValue(HKEY hKey, const QString &subKeyName, LPBYTE lpData, LPDWORD lpcbData) +{ + HKEY hSubKey = NULL; + const LONG openResult = RegOpenKeyEx(hKey, reinterpret_cast(subKeyName.utf16()), + 0, KEY_READ, &hSubKey); + if (openResult != ERROR_SUCCESS) + return false; + const bool result = RegQueryValueEx(hSubKey, 0, 0, 0, lpData, lpcbData) == ERROR_SUCCESS; + RegCloseKey(hSubKey); + return result; +} + +static QList readControls(const wchar_t *rootKey, unsigned wordSize) +{ + QList controls; + HKEY classesKey; + RegOpenKeyEx(HKEY_CLASSES_ROOT, rootKey, 0, KEY_READ, &classesKey); + if (!classesKey) { + qErrnoWarning("RegOpenKeyEx failed."); + return controls; + } + const QString systemRoot = QString::fromLocal8Bit(qgetenv("SystemRoot")); + const QRegExp systemRootPattern(QStringLiteral("%SystemRoot%"), Qt::CaseInsensitive, QRegExp::FixedString); + DWORD index = 0; + LONG result = 0; + wchar_t buffer[256]; + DWORD szBuffer = 0; + FILETIME ft; + do { + szBuffer = sizeof(buffer) / sizeof(wchar_t); + result = RegEnumKeyEx(classesKey, index, buffer, &szBuffer, 0, 0, 0, &ft); + szBuffer = sizeof(buffer) / sizeof(wchar_t); + if (result == ERROR_SUCCESS) { + HKEY subKey; + const QString clsid = QString::fromWCharArray(buffer); + const QString key = clsid + QStringLiteral("\\Control"); + result = RegOpenKeyEx(classesKey, reinterpret_cast(key.utf16()), 0, KEY_READ, &subKey); if (result == ERROR_SUCCESS) { - HKEY sub_key; - QString clsid = QString::fromWCharArray(buffer); - const QString key = clsid + QStringLiteral("\\Control"); - result = RegOpenKeyEx(classes_key, reinterpret_cast(key.utf16()), 0, KEY_READ, &sub_key); - if (result == ERROR_SUCCESS) { - RegCloseKey(sub_key); - RegistryQueryValue(classes_key, buffer, (LPBYTE)buffer, &szBuffer); - QString name = QString::fromWCharArray(buffer); - - controls << name; - clsids.insert(name, clsid); + RegCloseKey(subKey); + szBuffer = sizeof(buffer) / sizeof(wchar_t); + RegistryQueryValue(classesKey, buffer, (LPBYTE)buffer, &szBuffer); + Control control; + control.clsid = clsid; + control.wordSize = wordSize; + control.name = QString::fromWCharArray(buffer); + szBuffer = sizeof(buffer) / sizeof(wchar_t); + if (querySubKeyValue(classesKey, clsid + QStringLiteral("\\InprocServer32"), (LPBYTE)buffer, &szBuffer)) { + control.dll = QString::fromWCharArray(buffer); + control.dll.replace(systemRootPattern, systemRoot); } - result = ERROR_SUCCESS; + szBuffer = sizeof(buffer) / sizeof(wchar_t); + if (querySubKeyValue(classesKey, clsid + QStringLiteral("\\VERSION"), (LPBYTE)buffer, &szBuffer)) + control.version = QString::fromWCharArray(buffer); + controls.push_back(control); } - szBuffer = sizeof(buffer) / sizeof(wchar_t); - ++index; - } while (result == ERROR_SUCCESS); - RegCloseKey(classes_key); - controls.sort(); - } + result = ERROR_SUCCESS; + } + ++index; + } while (result == ERROR_SUCCESS); + RegCloseKey(classesKey); + return controls; +} - LONG RegistryQueryValue(HKEY hKey, LPCWSTR lpSubKey, LPBYTE lpData, LPDWORD lpcbData) +class ControlList : public QAbstractListModel +{ +public: + ControlList(QObject *parent=0) + : QAbstractListModel(parent) { - LONG ret = ERROR_FILE_NOT_FOUND; - HKEY hSubKey = NULL; - RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &hSubKey); - if (hSubKey) { - ret = RegQueryValueEx(hSubKey, 0, 0, 0, lpData, lpcbData); - RegCloseKey(hSubKey); + m_controls = readControls(L"CLSID", unsigned(QSysInfo::WordSize)); + if (QSysInfo::WordSize == 64) { // Append the 32bit controls as disabled items. + foreach (const Control &c, readControls(L"Wow6432Node\\CLSID", 32u)) { + if (std::find_if(m_controls.constBegin(), m_controls.constEnd(), FindByClsidPredicate(c.clsid)) == m_controls.constEnd()) + m_controls.append(c); + } } - return ret; + std::sort(m_controls.begin(), m_controls.end()); } - int rowCount(const QModelIndex & = QModelIndex()) const { return controls.count(); } + int rowCount(const QModelIndex & = QModelIndex()) const { return m_controls.count(); } QVariant data(const QModelIndex &index, int role) const; + Qt::ItemFlags flags(const QModelIndex &index) const; private: - QStringList controls; - QMap clsids; + QList m_controls; }; QVariant ControlList::data(const QModelIndex &index, int role) const @@ -117,14 +222,27 @@ QVariant ControlList::data(const QModelIndex &index, int role) const if (!index.isValid()) return QVariant(); - if (role == Qt::DisplayRole) - return controls.at(index.row()); - if (role == Qt::UserRole) - return clsids.value(controls.at(index.row())); - + switch (role) { + case Qt::DisplayRole: + return m_controls.at(index.row()).name; + case Qt::ToolTipRole: + return m_controls.at(index.row()).toolTip(); + case Qt::UserRole: + return m_controls.at(index.row()).clsid; + default: + break; + } return QVariant(); } +Qt::ItemFlags ControlList::flags(const QModelIndex &index) const +{ + Qt::ItemFlags result = QAbstractListModel::flags(index); + if (!index.isValid() || m_controls.at(index.row()).wordSize != QSysInfo::WordSize) + result &= ~Qt::ItemIsEnabled; + return result; +} + class QAxSelectPrivate { public: inline QString clsidAt(const QModelIndex &index) const -- cgit v1.2.3