MSDN.WhiteKnight - Stack Overflow answers
Ответ на "Usb flash - определение интерфейса."
Answer 734879
Решение на C++ для Windows
Определить версию USB можно с помощью Setup API и запросов
DeviceIoControl
. Нас интересуют запросы:IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX - возвращает сведения о фактически используемой в данный момент версии USB
IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 - возвращает сведения о поддерживаемых версиях USB
Алгоритм следующий:
Функцией
SetupDiEnumDeviceInterfaces
найти все интерфейсы USB-концентраторов.Для каждого концентратора функцией
SetupDiGetDeviceInterfaceDetail
получить путь к устройству - строку, которую можно скармливать функцииCreateFile
вместо пути к файлу, для отправки IOCTL.Через
IOCTL_USB_GET_HUB_INFORMATION_EX
получить число портов на концентраторе.Для каждого порта отправкой
IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX
и/илиIOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2
получить сведения о порте.Пользуясь полями полученной структуры
USB_DEVICE_DESCRIPTOR
, можно определить VID и PID, и далее с помощью них другие необходимые параметры для идентификации устройства (Friendly Name, Service и т.п.)
Пример кода на c++ для вывода названия, идентификатора, версий USB-протокола и текущей скорости для всех запоминающих USB-устройств, основан на коде из ответа MrMoDoJoJr на stackoverflow.com:
#include <stdio.h> #include <tchar.h> #include <Windows.h> #include <Setupapi.h> #include <winusb.h> #undef LowSpeed #include <Usbioctl.h> #include <stdlib.h> #include <Devpkey.h> #include <iostream> #include <string> #include <memory> #include <strsafe.h> #pragma comment(lib,"Setupapi.lib") void ErrorMes(LPTSTR 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((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); wprintf(L"%s failed with error %d: %s", lpszFunction, dw, lpMsgBuf); LocalFree(lpMsgBuf); LocalFree(lpDisplayBuf); } typedef struct { wchar_t name[1024];//friendly name wchar_t id[1024];//instance id } USB_DEVICE_PARAMS; /*Получение имени устройства с указанным InstanceID*/ BOOL GetDevice(wchar_t* id,wchar_t* output) { unsigned index; HDEVINFO hDevInfo; SP_DEVINFO_DATA DeviceInfoData; TCHAR id_upper[1024]=L""; TCHAR buf[1024]=L""; TCHAR match[1024]; DEVPROPTYPE dpt=0; for(int i=0;i<wcslen(id);i++){ id_upper[i]=toupper(id[i]);//преобразование в заглавные буквы } // List all connected devices hDevInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES); for (index = 0; ; index++) { DeviceInfoData.cbSize = sizeof(DeviceInfoData); if (!SetupDiEnumDeviceInfo(hDevInfo, index, &DeviceInfoData)) { return FALSE; // no match } BOOL res=SetupDiGetDeviceProperty(hDevInfo,&DeviceInfoData, &DEVPKEY_Device_InstanceId,&dpt,(PBYTE)buf,1000,NULL,0); if(res==FALSE)continue; if(wcscmp(buf,id_upper)==0){ //устройство найдено res=SetupDiGetDeviceProperty(hDevInfo,&DeviceInfoData, &DEVPKEY_Device_FriendlyName,&dpt,(PBYTE)buf,1000,NULL,0); wcscpy(output,buf);//возврат имени return TRUE; } } return FALSE;//устройство не найдено } /*Получение USB Mass Storage Device по указанным VID и PID*/ BOOL GetMassStorageDevice(int vid,int pid,USB_DEVICE_PARAMS* output) { unsigned index; HDEVINFO hDevInfo; SP_DEVINFO_DATA DeviceInfoData; TCHAR HardwareID[1024]; TCHAR buf[1024]; TCHAR match[1024]; DEVPROPTYPE dpt=0; BOOL res; //формируем строку для поиска StringCchPrintf(match,1024,L"VID_%04X&PID_%04X",vid,pid); // List all connected USB devices hDevInfo = SetupDiGetClassDevs(NULL, TEXT("USB"), NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES); for (index = 0; ; index++) { DeviceInfoData.cbSize = sizeof(DeviceInfoData); if (!SetupDiEnumDeviceInfo(hDevInfo, index, &DeviceInfoData)) { return FALSE; // no match } res=SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData, SPDRP_HARDWAREID, NULL, (BYTE*)HardwareID, sizeof(HardwareID), NULL); if(res==FALSE)continue; if (_tcsstr(HardwareID, match)) {//найдено устройство, проверяем его тип res=SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData, SPDRP_SERVICE, NULL, (BYTE*)buf, sizeof(buf), NULL); if(res==FALSE)continue; if(wcscmp(buf,L"USBSTOR")==0){//устройство является Mass Storage res=SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData, SPDRP_DEVICEDESC, NULL, (BYTE*)buf, sizeof(buf), NULL); if(res==FALSE)continue; //получаем дочернее устройство res=SetupDiGetDeviceProperty(hDevInfo,&DeviceInfoData, &DEVPKEY_Device_Children,&dpt,(PBYTE)buf,1000,NULL,0); if(res==FALSE)continue;//нет дочерних устройств wcscpy(output->id,buf);//возврат ID GetDevice(buf,output->name);//возврат имени устройства return TRUE; // найдено } } } return FALSE;//не найдено } int main() { setlocale(LC_ALL,"Russian"); GUID guid; /*USB HUB Interface class GUID*/ HRESULT hr = CLSIDFromString(L"{F18A0E88-C30C-11D0-8815-00A0C906BED8}", (LPCLSID)&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)) { 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; USB_HUB_INFORMATION_EX hubinfo; hubinfo.HighestPortNumber=0; res=DeviceIoControl(handle,IOCTL_USB_GET_HUB_INFORMATION_EX , &hubinfo,sizeof(hubinfo),&hubinfo,sizeof(hubinfo),&bytes_read,0); if(res==FALSE)ErrorMes(L"DeviceIoControl"); USB_NODE_CONNECTION_INFORMATION_EX coninfo={0};//get conn info USB_NODE_CONNECTION_INFORMATION_EX_V2 con2={0}; for(int j=1;j<=(int)hubinfo.HighestPortNumber;j++){ 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; USB_DEVICE_PARAMS usbdev={0}; //если на порте запоминающее устройство, вывести его данные if(GetMassStorageDevice(coninfo.DeviceDescriptor.idVendor, coninfo.DeviceDescriptor.idProduct,&usbdev)!=FALSE) { 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); wprintf(L"Device ID: %s\n",usbdev.id); wprintf(L"Device name: %s\n",usbdev.name); printf("Speed: %d",(int)coninfo.Speed); switch((int)coninfo.Speed){ case UsbLowSpeed:printf(" (low)\n");break; case UsbFullSpeed:printf(" (full)\n");break; case UsbHighSpeed:printf(" (high)\n");break; case UsbSuperSpeed:printf(" (super)\n");break; default:printf("\n");break; } //получение поддерживаемых протоколов con2.ConnectionIndex=j; con2.Length=sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2 ); con2.SupportedUsbProtocols.Usb300=1; res=DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 , &con2,sizeof(con2),&con2,sizeof(con2),&bytes_read,0); if(res==FALSE){ErrorMes(L"DeviceIoControl");continue;} printf("Supported protocols: "); if(con2.SupportedUsbProtocols.Usb110)printf("USB 1.1; "); if(con2.SupportedUsbProtocols.Usb200)printf("USB 2.0; "); if(con2.SupportedUsbProtocols.Usb300)printf("USB 3.0; "); printf("\n"); } }//end for CloseHandle(handle); }else{ ErrorMes(L"CreateFile");//failed to open device }//endif delete[] deviceInterfaceDetail; } } else { break; } ++deviceIndex; } SetupDiDestroyDeviceInfoList(deviceInfoHandle); } system("PAUSE"); return 0; }
Так выглядит результат:
Примечание. Информация выше относится к Windows 8-10. В более ранних ОС запросы на получение версии не поддерживаются, но можно получить признак поддержки High Speed:
DWORD bytes_read=0; USB_HUB_CAPABILITIES_EX hubinfo={0}; res=DeviceIoControl(handle, IOCTL_USB_GET_HUB_CAPABILITIES , &hubinfo,sizeof(hubinfo),&hubinfo,sizeof(hubinfo),&bytes_read,0); if(res==FALSE)ErrorMes(L"DeviceIoControl"); printf("Supports High speed: %d\n",hubinfo.CapabilityFlags.HubIsHighSpeedCapable);
Content is retrieved from StackExchange API.
Auto-generated by ruso-archive tools.