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 QUsbHidEnumerator::matchAndDispatchChangedDevice(const QString & deviceID, const GUID & guid, WPARAM wParam)
{
    bool rv = false;
    DWORD dwFlag = (DBT_DEVICEARRIVAL == wParam) ? DIGCF_PRESENT : DIGCF_ALLCLASSES;
    dwFlag |= DIGCF_INTERFACEDEVICE;
    HDEVINFO devInfo;
    QString s;
    if(m_vid && m_pid){
        s = QString("VID_%1&PID_%2").arg((ulong)m_vid,4,16,QChar('0')).arg((ulong)m_pid,4,16,QChar('0'));
    }else if(m_vid){
        s = QString("VID_%1").arg((ulong)m_vid,4,16,QChar('0'));
    }else if(m_pid){
        s = QString("PID_%1").arg((ulong)m_pid,4,16,QChar('0'));
    }
    QRegExp idRx(s.toUpper());
    if( (devInfo = SetupDiGetClassDevs(&guid,NULL,NULL,dwFlag)) != INVALID_HANDLE_VALUE )
    {
        SP_INTERFACE_DEVICE_DATA ifData;
        ifData.cbSize=sizeof(ifData);
        for(int i=0; SetupDiEnumDeviceInterfaces(devInfo, NULL, &guid, i, &ifData); i++)
        {
            DWORD needed;
            SetupDiGetDeviceInterfaceDetail(devInfo, &ifData, NULL, 0, &needed, NULL);
            PSP_INTERFACE_DEVICE_DETAIL_DATA detail=(PSP_INTERFACE_DEVICE_DETAIL_DATA)new BYTE[needed];
            detail->cbSize=sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
            SP_DEVINFO_DATA did={sizeof(SP_DEVINFO_DATA)};
            if (SetupDiGetDeviceInterfaceDetail(devInfo, &ifData, detail, needed, NULL, &did)){
                QString path = TCHARToQString(detail->DevicePath);
                if(deviceID.toUpper().contains(path.toUpper())){
                    rv = true;
                    QUsbHidInfo info;
                    info.path = path;
                    bool ready = false;
                    if(m_vid || m_pid){
                        ready = (info.path.toUpper().contains(idRx));
                    }else{
                        ready = true;
                    }
                    if(ready){
                        info.productID = info.vendorID = info.version = 0;
                        getDeviceDetailsWin( &info, devInfo, &did, wParam );
                        if( wParam == DBT_DEVICEARRIVAL )
                            emit deviceDiscovered(info);
                        else if( wParam == DBT_DEVICEREMOVECOMPLETE )
                            emit deviceRemoved(info);
                    }
                    break;
                }
            }
            delete [] detail;
        }
        SetupDiDestroyDeviceInfoList(devInfo);
    }
    return rv;
}
void QUsbHidEnumerator::enumerateDevicesWin( const GUID & guid, QList<QUsbHidInfo>* infoList , unsigned short vid, unsigned short pid)
{
    HDEVINFO devInfo;
    QString s;
    if(vid && pid){
        s = QString("VID_%1&PID_%2").arg((ulong)vid,4,16,QChar('0')).arg((ulong)pid,4,16,QChar('0'));
    }else if(vid){
        s = QString("VID_%1").arg((ulong)vid,4,16,QChar('0'));
    }else if(pid){
        s = QString("PID_%1").arg((ulong)vid,4,16,QChar('0'));
    }
    QRegExp idRx(s.toUpper());
    if( (devInfo = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE)) != INVALID_HANDLE_VALUE)
    {
        SP_INTERFACE_DEVICE_DATA ifData;
        ifData.cbSize=sizeof(ifData);
        for (int devIndex=0;SetupDiEnumDeviceInterfaces(devInfo, NULL, &guid, devIndex, &ifData);++devIndex){
            DWORD needed;
            SetupDiGetDeviceInterfaceDetail(devInfo, &ifData, NULL, 0, &needed, NULL);
            PSP_INTERFACE_DEVICE_DETAIL_DATA detail=(PSP_INTERFACE_DEVICE_DETAIL_DATA)new BYTE[needed];
            detail->cbSize=sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
            SP_DEVINFO_DATA did={sizeof(SP_DEVINFO_DATA)};
            if (SetupDiGetDeviceInterfaceDetail(devInfo, &ifData, detail, needed, NULL, &did)){
                QUsbHidInfo info;
                info.path = TCHARToQString(detail->DevicePath);
                bool ready = false;
                if(vid || pid){
                    ready = (info.path.toUpper().contains(idRx));
                }else{
                    ready = true;
                }
                if(ready){
                    info.vendorID = info.productID = info.version;
                    getDeviceDetailsWin( &info, devInfo, &did );
                    infoList->append(info);
                }
            }
            delete [] detail;
        }




//        SP_DEVINFO_DATA devInfoData;
//        devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
//        for(int i = 0; SetupDiEnumDeviceInfo(devInfo, i, &devInfoData); i++)
//        {
//            QUsbHidInfo info;
//            info.productID = info.vendorID = 0;
//            getDeviceDetailsWin( &info, devInfo, &devInfoData );
//            infoList->append(info);
//        }
        SetupDiDestroyDeviceInfoList(devInfo);
    }
}
/*!
     \internal
*/
static void 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);
    }
}
    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;
                QString devId = TCHARToQString(pDevInf->dbcc_name);
                // devId: \\?\USB#Vid_04e8&Pid_503b#0002F9A9828E0F06#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
                devId.remove("\\\\?\\"); // USB#Vid_04e8&Pid_503b#0002F9A9828E0F06#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
                devId.remove(QRegExp("#\\{(.+)\\}")); // USB#Vid_04e8&Pid_503b#0002F9A9828E0F06
                devId.replace("#", "\\"); // USB\Vid_04e8&Pid_503b\0002F9A9828E0F06
                devId = devId.toUpper();
                //qDebug() << "devname:" << devId;

                DWORD dwFlag = DBT_DEVICEARRIVAL == wParam ? (DIGCF_ALLCLASSES | DIGCF_PRESENT) : DIGCF_ALLCLASSES;
                HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS,NULL,NULL,dwFlag);
                SP_DEVINFO_DATA spDevInfoData;
                spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

                for(int i=0; SetupDiEnumDeviceInfo(hDevInfo, i, &spDevInfoData); i++)
                {
                    DWORD nSize=0 ;
                    TCHAR buf[MAX_PATH];
                    if ( !SetupDiGetDeviceInstanceId(hDevInfo, &spDevInfoData, buf, sizeof(buf), &nSize) )
                        qDebug() << "SetupDiGetDeviceInstanceId():" << GetLastError();
                    if( devId == TCHARToQString(buf) ) // we found a match
                    {
                        QextPortInfo info;
                        getDeviceDetailsWin( &info, hDevInfo, &spDevInfoData, wParam );
                        if( wParam == DBT_DEVICEARRIVAL )
                            emit deviceDiscovered(info);
                        else if( wParam == DBT_DEVICEREMOVECOMPLETE )
                            emit deviceRemoved(info);
                        break;
                    }
                }
                SetupDiDestroyDeviceInfoList(hDevInfo);
            }
        }
        return 0;
    }
    void QextSerialEnumerator::enumerateDevicesWin( HDEVINFO devInfo, const GUID* guidDev, QList<QextPortInfo>* infoList )
    {
        //enumerate the devices
        bool ok = true;
        SP_DEVICE_INTERFACE_DATA ifcData;
        ifcData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
        PSP_DEVICE_INTERFACE_DETAIL_DATA detData = NULL;
        DWORD detDataPredictedLength;
        for (DWORD i = 0; ok; i++) {
            ok = SetupDiEnumDeviceInterfaces(devInfo, NULL, guidDev, i, &ifcData);
            if (ok)
            {
                SP_DEVINFO_DATA devData = {sizeof(SP_DEVINFO_DATA)};
                //check for required detData size
                SetupDiGetDeviceInterfaceDetail(devInfo, & ifcData, NULL, 0, &detDataPredictedLength, & devData);
                detData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(detDataPredictedLength);
                detData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

                //check the details
                if (SetupDiGetDeviceInterfaceDetail(devInfo, &ifcData, detData, detDataPredictedLength, NULL, & devData)) {
                    // Got a device. Get the details.
                    QextPortInfo info;
                    getDeviceDetailsWin( &info, devInfo, &devData );
                    infoList->append(info);
                }
                else
                    qCritical() << "SetupDiGetDeviceInterfaceDetail failed:" << GetLastError();
                delete detData;
            }
            else if (GetLastError() != ERROR_NO_MORE_ITEMS) {
                qCritical() << "SetupDiEnumDeviceInterfaces failed:" << GetLastError();
                return;
            }
        }
        SetupDiDestroyDeviceInfoList(devInfo);
    }