diff options
author | Denis Shienkov <denis.shienkov@gmail.com> | 2013-11-08 16:36:26 +0400 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-11-30 15:58:32 +0100 |
commit | c070632fc73be89889f8297263d86b32390acd4c (patch) | |
tree | a5c9a2dd94bf30822838d444f29003867ed1ea59 /src/serialport/qserialportinfo_win.cpp | |
parent | 6c234760060b5b16cb089c59c69c7d38ceea9bc6 (diff) | |
download | qtserialport-c070632fc73be89889f8297263d86b32390acd4c.tar.gz |
Add the additional enumeration through Device Interface Class GUID
The current "Setup Class GUID" approach ignores the devices which has
been created by the drivers with a custom setup GUID's (e.g. Eltima
Virtual Serial Port Driver and so on).
In this case need to add each new custom GUID to the list. But it is
not a good solution and shall be used as a last resort.
The good solution is use of the "Device Interface Class GUID" instead
of the "Setup Class GUID" because it is the recommended way:
http://msdn.microsoft.com/en-us/library/windows/hardware/ff545036%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/ff545046%28v=vs.85%29.aspx
A new approach uses the standard GUID_DEVINTERFACE_COMPORT and
GUID_DEVINTERFACE_MODEM GUID's which shall be used for the development
of any serial port drivers. Besides requires adding of the additional
DIGCF_DEVICEINTERFACE flag for the SetupDiGetClassDevs() function,
see MSDN:
http://msdn.microsoft.com/en-us/library/windows/hardware/ff551069%28v=vs.85%29.aspx
It should be noted that this approach also can ignore some devices
with drivers which don't use the recommendation. Earlier already
there were attempts to implement this approach but unsuccessful,
see more 3bfe998860e0bfd3ce48784188eaa0d58bf86da1 and
bcdeb589dd9d3b0ff7270d380d043b1882eefdc0 commits.
Thus, it seems effective to use both "Setup Class GUID" and
"Device Interface Class GUID" approaches that will complement each
other. In this case can be keep only the standard GUID's.
1. Now all GUID classes are in the QUuid form and stored in the
constant list of pairs as QPair<uuid, flags>. It allows to avoid the
old heritage related to the pure-C coding style.
2. The second "flags" parameter from the pair is the DWORD input
parameter for the SetupDiGetClassDevs() function which specify the
control options that filter the device information elements. It
allows to pass the appropriate flags for the each used approach
independently.
Tested with the cenumerator example on Windows with Qt4 and then Qt5,
no regressions found.
Task-number: QTBUG-33313
Change-Id: I478905e8ae4b79b7d967e0727d2e1620ad667177
Reviewed-by: Sergey Belyashov <Sergey.Belyashov@gmail.com>
Reviewed-by: Laszlo Papp <lpapp@kde.org>
Diffstat (limited to 'src/serialport/qserialportinfo_win.cpp')
-rw-r--r-- | src/serialport/qserialportinfo_win.cpp | 55 |
1 files changed, 40 insertions, 15 deletions
diff --git a/src/serialport/qserialportinfo_win.cpp b/src/serialport/qserialportinfo_win.cpp index a584d78..51f529e 100644 --- a/src/serialport/qserialportinfo_win.cpp +++ b/src/serialport/qserialportinfo_win.cpp @@ -52,24 +52,28 @@ #include <QtCore/qvariant.h> #include <QtCore/qstringlist.h> +#include <QtCore/quuid.h> +#include <QtCore/qpair.h> QT_BEGIN_NAMESPACE #ifndef Q_OS_WINCE -static const GUID guidsArray[] = +typedef QPair<QUuid, DWORD> GuidFlagsPair; + +static inline const QList<GuidFlagsPair>& guidFlagsPairs() { - // Windows Ports Class GUID - { 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } }, - // Virtual Ports Class GUID (i.e. com0com and etc) - { 0xDF799E12, 0x3C56, 0x421B, { 0xB2, 0x98, 0xB6, 0xD3, 0x64, 0x2B, 0xC8, 0x78 } }, - // Windows Modems Class GUID - { 0x4D36E96D, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } }, - // Eltima Virtual Serial Port Driver v4 GUID - { 0xCC0EF009, 0xB820, 0x42F4, { 0x95, 0xA9, 0x9B, 0xFA, 0x6A, 0x5A, 0xB7, 0xAB } }, - // Advanced Virtual COM Port GUID - { 0x9341CD95, 0x4371, 0x4A37, { 0xA5, 0xAF, 0xFD, 0xB0, 0xA9, 0xD1, 0x96, 0x31 } }, -}; + static const QList<GuidFlagsPair> guidFlagsPairList = QList<GuidFlagsPair>() + // Standard Setup Ports Class GUID + << qMakePair(QUuid(0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18), DWORD(DIGCF_PRESENT)) + // Standard Setup Modems Class GUID + << qMakePair(QUuid(0x4D36E96D, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18), DWORD(DIGCF_PRESENT)) + // Standard Serial Port Device Interface Class GUID + << qMakePair(QUuid(0x86E0D1E0, 0x8089, 0x11D0, 0x9C, 0xE4, 0x08, 0x00, 0x3E, 0x30, 0x1F, 0x73), DWORD(DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)) + // Standard Modem Device Interface Class GUID + << qMakePair(QUuid(0x2C7089AA, 0x2E0E, 0x11D1, 0xB1, 0x14, 0x00, 0xC0, 0x4F, 0xC2, 0xAA, 0xE4), DWORD(DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); + return guidFlagsPairList; +} static QVariant deviceRegistryProperty(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData, @@ -157,6 +161,23 @@ static QString devicePortName(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInf return QString::fromWCharArray(((const wchar_t *)data.constData())); } +class SerialPortNameEqualFunctor +{ +public: + explicit SerialPortNameEqualFunctor(const QString &serialPortName) + : m_serialPortName(serialPortName) + { + } + + bool operator() (const QSerialPortInfo &serialPortInfo) const + { + return serialPortInfo.portName() == m_serialPortName; + } + +private: + const QString &m_serialPortName; +}; + QList<QSerialPortInfo> QSerialPortInfo::availablePorts() { static const QString usbVendorIdentifierPrefix(QStringLiteral("VID_")); @@ -168,10 +189,9 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() static const int productIdentifierSize = 4; QList<QSerialPortInfo> serialPortInfoList; - static const int guidCount = sizeof(guidsArray)/sizeof(guidsArray[0]); - for (int i = 0; i < guidCount; ++i) { - const HDEVINFO deviceInfoSet = ::SetupDiGetClassDevs(&guidsArray[i], NULL, 0, DIGCF_PRESENT); + foreach (const GuidFlagsPair &uniquePair, guidFlagsPairs()) { + const HDEVINFO deviceInfoSet = ::SetupDiGetClassDevs(reinterpret_cast<const GUID *>(&uniquePair.first), NULL, 0, uniquePair.second); if (deviceInfoSet == INVALID_HANDLE_VALUE) return serialPortInfoList; @@ -187,6 +207,11 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() if (s.isEmpty() || s.contains(QStringLiteral("LPT"))) continue; + if (std::find_if(serialPortInfoList.begin(), serialPortInfoList.end(), + SerialPortNameEqualFunctor(s)) != serialPortInfoList.end()) { + continue; + } + serialPortInfo.d_ptr->portName = s; serialPortInfo.d_ptr->device = QSerialPortPrivate::portNameToSystemLocation(s); serialPortInfo.d_ptr->description = |