UIMachineWindow.h: public: /* usb support, monitor usb device insertion */ #ifdef Q_WS_WIN32 QStringList m_hostUSBDevices; void updateHostUSBDeviceList(); QString getDriverKey(QString devId); QString getDeviceIdFromDriverKey(QString driverKey); #endif protected: /* vmlite, usb support, monitor usb device insertion */ #ifdef Q_WS_WIN32 void registerUSBDeviceNotification(); void onDeviceChange(MSG *aMsg); #endif UIMachineWindow.cpp: #ifdef Q_WS_WIN32 #include #include #endif /* vmlite, usb support, monitor usb device insertion */ #ifdef Q_WS_WIN32 void UIMachineWindow::registerUSBDeviceNotification() { //return; // this disables USB insertion detection const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } }; const GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } }; updateHostUSBDeviceList(); DEV_BROADCAST_DEVICEINTERFACE NotificationFilter; ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) ); NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE; HDEVNOTIFY hDevNotify = RegisterDeviceNotification(m_pMachineWindow->winId(), &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_HID; hDevNotify = RegisterDeviceNotification(m_pMachineWindow->winId(), &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); } // sync the following with our usb drivers //#define VMLITE_USB_DEVICE_ID "USB\\VID_80EE&PID_CAFE" #define VMLITE_USB_DEVICE_ID "USB\\VMLITEUSBSTUB" typedef struct _DEVICE_CHANGE_PARAMETER { UIMachineWindow* pThis; DWORD dbch_devicetype; WPARAM kind; WCHAR dbcc_name[MAX_PATH]; } DEVICE_CHANGE_PARAMETER, *PDEVICE_CHANGE_PARAMETER; static DWORD WINAPI deviceChangeThreadProc(LPVOID Parameter) { PDEVICE_CHANGE_PARAMETER pDeviceChange = (PDEVICE_CHANGE_PARAMETER)Parameter; UIMachineWindow* pThis = pDeviceChange->pThis; WPARAM kind = pDeviceChange->kind; /* pDevInf->dbcc_name, e.g. \\?\USB#VID_04e8&PID_503b#0002F9A9828E0F06#{a5dcbf10-6530-11d2-901f-00c04fb951ed} szDevId: USB#VID_04e8&PID_503b#0002F9A9828E0F06 szClass: USB */ // extract the devId portion, covert '#' to '\' QString devIdStr((QChar *)pDeviceChange->dbcc_name + 4, wcslen(pDeviceChange->dbcc_name + 4)); devIdStr = devIdStr.left(devIdStr.lastIndexOf('#')); devIdStr = devIdStr.replace('#', '\\'); free(pDeviceChange); // address is the driver key, e.g., {36FC9E60-C465-11CF-8056-444553540000}\0025 QString address = pThis->getDriverKey(devIdStr); // only hanlde devices that are really inserted, // when an attached device is released, arrival event will come here too, ignore such insertion if (pThis->m_hostUSBDevices.contains(address)) { return -1; } /* Get HOST: */ CHost host = vboxGlobal().virtualBox().GetHost(); /* find the host usb device, and attach it, try 180 secs */ for (int i=0; i<2 * 180; i++) { // this is extremely import, freezes otherwise QCoreApplication::processEvents(); /* Get USB devices list: */ CHostUSBDeviceVector devices = host.GetUSBDevices(); foreach (const CHostUSBDevice hostDevice, devices) { if (hostDevice.GetAddress() == address) { /* Get current console: */ CConsole console = pThis->session().GetConsole(); CUSBDevice attachedDevice = console.FindUSBDeviceById(hostDevice.GetId()); if (attachedDevice.isNull()) { console.AttachUSBDevice(hostDevice.GetId()); return console.isOk() ? 0 : -1; } else { return -1; } } } Sleep(500); } return -1; } /* get driver key for the specified usb device id, from registry, so works even if device is off or deteched use registry to read the driver key, we don't use Setup api because the device is not active e.g., devId: USB\VID_046D&PID_C016\5&9e58382&0&1 */ static QString getDriverKeyThroughRegistry(const QString& devId) { WCHAR keyName[MAX_PATH]; //e.g., HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_046D&PID_C016\5&9e58382&0&1 swprintf(keyName, L"SYSTEM\\CurrentControlSet\\Enum\\%ls", (WCHAR *)devId.unicode()); HKEY hkey; long lret = RegOpenKeyW(HKEY_LOCAL_MACHINE, keyName, &hkey); if (lret != ERROR_SUCCESS) return ""; WCHAR driver[MAX_PATH]; DWORD type; DWORD size = sizeof(driver); lret = RegQueryValueExW(hkey, L"Driver", 0, &type, (PBYTE)driver, &size); RegCloseKey(hkey); if (lret == ERROR_SUCCESS) { return QString((QChar *)driver, wcslen(driver)); } else { return ""; } } void UIMachineWindow::onDeviceChange(MSG *aMsg) { if (aMsg->wParam != DBT_DEVICEREMOVECOMPLETE && aMsg->wParam != DBT_DEVICEARRIVAL) return; PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)aMsg->lParam; if ( pHdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE) { return; } if ( DBT_DEVICEREMOVECOMPLETE == aMsg->wParam) { updateHostUSBDeviceList(); // need to remove the device that is just removed, in case our updated list still has it in the list PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr; /* pDevInf->dbcc_name, e.g. \\?\USB#VID_04e8&PID_503b#0002F9A9828E0F06#{a5dcbf10-6530-11d2-901f-00c04fb951ed} */ // extract the devId portion, covert '#' to '\' QString devIdStr((QChar *)pDevInf->dbcc_name + 4, wcslen(pDevInf->dbcc_name + 4)); devIdStr = devIdStr.left(devIdStr.lastIndexOf('#')); devIdStr = devIdStr.replace('#', '\\'); // address is the driver key, e.g., {36FC9E60-C465-11CF-8056-444553540000}\0025 QString address = getDriverKeyThroughRegistry(devIdStr); if (!address.isEmpty() && m_hostUSBDevices.contains(address)) { m_hostUSBDevices.removeAll(address); } } else if ( DBT_DEVICEARRIVAL == aMsg->wParam) { PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr; if (!m_pMachineWindow->isActiveWindow()) { updateHostUSBDeviceList(); return; } /* pDevInf->dbcc_name, e.g. \\?\USB#VID_04e8&PID_503b#0002F9A9828E0F06#{a5dcbf10-6530-11d2-901f-00c04fb951ed} szDevId: USB#VID_04e8&PID_503b#0002F9A9828E0F06 szClass: USB */ // extract the devId portion, covert '#' to '\' QString devIdStr((QChar *)pDevInf->dbcc_name + 4, wcslen(pDevInf->dbcc_name + 4)); devIdStr = devIdStr.left(devIdStr.lastIndexOf('#')); devIdStr = devIdStr.replace('#', '\\'); // when an usb device is attached, our vmlite virtualizazed usb will come here, ignore them if (devIdStr.startsWith(VMLITE_USB_DEVICE_ID, Qt::CaseInsensitive)) { updateHostUSBDeviceList(); return; } DWORD ThreadId; PDEVICE_CHANGE_PARAMETER param = (PDEVICE_CHANGE_PARAMETER)malloc(sizeof(DEVICE_CHANGE_PARAMETER)); if (param) { param->pThis = this; param->dbch_devicetype = pHdr->dbch_devicetype; param->kind = aMsg->wParam; wcscpy(param->dbcc_name, pDevInf->dbcc_name); HANDLE ThreadHandle = CreateThread( NULL, 0, deviceChangeThreadProc, param, 0, &ThreadId ); } } } /* get driver key for the original host usb device being attached from the attached device */ static QString getDriverKeyForOriginalDevice(const CHostUSBDevice& attachedDevice) { // the attached device and the host device have same vendor id, product id, etc. unsigned short vid = attachedDevice.GetVendorId(); unsigned short pid = attachedDevice.GetProductId(); // for non attached usb device, address is the driver key, e.g., {36FC9E60-C465-11CF-8056-444553540000}\0025 // attached host device has address of device name QString address = attachedDevice.GetAddress(); if (!address.startsWith("\\\\?\\")) { return address; } /* pDevInf->dbcc_name, e.g. \\?\USB#VID_04e8&PID_503b#0002F9A9828E0F06#{a5dcbf10-6530-11d2-901f-00c04fb951ed} szDevId: USB#VID_04e8&PID_503b#0002F9A9828E0F06 */ address = address.right(address.length() - 4); int pos = address.lastIndexOf('#'); address = address.left(pos); // the string after 2nd # is the serial #, same as the original device being attached pos = address.indexOf("#"); address = address.right(address.length() - pos - 1); pos = address.indexOf("#"); address = address.right(address.length() - pos - 1); WCHAR *serial = (WCHAR *)address.unicode(); // use registry to read the driver key, we don't use Setup api because the device is not active // e.g., HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_046D&PID_C016\5&9e58382&0&1 WCHAR devId[MAX_PATH]; swprintf(devId, L"SYSTEM\\CurrentControlSet\\Enum\\USB\\VID_%04x&PID_%04x\\%ls", vid, pid, serial); HKEY hkey; long lret = RegOpenKeyW(HKEY_LOCAL_MACHINE, devId, &hkey); if (lret != ERROR_SUCCESS) return ""; WCHAR driver[MAX_PATH]; DWORD type; DWORD size = sizeof(driver); lret = RegQueryValueExW(hkey, L"Driver", 0, &type, (PBYTE)driver, &size); RegCloseKey(hkey); if (lret == ERROR_SUCCESS) { return QString((QChar *)driver, wcslen(driver)); } else { return ""; } } void UIMachineWindow::updateHostUSBDeviceList() { m_hostUSBDevices.clear(); /* Get HOST: */ CHost host = vboxGlobal().virtualBox().GetHost(); /* Get USB devices list: */ CHostUSBDeviceVector devices = host.GetUSBDevices(); foreach (const CHostUSBDevice hostDevice, devices) { // address is the driver key, e.g., {36FC9E60-C465-11CF-8056-444553540000}\0025 QString address = hostDevice.GetAddress(); if (address.startsWith("\\\\?\\")) /* attached host device has address of device name */ { address = getDriverKeyForOriginalDevice(hostDevice); } m_hostUSBDevices << address; } } /* Get driver key from a usb id, devId: USB\Vid_04e8&Pid_503b\0002F9A9828E0F06 we use driver key to identify a host usb device, as this is unique, vid/pid/serial is not unique because serial might be emppty */ QString UIMachineWindow::getDriverKey(QString devId) { HDEVINFO hDevInfo = SetupDiGetClassDevsW(NULL, L"USB", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT); if( INVALID_HANDLE_VALUE == hDevInfo ) { return ""; } WCHAR driverKey[MAX_PATH] = L""; SP_DEVINFO_DATA spDevInfoData; spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA); for(int i=0; SetupDiEnumDeviceInfo(hDevInfo, i, &spDevInfoData); i++) { DWORD nSize = 0; WCHAR buf[MAX_PATH]; if ( !SetupDiGetDeviceInstanceIdW(hDevInfo, &spDevInfoData, buf, sizeof(buf), &nSize) ) return ""; if (0 == QString((QChar *)buf, wcslen(buf)).compare(devId, Qt::CaseInsensitive)) { nSize = 0; if ( SetupDiGetDeviceRegistryPropertyW(hDevInfo, &spDevInfoData, SPDRP_DRIVER, NULL, (PBYTE)buf, sizeof(buf), &nSize) ) { wcscpy(driverKey, buf); } break; } } SetupDiDestroyDeviceInfoList(hDevInfo); if (driverKey[0]) return QString((QChar *)driverKey, wcslen(driverKey)); else return ""; } /* Get usb id from driver key, devId: USB\Vid_04e8&Pid_503b\0002F9A9828E0F06, driver key: {36FC9E60-C465-11CF-8056-444553540000}\0025 */ QString UIMachineWindow::getDeviceIdFromDriverKey(QString driverKey) { HDEVINFO hDevInfo = SetupDiGetClassDevsW(NULL, L"USB", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT); if( INVALID_HANDLE_VALUE == hDevInfo ) { return ""; } WCHAR deviceId[MAX_PATH] = L""; SP_DEVINFO_DATA spDevInfoData; spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA); for(int i=0; SetupDiEnumDeviceInfo(hDevInfo, i, &spDevInfoData); i++) { DWORD nSize = 0; WCHAR buf[MAX_PATH]; if ( !SetupDiGetDeviceInstanceIdW(hDevInfo, &spDevInfoData, buf, sizeof(buf), &nSize) ) return ""; wcscpy(deviceId, buf); nSize = 0; if ( SetupDiGetDeviceRegistryPropertyW(hDevInfo, &spDevInfoData, SPDRP_DRIVER, NULL, (PBYTE)buf, sizeof(buf), &nSize) ) { if (0 == QString((QChar *)buf, wcslen(buf)).compare(driverKey, Qt::CaseInsensitive)) { break; } } deviceId[0] = 0; } SetupDiDestroyDeviceInfoList(hDevInfo); if (deviceId[0]) return QString((QChar *)deviceId, wcslen(deviceId)); else return ""; } #endif /* Q_WS_WIN32 */ UIMachineWindowNormal.cpp: UIMachineWindowNormal::UIMachineWindowNormal(UIMachineLogic *pMachineLogic, ulong uScreenId) : QIWithRetranslateUI2(0, Qt::Window) , UIMachineWindow(pMachineLogic, uScreenId) , m_pIndicatorsPool(new UIIndicatorsPool(pMachineLogic->uisession()->session(), this)) , m_pIdleTimer(0) { ........ // add as last line /* vmlite, usb and dnd support, monitor usb device insertion */ #ifdef Q_WS_WIN32 registerUSBDeviceNotification(); #endif } UIMachineWindowFullscreen.cpp: UIMachineWindowFullscreen::UIMachineWindowFullscreen(UIMachineLogic *pMachineLogic, ulong uScreenId) : QIWithRetranslateUI2(0, Qt::FramelessWindowHint) , UIMachineWindow(pMachineLogic, uScreenId) , m_pMainMenu(0) , m_pMiniToolBar(0) { ........ // add as last line /* vmlite, usb and dnd support, monitor usb device insertion */ #ifdef Q_WS_WIN32 registerUSBDeviceNotification(); #endif }