qCNC 0.82-alpha
/home/trilog/Desktop/project/gui/Final/src/lib/qextserialport/qextserialenumerator_win.cpp
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Defines