You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
7.5 KiB
223 lines
7.5 KiB
14 years ago
|
|
||
|
|
||
|
|
||
|
#include "qextserialenumerator.h"
|
||
|
#include <QDebug>
|
||
|
#include <QMetaType>
|
||
|
|
||
|
#include <objbase.h>
|
||
|
#include <initguid.h>
|
||
14 years ago
|
//#include "qextserialport.h"
|
||
14 years ago
|
#include <QRegExp>
|
||
14 years ago
|
#ifdef Q_OS_WIN
|
||
|
#ifndef _MSC_VER
|
||
|
#include <windows.h>
|
||
|
#include <dbt.h>
|
||
|
#include <QtCore/qglobal.h>
|
||
|
#endif
|
||
|
#endif
|
||
14 years ago
|
|
||
|
QextSerialEnumerator::QextSerialEnumerator( )
|
||
|
{
|
||
|
if( !QMetaType::isRegistered( QMetaType::type("QextPortInfo") ) )
|
||
|
qRegisterMetaType<QextPortInfo>("QextPortInfo");
|
||
|
#if (defined QT_GUI_LIB)
|
||
|
notificationWidget = 0;
|
||
|
#endif // Q_OS_WIN
|
||
|
}
|
||
|
|
||
|
QextSerialEnumerator::~QextSerialEnumerator( )
|
||
|
{
|
||
|
#if (defined QT_GUI_LIB)
|
||
|
if( notificationWidget )
|
||
|
delete notificationWidget;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// see http://msdn.microsoft.com/en-us/library/ms791134.aspx for list of GUID classes
|
||
|
#ifndef GUID_DEVCLASS_PORTS
|
||
|
DEFINE_GUID(GUID_DEVCLASS_PORTS, 0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 );
|
||
|
#endif
|
||
|
|
||
|
/* Gordon Schumacher's macros for TCHAR -> QString conversions and vice versa */
|
||
|
#ifdef UNICODE
|
||
|
#define QStringToTCHAR(x) (wchar_t*) x.utf16()
|
||
|
#define PQStringToTCHAR(x) (wchar_t*) x->utf16()
|
||
|
#define TCHARToQString(x) QString::fromUtf16((ushort*)(x))
|
||
|
#define TCHARToQStringN(x,y) QString::fromUtf16((ushort*)(x),(y))
|
||
|
#else
|
||
|
#define QStringToTCHAR(x) x.local8Bit().constData()
|
||
|
#define PQStringToTCHAR(x) x->local8Bit().constData()
|
||
|
#define TCHARToQString(x) QString::fromLocal8Bit((x))
|
||
|
#define TCHARToQStringN(x,y) QString::fromLocal8Bit((x),(y))
|
||
|
#endif /*UNICODE*/
|
||
|
|
||
|
|
||
|
//static
|
||
|
QString QextSerialEnumerator::getRegKeyValue(HKEY key, LPCTSTR property)
|
||
|
{
|
||
|
DWORD size = 0;
|
||
|
DWORD type;
|
||
|
RegQueryValueEx(key, property, NULL, NULL, NULL, & size);
|
||
|
BYTE* buff = new BYTE[size];
|
||
|
QString result;
|
||
|
if( RegQueryValueEx(key, property, NULL, &type, buff, & size) == ERROR_SUCCESS )
|
||
|
result = TCHARToQString(buff);
|
||
|
RegCloseKey(key);
|
||
|
delete [] buff;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//static
|
||
|
QString QextSerialEnumerator::getDeviceProperty(HDEVINFO devInfo, PSP_DEVINFO_DATA devData, DWORD property)
|
||
|
{
|
||
|
DWORD buffSize = 0;
|
||
|
SetupDiGetDeviceRegistryProperty(devInfo, devData, property, NULL, NULL, 0, & buffSize);
|
||
|
BYTE* buff = new BYTE[buffSize];
|
||
|
SetupDiGetDeviceRegistryProperty(devInfo, devData, property, NULL, buff, buffSize, NULL);
|
||
|
QString result = TCHARToQString(buff);
|
||
|
delete [] buff;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
QList<QextPortInfo> QextSerialEnumerator::getPorts()
|
||
|
{
|
||
|
QList<QextPortInfo> ports;
|
||
|
enumerateDevicesWin(GUID_DEVCLASS_PORTS, &ports);
|
||
|
return ports;
|
||
|
}
|
||
|
|
||
|
void QextSerialEnumerator::enumerateDevicesWin( const GUID & guid, QList<QextPortInfo>* infoList )
|
||
|
{
|
||
|
HDEVINFO devInfo;
|
||
|
if( (devInfo = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT)) != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
SP_DEVINFO_DATA devInfoData;
|
||
|
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||
|
for(int i = 0; SetupDiEnumDeviceInfo(devInfo, i, &devInfoData); i++)
|
||
|
{
|
||
|
QextPortInfo info;
|
||
|
info.productID = info.vendorID = 0;
|
||
|
getDeviceDetailsWin( &info, devInfo, &devInfoData );
|
||
|
infoList->append(info);
|
||
|
}
|
||
|
SetupDiDestroyDeviceInfoList(devInfo);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef QT_GUI_LIB
|
||
|
bool QextSerialRegistrationWidget::winEvent( MSG* message, long* result )
|
||
|
{
|
||
|
if ( message->message == WM_DEVICECHANGE ) {
|
||
|
qese->onDeviceChangeWin( message->wParam, message->lParam );
|
||
|
*result = 1;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void QextSerialEnumerator::setUpNotifications( )
|
||
|
{
|
||
|
#ifdef QT_GUI_LIB
|
||
|
if(notificationWidget)
|
||
|
return;
|
||
|
notificationWidget = new QextSerialRegistrationWidget(this);
|
||
|
|
||
|
DEV_BROADCAST_DEVICEINTERFACE dbh;
|
||
|
ZeroMemory(&dbh, sizeof(dbh));
|
||
|
dbh.dbcc_size = sizeof(dbh);
|
||
|
dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
|
||
|
CopyMemory(&dbh.dbcc_classguid, &GUID_DEVCLASS_PORTS, sizeof(GUID));
|
||
|
if( RegisterDeviceNotification( notificationWidget->winId( ), &dbh, DEVICE_NOTIFY_WINDOW_HANDLE ) == NULL)
|
||
|
qWarning() << "RegisterDeviceNotification failed:" << GetLastError();
|
||
|
// setting up notifications doesn't tell us about devices already connected
|
||
|
// so get those manually
|
||
|
foreach( QextPortInfo port, getPorts() )
|
||
|
emit deviceDiscovered( port );
|
||
|
#else
|
||
|
qWarning("QextSerialEnumerator: GUI not enabled - can't register for device notifications.");
|
||
|
#endif // QT_GUI_LIB
|
||
|
}
|
||
|
|
||
|
LRESULT QextSerialEnumerator::onDeviceChangeWin( WPARAM wParam, LPARAM lParam )
|
||
|
{
|
||
|
if ( DBT_DEVICEARRIVAL == wParam || DBT_DEVICEREMOVECOMPLETE == wParam )
|
||
|
{
|
||
|
PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lParam;
|
||
|
if( pHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE )
|
||
|
{
|
||
|
PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;
|
||
|
// delimiters are different across APIs...change to backslash. ugh.
|
||
|
QString deviceID = TCHARToQString(pDevInf->dbcc_name).toUpper().replace("#", "\\");
|
||
|
|
||
|
matchAndDispatchChangedDevice(deviceID, GUID_DEVCLASS_PORTS, wParam);
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
bool QextSerialEnumerator::matchAndDispatchChangedDevice(const QString & deviceID, const GUID & guid, WPARAM wParam)
|
||
|
{
|
||
|
bool rv = false;
|
||
|
DWORD dwFlag = (DBT_DEVICEARRIVAL == wParam) ? DIGCF_PRESENT : DIGCF_ALLCLASSES;
|
||
|
HDEVINFO devInfo;
|
||
|
if( (devInfo = SetupDiGetClassDevs(&guid,NULL,NULL,dwFlag)) != INVALID_HANDLE_VALUE )
|
||
|
{
|
||
|
SP_DEVINFO_DATA spDevInfoData;
|
||
|
spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||
|
for(int i=0; SetupDiEnumDeviceInfo(devInfo, i, &spDevInfoData); i++)
|
||
|
{
|
||
|
DWORD nSize=0 ;
|
||
|
TCHAR buf[MAX_PATH];
|
||
|
if ( SetupDiGetDeviceInstanceId(devInfo, &spDevInfoData, buf, MAX_PATH, &nSize) &&
|
||
|
deviceID.contains(TCHARToQString(buf))) // we found a match
|
||
|
{
|
||
|
rv = true;
|
||
|
QextPortInfo info;
|
||
|
info.productID = info.vendorID = 0;
|
||
|
getDeviceDetailsWin( &info, devInfo, &spDevInfoData, wParam );
|
||
|
if( wParam == DBT_DEVICEARRIVAL )
|
||
|
emit deviceDiscovered(info);
|
||
|
else if( wParam == DBT_DEVICEREMOVECOMPLETE )
|
||
|
emit deviceRemoved(info);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
SetupDiDestroyDeviceInfoList(devInfo);
|
||
|
}
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
bool QextSerialEnumerator::getDeviceDetailsWin( QextPortInfo* portInfo, HDEVINFO devInfo, PSP_DEVINFO_DATA devData, WPARAM wParam )
|
||
|
{
|
||
|
portInfo->friendName = getDeviceProperty(devInfo, devData, SPDRP_FRIENDLYNAME);
|
||
|
if( wParam == DBT_DEVICEARRIVAL)
|
||
|
portInfo->physName = getDeviceProperty(devInfo, devData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME);
|
||
|
portInfo->enumName = getDeviceProperty(devInfo, devData, SPDRP_ENUMERATOR_NAME);
|
||
|
QString hardwareIDs = getDeviceProperty(devInfo, devData, SPDRP_HARDWAREID);
|
||
|
HKEY devKey = SetupDiOpenDevRegKey(devInfo, devData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
|
||
14 years ago
|
|
||
14 years ago
|
QRegExp rx("^COM(\\d+)");
|
||
|
QString fullName(getRegKeyValue(devKey, TEXT("PortName")));
|
||
|
if(fullName.contains(rx)) {
|
||
|
int portnum = rx.cap(1).toInt();
|
||
|
if(portnum > 9) // COM ports greater than 9 need \\.\ prepended
|
||
|
fullName.prepend("\\\\.\\");
|
||
14 years ago
|
}
|
||
|
|
||
|
portInfo->portName = fullName;
|
||
14 years ago
|
QRegExp idRx("VID_(\\w+)&PID_(\\w+)");
|
||
|
if( hardwareIDs.toUpper().contains(idRx) )
|
||
|
{
|
||
|
bool dummy;
|
||
|
portInfo->vendorID = idRx.cap(1).toInt(&dummy, 16);
|
||
|
portInfo->productID = idRx.cap(2).toInt(&dummy, 16);
|
||
|
//qDebug() << "got vid:" << vid << "pid:" << pid;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|