|
qCNC 0.82-alpha
|
00001 00002 00003 00004 #include "qextserialenumerator.h" 00005 #include <QDebug> 00006 #include <QMetaType> 00007 00008 #include <objbase.h> 00009 #include <initguid.h> 00010 #include "qextserialport.h" 00011 #include <QRegExp> 00012 00013 QextSerialEnumerator::QextSerialEnumerator( ) 00014 { 00015 if( !QMetaType::isRegistered( QMetaType::type("QextPortInfo") ) ) 00016 qRegisterMetaType<QextPortInfo>("QextPortInfo"); 00017 #if (defined QT_GUI_LIB) 00018 notificationWidget = 0; 00019 #endif // Q_OS_WIN 00020 } 00021 00022 QextSerialEnumerator::~QextSerialEnumerator( ) 00023 { 00024 #if (defined QT_GUI_LIB) 00025 if( notificationWidget ) 00026 delete notificationWidget; 00027 #endif 00028 } 00029 00030 00031 00032 // see http://msdn.microsoft.com/en-us/library/ms791134.aspx for list of GUID classes 00033 #ifndef GUID_DEVCLASS_PORTS 00034 DEFINE_GUID(GUID_DEVCLASS_PORTS, 0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 ); 00035 #endif 00036 00037 /* Gordon Schumacher's macros for TCHAR -> QString conversions and vice versa */ 00038 #ifdef UNICODE 00039 #define QStringToTCHAR(x) (wchar_t*) x.utf16() 00040 #define PQStringToTCHAR(x) (wchar_t*) x->utf16() 00041 #define TCHARToQString(x) QString::fromUtf16((ushort*)(x)) 00042 #define TCHARToQStringN(x,y) QString::fromUtf16((ushort*)(x),(y)) 00043 #else 00044 #define QStringToTCHAR(x) x.local8Bit().constData() 00045 #define PQStringToTCHAR(x) x->local8Bit().constData() 00046 #define TCHARToQString(x) QString::fromLocal8Bit((x)) 00047 #define TCHARToQStringN(x,y) QString::fromLocal8Bit((x),(y)) 00048 #endif /*UNICODE*/ 00049 00050 00051 //static 00052 QString QextSerialEnumerator::getRegKeyValue(HKEY key, LPCTSTR property) 00053 { 00054 DWORD size = 0; 00055 DWORD type; 00056 RegQueryValueEx(key, property, NULL, NULL, NULL, & size); 00057 BYTE* buff = new BYTE[size]; 00058 QString result; 00059 if( RegQueryValueEx(key, property, NULL, &type, buff, & size) == ERROR_SUCCESS ) 00060 result = TCHARToQString(buff); 00061 RegCloseKey(key); 00062 delete [] buff; 00063 return result; 00064 } 00065 00066 //static 00067 QString QextSerialEnumerator::getDeviceProperty(HDEVINFO devInfo, PSP_DEVINFO_DATA devData, DWORD property) 00068 { 00069 DWORD buffSize = 0; 00070 SetupDiGetDeviceRegistryProperty(devInfo, devData, property, NULL, NULL, 0, & buffSize); 00071 BYTE* buff = new BYTE[buffSize]; 00072 SetupDiGetDeviceRegistryProperty(devInfo, devData, property, NULL, buff, buffSize, NULL); 00073 QString result = TCHARToQString(buff); 00074 delete [] buff; 00075 return result; 00076 } 00077 00078 QList<QextPortInfo> QextSerialEnumerator::getPorts() 00079 { 00080 QList<QextPortInfo> ports; 00081 enumerateDevicesWin(GUID_DEVCLASS_PORTS, &ports); 00082 return ports; 00083 } 00084 00085 void QextSerialEnumerator::enumerateDevicesWin( const GUID & guid, QList<QextPortInfo>* infoList ) 00086 { 00087 HDEVINFO devInfo; 00088 if( (devInfo = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT)) != INVALID_HANDLE_VALUE) 00089 { 00090 SP_DEVINFO_DATA devInfoData; 00091 devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); 00092 for(int i = 0; SetupDiEnumDeviceInfo(devInfo, i, &devInfoData); i++) 00093 { 00094 QextPortInfo info; 00095 info.productID = info.vendorID = 0; 00096 getDeviceDetailsWin( &info, devInfo, &devInfoData ); 00097 infoList->append(info); 00098 } 00099 SetupDiDestroyDeviceInfoList(devInfo); 00100 } 00101 } 00102 00103 #ifdef QT_GUI_LIB 00104 bool QextSerialRegistrationWidget::winEvent( MSG* message, long* result ) 00105 { 00106 if ( message->message == WM_DEVICECHANGE ) { 00107 qese->onDeviceChangeWin( message->wParam, message->lParam ); 00108 *result = 1; 00109 return true; 00110 } 00111 return false; 00112 } 00113 #endif 00114 00115 void QextSerialEnumerator::setUpNotifications( ) 00116 { 00117 #ifdef QT_GUI_LIB 00118 if(notificationWidget) 00119 return; 00120 notificationWidget = new QextSerialRegistrationWidget(this); 00121 00122 DEV_BROADCAST_DEVICEINTERFACE dbh; 00123 ZeroMemory(&dbh, sizeof(dbh)); 00124 dbh.dbcc_size = sizeof(dbh); 00125 dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; 00126 CopyMemory(&dbh.dbcc_classguid, &GUID_DEVCLASS_PORTS, sizeof(GUID)); 00127 if( RegisterDeviceNotification( notificationWidget->winId( ), &dbh, DEVICE_NOTIFY_WINDOW_HANDLE ) == NULL) 00128 qWarning() << "RegisterDeviceNotification failed:" << GetLastError(); 00129 // setting up notifications doesn't tell us about devices already connected 00130 // so get those manually 00131 foreach( QextPortInfo port, getPorts() ) 00132 emit deviceDiscovered( port ); 00133 #else 00134 qWarning("QextSerialEnumerator: GUI not enabled - can't register for device notifications."); 00135 #endif // QT_GUI_LIB 00136 } 00137 00138 LRESULT QextSerialEnumerator::onDeviceChangeWin( WPARAM wParam, LPARAM lParam ) 00139 { 00140 if ( DBT_DEVICEARRIVAL == wParam || DBT_DEVICEREMOVECOMPLETE == wParam ) 00141 { 00142 PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lParam; 00143 if( pHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE ) 00144 { 00145 PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr; 00146 // delimiters are different across APIs...change to backslash. ugh. 00147 QString deviceID = TCHARToQString(pDevInf->dbcc_name).toUpper().replace("#", "\\"); 00148 00149 matchAndDispatchChangedDevice(deviceID, GUID_DEVCLASS_PORTS, wParam); 00150 } 00151 } 00152 return 0; 00153 } 00154 00155 bool QextSerialEnumerator::matchAndDispatchChangedDevice(const QString & deviceID, const GUID & guid, WPARAM wParam) 00156 { 00157 bool rv = false; 00158 DWORD dwFlag = (DBT_DEVICEARRIVAL == wParam) ? DIGCF_PRESENT : DIGCF_ALLCLASSES; 00159 HDEVINFO devInfo; 00160 if( (devInfo = SetupDiGetClassDevs(&guid,NULL,NULL,dwFlag)) != INVALID_HANDLE_VALUE ) 00161 { 00162 SP_DEVINFO_DATA spDevInfoData; 00163 spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA); 00164 for(int i=0; SetupDiEnumDeviceInfo(devInfo, i, &spDevInfoData); i++) 00165 { 00166 DWORD nSize=0 ; 00167 TCHAR buf[MAX_PATH]; 00168 if ( SetupDiGetDeviceInstanceId(devInfo, &spDevInfoData, buf, MAX_PATH, &nSize) && 00169 deviceID.contains(TCHARToQString(buf))) // we found a match 00170 { 00171 rv = true; 00172 QextPortInfo info; 00173 info.productID = info.vendorID = 0; 00174 getDeviceDetailsWin( &info, devInfo, &spDevInfoData, wParam ); 00175 if( wParam == DBT_DEVICEARRIVAL ) 00176 emit deviceDiscovered(info); 00177 else if( wParam == DBT_DEVICEREMOVECOMPLETE ) 00178 emit deviceRemoved(info); 00179 break; 00180 } 00181 } 00182 SetupDiDestroyDeviceInfoList(devInfo); 00183 } 00184 return rv; 00185 } 00186 00187 bool QextSerialEnumerator::getDeviceDetailsWin( QextPortInfo* portInfo, HDEVINFO devInfo, PSP_DEVINFO_DATA devData, WPARAM wParam ) 00188 { 00189 portInfo->friendName = getDeviceProperty(devInfo, devData, SPDRP_FRIENDLYNAME); 00190 if( wParam == DBT_DEVICEARRIVAL) 00191 portInfo->physName = getDeviceProperty(devInfo, devData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME); 00192 portInfo->enumName = getDeviceProperty(devInfo, devData, SPDRP_ENUMERATOR_NAME); 00193 QString hardwareIDs = getDeviceProperty(devInfo, devData, SPDRP_HARDWAREID); 00194 HKEY devKey = SetupDiOpenDevRegKey(devInfo, devData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); 00195 portInfo->portName = QextSerialPort::fullPortNameWin( getRegKeyValue(devKey, TEXT("PortName")) ); 00196 QRegExp idRx("VID_(\\w+)&PID_(\\w+)"); 00197 if( hardwareIDs.toUpper().contains(idRx) ) 00198 { 00199 bool dummy; 00200 portInfo->vendorID = idRx.cap(1).toInt(&dummy, 16); 00201 portInfo->productID = idRx.cap(2).toInt(&dummy, 16); 00202 //qDebug() << "got vid:" << vid << "pid:" << pid; 00203 } 00204 return true; 00205 } 00206