Страницы

Поиск по вопросам

вторник, 31 марта 2020 г.

Как получить информацию о подключенном устройстве?

#linux #windows #qt #winapi #usb


Я пишу на С++, использую Qt под Windows. Мне надо получить: название модели, изготовителя,
серийный номер устройства(видео камеры, фото , квадрокоптера , флешки или SD Card)
и путь до устройства. Желательно кроссплатформенное решение.


Есть ответ SetupDiGetDeviceProperty. Но тут не кроссплатформенное решение , к тому
же я не совсем понимаю как получить путь до устройства.
Читал о библиотеки libusb. Но тут не выводятся название модели, изготовителя, серийный
номер устройства. То что выводиться :

Dev (bus 2, device 0): 8086 - 1E31
Dev (bus 1, device 4): 04A9 - 1795
Dev (bus 1, device 3): A4Tech - USB Mouse
Dev (bus 3, device 0): 8086 - 1E26
Dev (bus 1, device 1): 8087 - 0024
Dev (bus 1, device 0): 8086 - 1E2D
Dev (bus 1, device 2): 0BDA - 0151
Dev (bus 1, device 6): Logitech Inc. - Logitech USB Headset H340
Dev (bus 3, device 2): 8087 - 0024
Dev (bus 3, device 3): Logitech - USB Keyboard
Dev (bus 3, device 1): 04A9 - 3206


Хотя была вставлена флешка и подключена камера.
Есть изящное решение этой задачи. Если кто сталкивался с такой задачей поделитесь
кодом пожалуйста.
    


Ответы

Ответ 1



К сожалению, используя библиотеку libusb под Windows нельзя вытянуть всю эту информацию без установки специального драйвера WinUSB. Можно только получить VID и PID (шестнадцатеричные значения типа 8086 - 1E31 в вашем примере), и по ним найти производителя и устройство в таблице известных идентификаторов, например здесь. Производителя и серийный номер можно получить, используя Setup API и IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION. Букву диска тоже можно получить только средствами Setup API, это несколько сложнее. Для этого нужно вначале построить таблицу номеров дисков для всех используемых букв дисков с помощью IOCTL_STORAGE_GET_DEVICE_NUMBER; затем открыть интересующее устройство (запоминающее устройство, которое является дочерним для USB-устройства), найти его номер тем же IOCTL, сравнить его со значениями из таблицы и таким образом определить букву. Как-то так: #include #include #include #include #include #include #include #undef LowSpeed #include #include #pragma comment(lib,"Setupapi.lib") void ErrorMes(LPCTSTR lpszFunction) { // Retrieve the system error message for the last-error code LPVOID lpMsgBuf; LPVOID lpDisplayBuf; DWORD dw = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); // Display the error message lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen(lpszFunction) + 40) * sizeof(TCHAR)); wprintf(L"%s failed with error %d: %s", lpszFunction, dw, lpMsgBuf); LocalFree(lpMsgBuf); LocalFree(lpDisplayBuf); } //Поиск номера диска для USB-устройства BOOL FindDiskNumber(LPCWSTR match, STORAGE_DEVICE_NUMBER* lpret){ BOOL retval = FALSE; DEVPROPTYPE dpt=0; wchar_t buffer[1024]=L""; TCHAR id_upper[1024]=L""; DWORD RequiredSize = 0; SP_DEVINFO_DATA devinfo = { 0 }; SP_DEVICE_INTERFACE_DATA deviceInterface = { 0 }; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetail = NULL; BOOL res; HDEVINFO deviceInfoHandle = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (deviceInfoHandle != INVALID_HANDLE_VALUE) { int deviceIndex = 0; while (true) { ZeroMemory(&deviceInterface,sizeof(deviceInterface)); deviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); //получение всех дисков if (SetupDiEnumDeviceInterfaces(deviceInfoHandle, 0, &GUID_DEVINTERFACE_DISK, deviceIndex, &deviceInterface)) { DWORD cbRequired = 0; SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, 0, 0, &cbRequired, 0); if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { deviceInterfaceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[cbRequired]); memset(deviceInterfaceDetail, 0, cbRequired); deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); if (!SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, deviceInterfaceDetail, cbRequired, &cbRequired, 0)) { goto Next; } // Initialize the structure before using it. memset(deviceInterfaceDetail, 0, cbRequired); deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); // Call the API a second time to retrieve the actual // device path string. BOOL status = SetupDiGetDeviceInterfaceDetail( deviceInfoHandle, // Handle to device information set &deviceInterface, // Pointer to current node in devinfo set deviceInterfaceDetail, // Pointer to buffer to receive device path cbRequired, // Length of user-allocated buffer &cbRequired, // Pointer to arg to receive required buffer length NULL); // Not interested in additional data //получение информации о устройстве ZeroMemory(&devinfo,sizeof(devinfo)); devinfo.cbSize = sizeof(SP_DEVINFO_DATA); BOOL success = SetupDiEnumDeviceInfo(deviceInfoHandle, deviceIndex, &devinfo); if(success==FALSE){ErrorMes(L"SetupDiEnumDeviceInfo"); goto Next;} res=SetupDiGetDeviceProperty(deviceInfoHandle,&devinfo, &DEVPKEY_Device_Parent,&dpt,(PBYTE)buffer,1000,NULL,0); if(res==FALSE){ErrorMes(L"SetupDiGetDeviceProperty");goto Next;} int len = wcslen(buffer); for(int i=0;iDevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if(handle==INVALID_HANDLE_VALUE) { ErrorMes(L"CreateFile");goto Next; } STORAGE_DEVICE_NUMBER sdn = {0}; DWORD nbytes = 0; //получение номера диска res = DeviceIoControl(handle, // handle to device IOCTL_STORAGE_GET_DEVICE_NUMBER, // dwIoControlCode NULL, // lpInBuffer 0, // nInBufferSize (LPVOID) &sdn, // output buffer (DWORD) sizeof(sdn), // size of output buffer (LPDWORD) &nbytes, // number of bytes returned NULL // OVERLAPPED structure ); CloseHandle(handle); if(res != FALSE){ //устройство найдено memcpy(lpret,&sdn,sizeof(sdn)); retval = TRUE; } else ErrorMes(L"DeviceIoControl"); } } } else { break; } Next: if(deviceInterfaceDetail != NULL){ delete[] deviceInterfaceDetail; deviceInterfaceDetail = NULL; } if(retval != FALSE) break; //устройство уже найдено deviceIndex++; //следующее устройство } SetupDiDestroyDeviceInfoList(deviceInfoHandle); } else ErrorMes(L"SetupDiGetClassDevs"); return retval; } //таблица номеров для всех дисков bool disk_IsUsed[30]={0}; STORAGE_DEVICE_NUMBER disk_number[30]={0}; int _tmain(int argc, _TCHAR* argv[]) { setlocale(LC_ALL,"Russian"); HANDLE hVol; DWORD nbytes; WCHAR letter; WCHAR volume[100]={0}; int i; STORAGE_DEVICE_NUMBER sdn={0}; //заполняем таблицу номеров для дисков for(i=0;i<30;i++){ letter = 'A' + i; wsprintf(volume,L"\\\\.\\%c:",letter); disk_IsUsed[i] = FALSE; hVol = CreateFile( volume, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if(hVol == NULL || hVol == INVALID_HANDLE_VALUE){continue;} BOOL ret = DeviceIoControl(hVol, // handle to device IOCTL_STORAGE_GET_DEVICE_NUMBER, // dwIoControlCode NULL, // lpInBuffer 0, // nInBufferSize (LPVOID) &(disk_number[i]), // output buffer (DWORD) sizeof(STORAGE_DEVICE_NUMBER), // size of output buffer (LPDWORD) &nbytes, // number of bytes returned NULL // OVERLAPPED structure ); CloseHandle(hVol); if(ret == FALSE){continue;} disk_IsUsed[i] = TRUE; } WCHAR match[1024]={0}; GUID guid = { 0xF18A0E88, 0xC30C, 0x11D0, { 0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8 } }; /*USB HUB Interface class GUID*/ HDEVINFO deviceInfoHandle = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (deviceInfoHandle != INVALID_HANDLE_VALUE) { int deviceIndex = 0; while (true) { SP_DEVICE_INTERFACE_DATA deviceInterface = { 0 }; deviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); //получение всех USB-концентраторов if (SetupDiEnumDeviceInterfaces(deviceInfoHandle, 0, &guid, deviceIndex, &deviceInterface)) { DWORD cbRequired = 0; SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, 0, 0, &cbRequired, 0); if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[cbRequired]); memset(deviceInterfaceDetail, 0, cbRequired); deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); if (!SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, deviceInterfaceDetail, cbRequired, &cbRequired, 0)) { delete[] deviceInterfaceDetail; deviceIndex++; continue; } // Initialize the structure before using it. memset(deviceInterfaceDetail, 0, cbRequired); deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); // Call the API a second time to retrieve the actual // device path string. BOOL status = SetupDiGetDeviceInterfaceDetail( deviceInfoHandle, // Handle to device information set &deviceInterface, // Pointer to current node in devinfo set deviceInterfaceDetail, // Pointer to buffer to receive device path cbRequired, // Length of user-allocated buffer &cbRequired, // Pointer to arg to receive required buffer length NULL); // Not interested in additional data BOOL res; /*Открываем устройство для отправки IOCTL*/ HANDLE handle = CreateFile(deviceInterfaceDetail->DevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if(handle!=INVALID_HANDLE_VALUE) { DWORD bytes_read=0; UINT ports = 0; USB_NODE_INFORMATION nodeinfo; USB_NODE_CONNECTION_INFORMATION_EX coninfo={0}; const UINT BUFSIZE = 1000; char buffer[BUFSIZE]={0}; USB_DESCRIPTOR_REQUEST* req = (USB_DESCRIPTOR_REQUEST*)&buffer; USB_STRING_DESCRIPTOR* desc; ZeroMemory(&nodeinfo,sizeof(nodeinfo)); nodeinfo.NodeType = UsbHub; //получаем число портов на концентраторе res=DeviceIoControl(handle,IOCTL_USB_GET_NODE_INFORMATION , &nodeinfo,sizeof(nodeinfo),&nodeinfo,sizeof(nodeinfo),&bytes_read,0); if(res==FALSE)ErrorMes(L"DeviceIoControl"); else ports = (UINT)nodeinfo.u.HubInformation.HubDescriptor.bNumberOfPorts; for(int j=1;j<=ports;j++){ ZeroMemory(&coninfo,sizeof(coninfo)); coninfo.ConnectionIndex=j; //получаем инфу о порте res=DeviceIoControl(handle,IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX , &coninfo,sizeof(coninfo),&coninfo,sizeof(coninfo),&bytes_read,0); if(res==FALSE){ErrorMes(L"DeviceIoControl");continue;} if(coninfo.ConnectionStatus==0) continue; //нет устройства printf("\n- Hub %2d, Port %2d: USB v%x device\n",deviceIndex, j,(int)coninfo.DeviceDescriptor.bcdUSB); printf("VID: %04X PID: %04X\n",(int)coninfo.DeviceDescriptor.idVendor ,(int)coninfo.DeviceDescriptor.idProduct); //формируем строку для поиска устройства wsprintf(match,L"VID_%04X&PID_%04X",(UINT)coninfo.DeviceDescriptor.idVendor ,(UINT)coninfo.DeviceDescriptor.idProduct); /*Serial number*/ ZeroMemory(buffer,BUFSIZE); req->ConnectionIndex=j; req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) + coninfo.DeviceDescriptor.iSerialNumber; req->SetupPacket.wLength = BUFSIZE - sizeof(USB_DESCRIPTOR_REQUEST); req->SetupPacket.wIndex = 0x409; //US English res=DeviceIoControl(handle,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION , &buffer,sizeof(buffer),&buffer,sizeof(buffer),&bytes_read,0); if(res==FALSE){ErrorMes(L"DeviceIoControl");continue;} desc = (USB_STRING_DESCRIPTOR*)(&req->Data[0]); wprintf(L"Serial: %s\n",desc->bString); /*Vendor*/ ZeroMemory(buffer,BUFSIZE); req->ConnectionIndex=j; req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) + coninfo.DeviceDescriptor.iManufacturer; req->SetupPacket.wLength = BUFSIZE - sizeof(USB_DESCRIPTOR_REQUEST); req->SetupPacket.wIndex = 0x409; //US English res=DeviceIoControl(handle,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION , &buffer,sizeof(buffer),&buffer,sizeof(buffer),&bytes_read,0); if(res==FALSE){ErrorMes(L"DeviceIoControl");continue;} desc = (USB_STRING_DESCRIPTOR*)(&req->Data[0]); wprintf(L"Vendor: %s\n",desc->bString); /*Product*/ ZeroMemory(buffer,BUFSIZE); req->ConnectionIndex=j; req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) + coninfo.DeviceDescriptor.iProduct; req->SetupPacket.wLength = BUFSIZE - sizeof(USB_DESCRIPTOR_REQUEST); req->SetupPacket.wIndex = 0x409; //US English res=DeviceIoControl(handle,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION , &buffer,sizeof(buffer),&buffer,sizeof(buffer),&bytes_read,0); if(res==FALSE){ErrorMes(L"DeviceIoControl");continue;} desc = (USB_STRING_DESCRIPTOR*)(&req->Data[0]); wprintf(L"Product: %s\n",desc->bString); /*Disk letter*/ res = FindDiskNumber(match,&sdn); if(res != FALSE) { for(i=0;i<30;i++) if( disk_IsUsed[i] !=FALSE && disk_number[i].DeviceNumber == sdn.DeviceNumber && disk_number[i].DeviceType == sdn.DeviceType) { letter = 'A' + i; printf("Disk letter: %c\n",letter); } } else printf("Disk letter not found\n"); } CloseHandle(handle); }else{ ErrorMes(L"CreateFile");//failed to open device }//endif delete[] deviceInterfaceDetail; } } else { break; } ++deviceIndex; } SetupDiDestroyDeviceInfoList(deviceInfoHandle); } else ErrorMes(L"SetupDiGetClassDevs"); system("PAUSE"); return 0; } Должно вывести подобный результат: ‐ Hub 3, Port 1: USB v200 device VID: 8564 PID: 1000 Serial: 5B94314A Vendor: JetFlash Product: Mass Storage Device Disk letter: G ‐ Hub 3, Port 4: USB v110 device VID: 09DA PID: 000A Serial: ? Vendor: A4Tech Product: USB Mouse Disk letter not found ‐ Hub 3, Port 6: USB v110 device VID: 046E PID: 5505 Serial: ? Vendor: BTC Product: USB Multimedia Keyboard Disk letter not found ‐ Hub 3, Port 10: USB v200 device VID: 04E8 PID: 689E Serial: 1234567890ABCDEF Vendor: SAMSUNG Electronics Co., Ltd. Product: Samsung Android USB Device Disk letter: H

Комментариев нет:

Отправить комментарий