I have asked a similar question previously, but 1. no one answered and 2. it is a bit different. I have managed to get the correct file Path and created a handler by using CreateFile. I have then tried to use the HidD_GetFeature() function, but when I print out the report, it is all in symbols - not letters, numbers or readable sign. Does anyone know why it is doing that?? Here's my code:
/*****************************Mainframe.cpp**************************************/
#include"DeviceManager.h"
int main()
{
int iQuit;
DeviceManager deviceManager;
//deviceManager.ListAllDevices();
deviceManager.GetDevice("8888", "0308");
std::cin >> iQuit;
return 0;
}
/***********************************DeviceManager.h***************************/
#include <windows.h>
//#include <hidsdi.h>
#include <setupapi.h>
#include <iostream>
#include <cfgmgr32.h>
#include <tchar.h>
#include <devpkey.h>
extern "C"{
#include <hidsdi.h>
}
//#pragma comment (lib, "setupapi.lib")
class DeviceManager
{
public:
DeviceManager();
~DeviceManager();
void ListAllDevices();
void GetDevice(std::string vid, std::string pid);
HANDLE PSMove;
byte reportBuffer[57];
GUID guid;
private:
HDEVINFO deviceInfoSet; //A list of all the devices
SP_DEVINFO_DATA deviceInfoData; //A device from deviceInfoSet
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailedData;
};
/********************************DeviceManager.cpp*********************************/
#include"DeviceManager.h"
DeviceManager::DeviceManager()
{
HidD_GetHidGuid(&guid);
deviceInfoSet = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); //Gets all Devices
}
DeviceManager::~DeviceManager()
{
}
void DeviceManager::ListAllDevices()
{
DWORD deviceIndex = 0;
deviceInfoData.cbSize = sizeof(deviceInfoData);
while(SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex, &deviceInfoData))
{
deviceInfoData.cbSize = sizeof(deviceInfoData);
ULONG tcharSize;
CM_Get_Device_ID_Size(&tcharSize, deviceInfoData.DevInst, 0);
TCHAR* deviceIDBuffer = new TCHAR[tcharSize]; //the device ID will be stored in this array, so the tcharSize needs to be big enough to hold all the info.
//Or we can use MAX_DEVICE_ID_LEN, which is 200
CM_Get_Device_ID(deviceInfoData.DevInst, deviceIDBuffer, MAX_PATH, 0); //gets the devices ID - a long string that looks like a file path.
/*
//SetupDiGetDevicePropertyKeys(deviceInfoSet, &deviceInfoData, &devicePropertyKey, NULL, 0, 0);
if( deviceIDBuffer[8]=='8' && deviceIDBuffer[9]=='8' && deviceIDBuffer[10]=='8' && deviceIDBuffer[11]=='8' && //VID
deviceIDBuffer[17]=='0' && deviceIDBuffer[18]=='3' && deviceIDBuffer[19]=='0' && deviceIDBuffer[20]=='8') //PID
{
std::cout << deviceIDBuffer << "\t<-- Playstation Move" << std::endl;
}
else
{
std::cout << deviceIDBuffer << std::endl;
}*/
std::cout << deviceIDBuffer << std::endl;
deviceIndex++;
}
}
void DeviceManager::GetDevice(std::string vid, std::string pid)
{
DWORD deviceIndex = 0;
deviceInfoData.cbSize = sizeof(deviceInfoData);
while(SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex, &deviceInfoData))
{
deviceInfoData.cbSize = sizeof(deviceInfoData);
ULONG IDSize;
CM_Get_Device_ID_Size(&IDSize, deviceInfoData.DevInst, 0);
TCHAR* deviceID = new TCHAR[IDSize];
CM_Get_Device_ID(deviceInfoData.DevInst, deviceID, MAX_PATH, 0);
if( deviceID[8]==vid.at(0) && deviceID[9]==vid.at(1) && deviceID[10]==vid.at(2) && deviceID[11]==vid.at(3) && //VID
deviceID[17]==pid.at(0) && deviceID[18]==pid.at(1) && deviceID[19]==pid.at(2) && deviceID[20]==pid.at(3)) //PID
{
DWORD deviceInterfaceIndex = 0;
deviceInterfaceData.cbSize = sizeof(deviceInterfaceData);
//HDEVINFO deviceInterfaceSet = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_DEVICEINTERFACE);
if(SetupDiEnumDeviceInterfaces(deviceInfoSet, &deviceInfoData, &guid, deviceInterfaceIndex, &deviceInterfaceData))
{
deviceInterfaceData.cbSize = sizeof(deviceInterfaceData);
deviceInterfaceDetailedData.cbSize = sizeof(deviceInterfaceDetailedData);
DWORD requiredSize;
SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, NULL, 0, &requiredSize, &deviceInfoData); //Gets the size
SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, &deviceInterfaceDetailedData, requiredSize, NULL, NULL); //Sets the deviceInterfaceDetailedData
//std::cout << deviceInterfaceDetailedData.DevicePath << std::endl;
PSMove = CreateFile(deviceInterfaceDetailedData.DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
reportBuffer[0] = 0;
ULONG reportBufferLength = sizeof(reportBuffer);
HidD_GetFeature(PSMove, &reportBuffer, reportBufferLength);
std::cout << reportBuffer << std::endl;
//deviceInterfaceIndex++;
}
break;
}
deviceIndex++;
}
}
the HidD_GetFeature() function is at the bottom of this huge block of code.
UPDATE: I've managed to print the report now, but it is just a random 8 bit hex. Everytime I close the program down and run it again, it prints out different results. Why's that?
The ListAllDevices() function isn't displaying the info correctly because you're outputting a wchar_t* to std::cout. You need to use std::wcout for wide chars.
Related
I'm using some legacy code to enumerate ports on my machine:
#include <windows.h>
#include <devguid.h>
#include <setupapi.h>
#include <string>
#include <iostream>
#include <assert.h>
bool GetTextProperty( std::string& sProperty,
HDEVINFO dev,
_SP_DEVINFO_DATA* pDeviceInfoData,
DWORD prop )
{
char szBuf[MAX_PATH];
DWORD iPropertySize = 0;
if (SetupDiGetDeviceRegistryProperty(dev, pDeviceInfoData,
prop, 0L, (PBYTE) szBuf, MAX_PATH, &iPropertySize))
{
sProperty = szBuf;
assert( iPropertySize >= sProperty.size() + 1 );
return true;
}
return false;
}
inline bool readRegistryKeyValue( HKEY hKey, const std::string& key, std::string& value )
{
bool res = false;
CHAR szBuffer[512];
DWORD dwBufferSize = sizeof(szBuffer);
ULONG nError = RegQueryValueEx(hKey, key.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize);
if (ERROR_SUCCESS == nError)
{
value = szBuffer;
res = true;
}
return res;
}
void ListPorts()
{
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, 0L, 0L, DIGCF_PRESENT);
if ( hDevInfo == INVALID_HANDLE_VALUE )
{
//Medoc_ReportError(MEDOC_ERROR_HARDWARE_DRIVER_API_FAILED,
// &hDevInfo, sizeof hDevInfo);
assert( false );
}
else
{
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData) != 0; i++)
{
char szBuf[MAX_PATH];
short wImageIdx = 0;
short wItem = 0;
DWORD iPropertySize;
if (SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData,
SPDRP_FRIENDLYNAME, 0L, (PBYTE) szBuf, MAX_PATH, &iPropertySize))
{
std::cout << "Smart name: " << szBuf << std::endl;
HKEY hKey = SetupDiOpenDevRegKey(
hDevInfo,
&DeviceInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DEV,
KEY_READ );
if ( hKey )
{
std::string portName;
readRegistryKeyValue( hKey, "PortName", portName );
std::cout << "Port name: " << szBuf << std::endl;
for ( DWORD prop = 0; prop != SPDRP_MAXIMUM_PROPERTY; ++prop )
{
std::string temp;
GetTextProperty( temp, hDevInfo, &DeviceInfoData, prop );
std::cout << prop << " : " << temp << std::endl;
}
RegCloseKey(hKey);
}
}
}
}
// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
}
int main( int argc, char* argv[] )
{
ListPorts();
return 0;
}
Among other information, this gives me access to port name (COM*), type (FTDI for instance), VID and PID...
However, when I have many different devices based on a FTDI chip plugged, they all have the same information (SPDRP_HARDWAREID prperty reports FTDIBUS\COMPORT&VID_0403&PID_6015 or FTDIBUS\COMPORT&VID_0403&PID_6010). So I cannot discriminate who is who.
When I use a USB sniffer ("Device Monitoring Studio"), this one is able to report more relevant information withoutestablishing any connection to the ports:
Can this kind of extended information be accessed through Windows API to discriminate by name many devices using the same FTDI chip? Or must I use FTDI driver API to achieve this?
With the help of Ben Voigt and Simon Mourier, I could achieve this, here is the piece of code:
// More includes:
#include <initguid.h>
#include <devpkey.h>
#include <cfgmgr32.h>
// A new dependency:
#pragma comment (lib, "Cfgmgr32.lib")
bool GetDeviceProperty( const std::string& what,
DEVINST dev,
DEVPROPKEY prop )
{
char szDeviceBuf[MAX_PATH];
DEVPROPTYPE type;
ULONG iDevicePropertySize = MAX_PATH;
if ( CM_Get_DevNode_PropertyW(dev,
&prop,
&type,
(PBYTE) szDeviceBuf,
&iDevicePropertySize,
0) == CR_SUCCESS )
{
wchar_t* txt = (wchar_t*) szDeviceBuf;
std::wstring ws(txt);
std::cout << what << " : " << std::string(ws.begin(), ws.end()) << std::endl;
return true;
}
else
{
return false;
}
}
void ListPorts()
{
...
DEVINST devInstParent;
auto status = CM_Get_Parent(&devInstParent, DeviceInfoData.DevInst, 0);
if (status == CR_SUCCESS)
{
ShowDeviceProperty( "Bus reported device description", devInstParent, DEVPKEY_Device_BusReportedDeviceDesc );
ShowDeviceProperty( "Device description", devInstParent, DEVPKEY_Device_DeviceDesc );
}
else
{
continue;
}
...
I am looking for example code in ansi c/c++ that will find usb devices by their pid/vid/sn# and then find the associated comport number. I have multiple FTDI usb serial ports connected to a pc and need to identify each port by the known SN#. This code I found will display the HWID info but how do I use it to get the comport number? Here is a response to the below code for one of the devices: USB\VID_0403&PID_6001\FTAME7HK
Are there an online tutorial that runs through examples for this type of code?
#include <windows.h>
#include <ansi_c.h>
#include <Setupapi.h>
#include <devguid.h>
#include <Setupapi.h>
HDEVINFO deviceInfoSet;
GUID *guidDev = (GUID*) &GUID_DEVCLASS_USB;
TCHAR buffer [4000];
DWORD buffersize =4000;
int memberIndex = 0;
main()
{
deviceInfoSet = SetupDiGetClassDevs(guidDev, NULL, NULL, DIGCF_PRESENT | DIGCF_PROFILE);
while (TRUE) {
SP_DEVINFO_DATA deviceInfoData;
ZeroMemory(&deviceInfoData, sizeof(SP_DEVINFO_DATA));
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (SetupDiEnumDeviceInfo(deviceInfoSet, memberIndex, &deviceInfoData) == FALSE) {
if (GetLastError() == ERROR_NO_MORE_ITEMS)
{
break;
}
}
DWORD nSize=0 ;
SetupDiGetDeviceInstanceId (deviceInfoSet, &deviceInfoData, buffer, sizeof(buffer), &nSize);
buffer [nSize] ='\0';
printf ("%s\n", buffer);
memberIndex++;
}
if (deviceInfoSet) {
SetupDiDestroyDeviceInfoList(deviceInfoSet);
}
getchar();
return 0;
}
If you want the friendly name, which typically includes the parenthesized com port number, this should do it:
{
wchar_t friendly_name[128];
if (!SetupDiGetDeviceRegistryPropertyW(device_list, &device_data, SPDRP_FRIENDLYNAME, nullptr, reinterpret_cast<PBYTE>(friendly_name), sizeof friendly_name, nullptr))
return;
StringCopyW(buffer, friendly_name);
}
To get the two parameters device_list and device_data for the above call, I use this function:
void rescan_ports( void )
{
SP_DEVINFO_DATA device_data = { sizeof device_data };
HDEVINFO device_list = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_COMPORT, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
DWORD error = GetLastError();
if (!device_list && device_list == INVALID_HANDLE_VALUE) return;
bool ended = false;
for( int i = 0; i < 6000 && !ended; i++ ) {
if (SetupDiEnumDeviceInfo(device_list, i, &device_data))
format_and_add_port_detail(device_list, device_data);
else
ended = (GetLastError() == ERROR_NO_MORE_ITEMS);
}
SetupDiDestroyDeviceInfoList(device_list);
}
It's very similar to what you wrote, except that mine uses GUID_DEVINTERFACE_COMPORT to find only serial ports.
I'm trying to work with Bluetooth LE devices using Windows GATT API in Windows 10. But I never detect any devices. Running this code always returns ERROR_NO_MORE_ITEMS. I've tried with a Windows laptop with built in Bluetooth 4.0 as well as a USB bluetooth dongle. I see the Bluetooth LE Enumerator in the Device Manager, and the driver shows as installed and working.
Note: I'm trying to build a .dll so I don't want to use UWP.
#include <vector>
#include <cstdio>
#include <iostream>
#include <windows.h>
#include <SetupAPI.h>
#include <Bluetoothleapis.h>
bool enumDevices() {
HDEVINFO handle = INVALID_HANDLE_VALUE;
GUID BluetoothClassGUID = GUID_BLUETOOTHLE_DEVICE_INTERFACE;
handle = SetupDiGetClassDevs(
&BluetoothClassGUID,
NULL,
NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (handle == INVALID_HANDLE_VALUE) {
std::wcout << " No Device class" << std::endl;
return FALSE;
}
GUID BluetoothInterfaceGUID = GUID_BLUETOOTHLE_DEVICE_INTERFACE;
std::vector<SP_DEVICE_INTERFACE_DATA> ble_interfaces;
std::vector<std::wstring> ble_paths;
// Enumerate device of LE_DEVICE interface class
for (int i = 0;; i++) {
std::string error;
SP_DEVICE_INTERFACE_DATA device_interface_data = { 0 };
device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
BOOL success = SetupDiEnumDeviceInterfaces(
handle,
NULL,
(LPGUID)&BluetoothInterfaceGUID,
(DWORD)i,
&device_interface_data);
if (!success) {
DWORD last_error = GetLastError();
if (last_error == ERROR_NO_MORE_ITEMS) {
std::wcout << " No more devices found" << std::endl;
break;
}
else {
std::wcout << " Error enumerating device interfaces: " << last_error;
return FALSE;
}
}
// Retrieve required # of bytes for interface details
ULONG required_length = 0;
success = SetupDiGetDeviceInterfaceDetail(
handle,
&device_interface_data,
NULL,
0,
&required_length,
NULL);
if (!success) {
DWORD last_error = GetLastError();
return FALSE;
}
UINT8* interface_data = new UINT8[required_length];
memset(interface_data, 0, required_length);
PSP_DEVICE_INTERFACE_DETAIL_DATA device_interface_detail_data = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(interface_data);
device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
SP_DEVINFO_DATA device_info_data = { 0 };
device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
ULONG actual_length = required_length;
success = SetupDiGetDeviceInterfaceDetail(
handle,
&device_interface_data,
device_interface_detail_data,
actual_length,
&required_length,
&device_info_data);
//Store data
std::wstring strpath = std::wstring(device_interface_detail_data->DevicePath);
OLECHAR* bstrGuid;
StringFromCLSID(device_interface_data.InterfaceClassGuid, &bstrGuid);
std::wcout << " Path: " << strpath << " GUID:" << bstrGuid << std::endl;
ble_paths.push_back(strpath);
ble_interfaces.push_back(device_interface_data);
}
}
int main() {
enumDevices();
}
As you know there is some difference between a process name and it's description, for example the dwm.exe process's description is Desktop Window Manager
I can check the name of the processes with this code:
#include <windows.h>
#include <TlHelp32.h>
#include <Winternl.h>
typedef NTSTATUS (NTAPI *NTQUERYINFORMATIONPROCESS)(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
int main()
{
PEB Peb = {0};
DWORD dwSize = 0;
DWORD dwPID = 0;
HANDLE hProcess = NULL;
HANDLE hProcessSnap = NULL;
WCHAR PsPath[MAX_PATH] = {0};
WCHAR wszProcName[20] = L"dwm.exe"; //Desktop Window Manager
PROCESSENTRY32 PsEntry32 = {0};
PROCESS_BASIC_INFORMATION PsBasicInfo = {0};
RTL_USER_PROCESS_PARAMETERS RtlUserPsParams = {0};
NTQUERYINFORMATIONPROCESS NtFunction = NULL;
if((hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) != INVALID_HANDLE_VALUE)
{
PsEntry32.dwSize = sizeof(PROCESSENTRY32);
if(!Process32First(hProcessSnap, &PsEntry32))
{
CloseHandle(hProcessSnap);
return FALSE;
}
do
{
if(lstrcmpiW(PsEntry32.szExeFile, wszProcName) == 0)
{
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, PsEntry32.th32ProcessID);
if(hProcess != INVALID_HANDLE_VALUE)
{
NtFunction = (NTQUERYINFORMATIONPROCESS)GetProcAddress(LoadLibraryW(L"ntdll.dll"), "NtQueryInformationProcess");
if(NtFunction)
{
if(NtFunction(hProcess, ProcessBasicInformation, &PsBasicInfo, sizeof(PROCESS_BASIC_INFORMATION), &dwSize) == ERROR_SUCCESS)
{
ReadProcessMemory(hProcess, PsBasicInfo.PebBaseAddress, &Peb, sizeof(PEB), (SIZE_T*)&dwSize);
ReadProcessMemory(hProcess, Peb.ProcessParameters, &RtlUserPsParams, sizeof(RTL_USER_PROCESS_PARAMETERS), (SIZE_T*)&dwSize);
ReadProcessMemory(hProcess, RtlUserPsParams.ImagePathName.Buffer, PsPath, RtlUserPsParams.ImagePathName.Length, (SIZE_T*)&dwSize);
dwPID = PsEntry32.th32ProcessID;
}
}
CloseHandle(hProcess);
}
}
}while(Process32Next(hProcessSnap, &PsEntry32));
CloseHandle(hProcessSnap);
}
return 0;
}
now I want to check the processes description
Is it possible to get all processes description one by one and check them?
I use ToolHelp32Snapshot() to get the module path instead of your PEB method, following that I:
GetFileVersionInfoSizeA() to get the size of the version structure
GetFileVersionInfoA() to pull the data from that structure into a local char array.
VerQueryValue() with "\VarFileInfo\Translation" to get the language code pages
Then I loop through the different language code pages to create the subblock string required for the next query.
Then I use VerQueryValue() with the correct language code page inserted inside the sub block and store the result into another char array.
Then we print this string to console.
#include <iostream>
#include <string>
#include <Windows.h>
#include <TlHelp32.h>
#include <strsafe.h>
#pragma comment(lib,"Version.lib")
std::string GetModulePath(std::string moduleName, DWORD procId)
{
std::string path;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
if (hSnap != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 modEntry{};
modEntry.dwSize = sizeof(modEntry);
if (Module32First(hSnap, &modEntry))
{
do
{
if (!_stricmp(modEntry.szModule, moduleName.c_str()))
{
path = modEntry.szExePath;
break;
}
} while (Module32Next(hSnap, &modEntry));
}
}
CloseHandle(hSnap);
return path;
}
std::string GetFilePath(std::string procName)
{
std::string path;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 procEntry;
procEntry.dwSize = sizeof(procEntry);
if (Process32First(hSnap, &procEntry))
{
do
{
if (!_stricmp(procEntry.szExeFile, procName.c_str()))
{
path = GetModulePath(procName, procEntry.th32ProcessID);
break;
}
} while (Process32Next(hSnap, &procEntry));
}
}
CloseHandle(hSnap);
return path;
}
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
};
int main()
{
std::string path = GetFilePath("notepad++.exe");
DWORD verSize = GetFileVersionInfoSizeA(path.c_str(), 0);
char* data = new char[verSize]{ 0 };
GetFileVersionInfoA(path.c_str(), 0, verSize, data);
UINT length;
LANGANDCODEPAGE* lpTranslate;
VerQueryValue(data, "\\VarFileInfo\\Translation", (LPVOID*)&lpTranslate, &length);
char SubBlock[50]{ 0 };
for (unsigned int i = 0; i < (length / sizeof(struct LANGANDCODEPAGE)); i++)
{
HRESULT result = StringCchPrintf(SubBlock, 50,
TEXT("\\StringFileInfo\\%04x%04x\\FileDescription"),
lpTranslate[i].wLanguage,
lpTranslate[i].wCodePage);
char* description = new char[0x100]{ 0 };
UINT length2;
VerQueryValue(data, SubBlock, (LPVOID*)&description, &length2);
std::cout << description << "\n";
}
getchar();
return 0;
}
Must run as administrator, and only tested on x86.
I use setup API functions to find a USB device then use createfile to communicate with it. i.e. using SetupDiGetClassDevs, SetupDiEnumDeviceInterfaces, SetupDiGetDeviceInterfaceDetail, etc.
I would like to be able to determine if the device is connected at USB2 speeds or USB3 speeds ie. SuperSpeed or not
How can I do this through the Windows APIs?
This is what I ended up going with. It's convoluted. Cant believe there isn't an easier way:
#include "stdafx.h"
#include <Windows.h>
#include <Setupapi.h>
#include <winusb.h>
#undef LowSpeed
#include <Usbioctl.h>
#include <iostream>
#include <string>
#include <memory>
#include <vector>
class Usb_Device
{
private:
std::wstring _driverKey;
char _speed;
public:
Usb_Device(int adapterNumber, std::wstring devicePath, char speed);
virtual char GetSpeed(std::wstring driverKey);
};
class Usb_Hub : public Usb_Device
{
private:
bool _isRootHub;
std::wstring _deviceDescription;
std::wstring _devicePath;
std::vector<std::unique_ptr<Usb_Device>> _devices;
public:
Usb_Hub(std::wstring devicePath, char speed);
virtual char GetSpeed(std::wstring driverKey) override;
};
class Usb_Controller
{
private:
GUID _interfaceClassGuid;
std::wstring _devicePath;
std::wstring _deviceDescription;
std::wstring _driverKey;
std::vector<std::unique_ptr<Usb_Device>> _devices;
public:
Usb_Controller();
char GetSpeed(std::wstring driverKey);
};
static std::unique_ptr<Usb_Device> BuildDevice(int portCount, std::wstring devicePath)
{
std::unique_ptr<Usb_Device> ret;
HANDLE handle = INVALID_HANDLE_VALUE;
DWORD bytes = -1;
DWORD bytesReturned = -1;
BOOL isConnected = FALSE;
char speed;
// Open a handle to the Hub device
handle = CreateFile(devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (handle != INVALID_HANDLE_VALUE)
{
bytes = sizeof(USB_NODE_CONNECTION_INFORMATION_EX);
PUSB_NODE_CONNECTION_INFORMATION_EX nodeConnection = (PUSB_NODE_CONNECTION_INFORMATION_EX)(new char[bytes]);
nodeConnection->ConnectionIndex = portCount;
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, nodeConnection, bytes, nodeConnection, bytes, &bytesReturned, 0))
{
isConnected = nodeConnection->ConnectionStatus == USB_CONNECTION_STATUS::DeviceConnected;
speed = nodeConnection->Speed;
}
if (isConnected)
{
if (nodeConnection->DeviceDescriptor.bDeviceClass == 0x09 /*HubDevice*/)
{
bytes = sizeof(USB_NODE_CONNECTION_NAME);
PUSB_NODE_CONNECTION_NAME nodeConnectionName = (PUSB_NODE_CONNECTION_NAME)(new char[bytes]);
nodeConnectionName->ConnectionIndex = portCount;
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_NAME, nodeConnectionName, bytes, nodeConnectionName, bytes, &bytesReturned, 0))
{
bytes = nodeConnectionName->ActualLength;
delete[] nodeConnectionName;
nodeConnectionName = (PUSB_NODE_CONNECTION_NAME)(new char[bytes]);
nodeConnectionName->ConnectionIndex = portCount;
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_NAME, nodeConnectionName, bytes, nodeConnectionName, bytes, &bytesReturned, 0))
{
std::wstring name = std::wstring(L"\\\\?\\") + std::wstring(nodeConnectionName->NodeName);
ret = std::unique_ptr<Usb_Device>(new Usb_Hub(name, speed));
}
}
delete[] nodeConnectionName;
}
else
{
ret = std::unique_ptr<Usb_Device>(new Usb_Device(portCount, devicePath, speed));
}
}
else
{
// Chuck this device
}
delete[] nodeConnection;
CloseHandle(handle);
}
return ret;
}
Usb_Controller::Usb_Controller()
{
BOOL success = TRUE;
for (int index = 0; success; index++)
{
GUID guid;
HRESULT hr = CLSIDFromString(L"{3abf6f2d-71c4-462a-8a92-1e6861e6af27}", (LPCLSID)&guid);
unsigned char* ptr = new unsigned char[2048]; // Should really do two calls, but that's more effort
HDEVINFO deviceInfoHandle = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
// Create a device interface data structure
SP_DEVICE_INTERFACE_DATA deviceInterfaceData = { 0 };
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
// Start the enumeration.
success = SetupDiEnumDeviceInterfaces(deviceInfoHandle, 0, &guid, index, &deviceInterfaceData);
if (success)
{
_interfaceClassGuid = deviceInterfaceData.InterfaceClassGuid;
// Build a DevInfo data structure.
SP_DEVINFO_DATA deviceInfoData = { 0 };
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
// Now we can get some more detailed informations.
DWORD nRequiredSize = 0;
SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterfaceData, 0, 0, &nRequiredSize, 0);
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[nRequiredSize]);
memset(deviceInterfaceDetailData, 0, nRequiredSize);
deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterfaceData, deviceInterfaceDetailData, nRequiredSize, &nRequiredSize, &deviceInfoData))
{
_devicePath = deviceInterfaceDetailData->DevicePath;
// Get the device description and driver key name.
DWORD requiredSize = 0;
DWORD regType = REG_SZ;
if (SetupDiGetDeviceRegistryProperty(deviceInfoHandle, &deviceInfoData, SPDRP_DEVICEDESC, ®Type, ptr, 2048, &requiredSize))
{
_deviceDescription = reinterpret_cast<wchar_t*>(ptr);
}
if (SetupDiGetDeviceRegistryProperty(deviceInfoHandle, &deviceInfoData, SPDRP_DRIVER, ®Type, ptr, 2048, &requiredSize))
{
_driverKey = reinterpret_cast<wchar_t*>(ptr);
}
}
delete[] deviceInterfaceDetailData;
}
SetupDiDestroyDeviceInfoList(deviceInfoHandle);
std::unique_ptr<Usb_Device> hub(new Usb_Hub(_devicePath, -1));
_devices.push_back(std::move(hub));
}
else
{
success = false;
}
delete[] ptr;
}
}
char Usb_Controller::GetSpeed(std::wstring driverKey)
{
char speed = -1;
for (auto it = _devices.begin(); it != _devices.end() && speed == -1; ++it)
{
if (*it != nullptr)
{
speed = (*it)->GetSpeed(driverKey);
}
}
return speed;
}
Usb_Hub::Usb_Hub(std::wstring devicePath, char speed) :
Usb_Device(-1, devicePath, speed)
{
HANDLE handle1 = INVALID_HANDLE_VALUE;
HANDLE handle2 = INVALID_HANDLE_VALUE;
_deviceDescription = L"Standard-USB-Hub";
_devicePath = devicePath;
DWORD bytesReturned = -1;
DWORD bytes = -1;
BOOL success = TRUE;
// Open a handle to the host controller.
handle1 = CreateFile(devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (handle1 != INVALID_HANDLE_VALUE)
{
USB_ROOT_HUB_NAME rootHubName;
memset(&rootHubName, 0, sizeof(USB_ROOT_HUB_NAME));
// Get the root hub name.
if (DeviceIoControl(handle1, IOCTL_USB_GET_ROOT_HUB_NAME, nullptr, 0, &rootHubName, sizeof(USB_ROOT_HUB_NAME), &bytesReturned, 0))
{
if (rootHubName.ActualLength > 0)
{
PUSB_ROOT_HUB_NAME actualRootHubName = (PUSB_ROOT_HUB_NAME)(new char[rootHubName.ActualLength]);
if (DeviceIoControl(handle1, IOCTL_USB_GET_ROOT_HUB_NAME, nullptr, 0, actualRootHubName, rootHubName.ActualLength, &bytesReturned, 0))
{
_isRootHub = true;
_deviceDescription = L"RootHub";
_devicePath = std::wstring(L"\\\\?\\") + std::wstring(actualRootHubName->RootHubName);
}
delete[] actualRootHubName;
}
}
// Now let's open the hub (based upon the hub name we got above).
int PortCount = 0;
handle2 = CreateFile(_devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (handle2 != INVALID_HANDLE_VALUE)
{
bytes = sizeof(USB_NODE_INFORMATION);
PUSB_NODE_INFORMATION nodeInfo = (PUSB_NODE_INFORMATION)(new char[bytes]);
memset(nodeInfo, 0, sizeof(USB_NODE_INFORMATION));
nodeInfo->NodeType = USB_HUB_NODE::UsbHub;
// Get the hub information.
if (DeviceIoControl(handle2, IOCTL_USB_GET_NODE_INFORMATION, nodeInfo, bytes, nodeInfo, bytes, &bytesReturned, 0))
{
DWORD d = GetLastError();
PortCount = nodeInfo->u.HubInformation.HubDescriptor.bNumberOfPorts;
}
delete[] nodeInfo;
CloseHandle(handle2);
}
CloseHandle(handle1);
for (int index = 1; index <= PortCount; index++)
{
std::unique_ptr<Usb_Device> device = BuildDevice(index, _devicePath);
_devices.push_back(std::move(device));
}
}
else
{
success = FALSE;
}
}
char Usb_Hub::GetSpeed(std::wstring driverKey)
{
char speed = Usb_Device::GetSpeed(driverKey);
if (speed == -1)
{
for (auto it = _devices.begin(); it != _devices.end() && speed == -1; ++it)
{
if (*it != nullptr)
{
speed = (*it)->GetSpeed(driverKey);
}
}
}
return speed;
}
Usb_Device::Usb_Device(int adapterNumber, std::wstring devicePath, char speed)
{
_speed = speed;
HANDLE handle = CreateFile(devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (handle != INVALID_HANDLE_VALUE)
{
// Get the Driver Key Name (usefull in locating a device)
DWORD bytesReturned = -1;
DWORD bytes = sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
PUSB_NODE_CONNECTION_DRIVERKEY_NAME driverKey = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)(new char[bytes]);
driverKey->ConnectionIndex = adapterNumber;
// Use an IOCTL call to request the Driver Key Name
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, driverKey, bytes, driverKey, bytes, &bytesReturned, 0))
{
bytes = driverKey->ActualLength;
delete[] driverKey;
driverKey = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)(new char[bytes]);
driverKey->ConnectionIndex = adapterNumber;
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, driverKey, bytes, driverKey, bytes, &bytesReturned, 0))
{
_driverKey = driverKey->DriverKeyName;
}
}
delete[] driverKey;
CloseHandle(handle);
}
}
char Usb_Device::GetSpeed(std::wstring driverKey)
{
return _speed;
}
int main()
{
Usb_Controller controller;
GUID guid;
HRESULT hr = CLSIDFromString(L"{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}", (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);
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 success = TRUE;
for (int i = 0; success; i++)
{
SP_DEVINFO_DATA deviceInterfaceData = { 0 };
deviceInterfaceData.cbSize = sizeof(SP_DEVINFO_DATA);
// Start the enumeration.
success = SetupDiEnumDeviceInfo(deviceInfoHandle, i, &deviceInterfaceData);
DWORD RequiredSize = 0;
DWORD regType = REG_SZ;
unsigned char* ptr = new unsigned char[2048];
if (SetupDiGetDeviceRegistryProperty(deviceInfoHandle, &deviceInterfaceData, SPDRP_DRIVER, ®Type, ptr, 2048, &RequiredSize))
{
char speed = controller.GetSpeed(reinterpret_cast<wchar_t*>(ptr));
std::wcout << std::wstring(reinterpret_cast<wchar_t*>(ptr)) << std::endl;
std::wcout << L"Speed: " << (int)speed << std::endl;
}
delete[] ptr;
}
auto hDeviceHandle = CreateFile(
deviceInterfaceDetail->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
CloseHandle(hDeviceHandle);
delete[] deviceInterfaceDetail;
}
}
else
{
break;
}
++deviceIndex;
}
SetupDiDestroyDeviceInfoList(deviceInfoHandle);
}
return 0;
}
I guess you will have to try WinUSB in the link there's a sample code of detecting the speed of USB. If you want the description of WinUSB you will find it here.