Windows 8.1 Bluetooth LE can't get device interface - c++

I am trying to retrieve the name and handle of all paired bluetooth devices on a windows 8.1 machine.
I can get the name, but SetupDiEnumDeviceInterfaces always returns false. I read somewhere that I need to include DIGCF_DEVICEINTERFACE in the SetupDIGetClassDevs function, but it still doesn't work.
Here is my code:
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(
&GUID_DEVCLASS_BLUETOOTH,
0, 0, DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
// Insert error handling here.
return;//1;
}
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i,
&DeviceInfoData); i++)
{
DWORD DataT;
LPTSTR buffer = NULL;
DWORD buffersize = 0;
while (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
SPDRP_FRIENDLYNAME,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){
// Change the buffer size.
if (buffer) delete(buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = new wchar_t[buffersize * 2];
}
else{
// Insert error handling here.
break;
}
}
HWND deviceList = GetDlgItem(GetActiveWindow(), LIST_BOX);
if (deviceList && buffersize > 0)
{
SendMessage(deviceList, LB_ADDSTRING, 0, (LPARAM)buffer);
}
if (buffer) delete(buffer);
// WORKS UNTIL HERE BUT ENUMERATING THROUGH INTERFACES ALWAYS RETURNS FALSE
SP_DEVICE_INTERFACE_DATA devIntData;
HDEVINFO hDevInfo2 = SetupDiGetClassDevs(
&GUID_DEVCLASS_BLUETOOTH,
0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (SetupDiEnumDeviceInterfaces(hDevInfo2,
&DeviceInfoData,
&GUID_BLUETOOTHLE_DEVICE_INTERFACE,
i,
&devIntData))
{
DWORD reqSize;
SP_DEVINFO_DATA buffer;
while (SetupDiGetDeviceInterfaceDetail(hDevInfo2,
&devIntData,
NULL,
NULL,
&reqSize,
&buffer))
{
OutputDebugString(L"DeviceINTERFACE");
}
}
}
I have tried putting the device enumeration outside of the name enumeration loop, but it still returns false also I would like the handle and the name to be associated so I would like them to be found in the same context.
If anyone has any sample code on a full bluetooth LE workflow in windows 8.1 (find name, find handles, find services, find characteristics, write to characteristics) and could share that with me I would greatly appreciate it. Thanks.

Figured it out, wasn't allocating memory for my buffers properly.
EDIT: Adding code
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(
&GUID_DEVCLASS_BLUETOOTH,
0, 0, DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
// Insert error handling here.
return;//1;
}
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i,
&DeviceInfoData); i++)
{
DWORD DataT;
LPTSTR buffer = NULL;
DWORD buffersize = 0;
//This loop gets the name with SPDRP_FRIENDLYNAME
while (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
SPDRP_FRIENDLYNAME,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){
// Change the buffer size.
if (buffer) delete(buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = new wchar_t[buffersize * 2];
}
else{
// Insert error handling here.
break;
}
}
DWORD DataT2;
LPTSTR buffer2 = NULL;
DWORD buffersize2 = 0;
//This Loop gets the Bluetooth Address with SPDRP_HARDWAREID
// NOTE: there is more information than just the address you will have
// to do some string manipulation to have just the address
while (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
SPDRP_HARDWAREID,
&DataT2,
(PBYTE)buffer2,
buffersize2,
&buffersize2))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){
// Change the buffer size.
if (buffer2) delete(buffer2);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer2 = new wchar_t[buffersize2 * 2];
}
else{
// Insert error handling here.
break;
}
}
if (buffersize > 0)
{
//do what you need with the info
//name is in buffer
//address is in buffer2
}
}
Next i get the handles in a different function because you need to enumerate over Interfaces and not info with SetupDiEnumDeviceInterfaces instead of SetupDiEnumDeviceInfo in the for loop
Using the bluetooth address I match the two and store appropriately

Related

Getting Connection-State from Bluetooth Low Energy Device from Device Manager

i'm developing on a Bluetooth Low Energy Device and i need to see in code if the device is connected or not.
First thing i noticed was that there is in the Devicemanager a Attribute "Verbunden"-> English: Connected and it says true or false if my device is connected or not. So i need to read that Attribute in my program.
What i have tried till now:
Getting all Devices with SetupDiGetClassDevs
Getting the FriendlyName with SetupDiGetDeviceRegistryProperty
Searching for my Device with the name.
That works.
Now i wanted to get that Connected-Attribute but i didn't find out what i have to use at SetupDiGetDeviceRegistryProperty.
SetupDiGetDeviceRegistryProperty is described here https://msdn.microsoft.com/en-us/library/windows/hardware/ff551967(v=vs.85).aspx
Maybe someone knows what is the right value for Property.
My Code:
int get_device_info( void )
{
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
FILE * devices = fopen("devices.txt", "a+");
GUID AGuid;
//GUID can be constructed from "{xxx....}" string using CLSID
CLSIDFromString(TEXT(TO_SEARCH_DEVICE_UUID), &AGuid);
GUID BluetoothInterfaceGUID = AGuid;
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(&BluetoothInterfaceGUID,
0, // Enumerator
0,
DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
// Insert error handling here.
return 1;
}
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i=0;SetupDiEnumDeviceInfo(hDevInfo,i,
&DeviceInfoData);i++)
{
DWORD DataT;
LPTSTR buffer = NULL;
DWORD buffersize = 0;
//
// Call function with null to begin with,
// then use the returned buffer size (doubled)
// to Alloc the buffer. Keep calling until
// success or an unknown failure.
//
// Double the returned buffersize to correct
// for underlying legacy CM functions that
// return an incorrect buffersize value on
// DBCS/MBCS systems.
//
while (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
SPDRP_FRIENDLYNAME,
//SPDRP_DEVICEDESC,
//SPDRP_CAPABILITIES,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
if (GetLastError() ==
ERROR_INSUFFICIENT_BUFFER)
{
// Change the buffer size.
if (buffer) LocalFree(buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = (wchar_t *)LocalAlloc(LPTR,buffersize * 2);
}
else
{
// Insert error handling here.
break;
}
}
if(buffer)
{
if( strcmp("Name of Device",AnsiString(buffer).c_str())==0)
{
fprintf(devices,"Result:[%s]",AnsiString(buffer).c_str());
if (buffer) LocalFree(buffer);
}
}
}
if ( GetLastError()!=NO_ERROR &&
GetLastError()!=ERROR_NO_MORE_ITEMS )
{
// Insert error handling here.
return 1;
}
// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
fclose(devices);
return 0;
}
Instead of using SetupDiEnumDeviceInfo, you would try:
1. using SetupDiEnumDeviceInterfaces
2. using SetupDiGetDeviceInterfaceProperty
3. using SetupDiGetDeviceInterfacePropertyKeys to get a list of all Property Keys available for the interface
4. using SetupDiGetDeviceProperty and/or SetupDiGetDeviceRegistryProperty
Instead of using SPDRP_XXX constants, you would use DEVPROP, as defined in 'devpkey.h' ...
Below are a few examples taken from the log of a test prog I wrote to discover the whole thing:
DEVPROPNAME: DEVPKEY_DeviceInterface_Bluetooth_DeviceAddress
DEVPROPGUID: {2BD67D8B-8BEB-48D5-87E0-6CDA3428040A}
DEVPROPPID: 1
DEVPROPTYPE: DEVPROP_TYPE_STRING
Value: c026df001017
DEVPROPNAME: DEVPKEY_Device_Children
DEVPROPGUID: {4340A6C5-93FA-4706-972C-7B648008A5A7}
DEVPROPPID: 9
DEVPROPTYPE: DEVPROP_TYPE_STRING_LIST
Value:
BTHLEDevice\{00001800-0000-1000-8000-00805f9b34fb}_c026df001017\8&2fd07168&1&0001
BTHLEDevice\{00001801-0000-1000-8000-00805f9b34fb}_c026df001017\8&2fd07168&1&0008
BTHLEDevice\{00001809-0000-1000-8000-00805f9b34fb}_c026df001017\8&2fd07168&1&000c
BTHLEDevice\{0000180f-0000-1000-8000-00805f9b34fb}_c026df001017\8&2fd07168&1&0010
BTHLEDevice\{0000180a-0000-1000-8000-00805f9b34fb}_c026df001017\8&2fd07168&1&0014
BTHLEDevice\{00001523-1212-efde-1523-785feabcd123}_c026df001017\8&2fd07168&1&0019
On a second subject, you are 'working' on the 'device' itself ( SetupDiGetClassDevs(&BluetoothInterfaceGUID...) [and then working on the \BTHLE\ tree in Registry].
After listing all GattServices of this device and getting their uuids, you could restart that iteration on the device_guid itself SetupDiGetClassDevs(&GattServiceGUID...) [and then working on the \BTHLEDevice\ tree in Registry].
Now, to answer your question, I'm still searching myself :) But I'm not really sure:
1) that it is a working (dynamic) information to know the connection state
2) that it is a 'Property' you can access by the above methods
I have found out a solution.
GUID AGuid;
//GUID can be constructed from "{xxx....}" string using CLSID
CLSIDFromString(TEXT(TO_SEARCH_DEVICE_UUID), &AGuid);
GUID BluetoothInterfaceGUID = AGuid;
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(&BluetoothInterfaceGUID,
0, // Enumerator
0,
DIGCF_ALLCLASSES | DIGCF_PRESENT);//DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);//DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
// Insert error handling here.
return 1;
}
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i=0;SetupDiEnumDeviceInfo(hDevInfo,i,
&DeviceInfoData);i++)
{
DWORD DataT;
LPTSTR buffer = NULL;
LPTSTR buffer1 = NULL;
DWORD buffersize = 0;
while (!SetupDiGetDeviceRegistryProperty( // Get Name
hDevInfo,
&DeviceInfoData,
SPDRP_FRIENDLYNAME,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
if (GetLastError() ==
ERROR_INSUFFICIENT_BUFFER)
{
// Change the buffer size.
if (buffer) LocalFree(buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = (wchar_t *)LocalAlloc(LPTR,buffersize * 2);
}
else
{
// Insert error handling here.
break;
}
}
{
if(strcmp("Your Device",AnsiString(buffer).c_str())==0) //Found your device
{
//########
DEVPROPTYPE ulPropertyType;
DWORD dwSize;
ULONG devst;
// memset(devst,0,sizeof(devst));
bool err = SetupDiGetDeviceProperty( //Checking Connection State
hDevInfo,
&DeviceInfoData,
&DEVPKEY_Device_DevNodeStatus, //Connected(0x02000000)
&ulPropertyType,
(BYTE *) &devst,
sizeof(devst),
&dwSize,
0);
DWORD error;
error = GetLastError();
if (devst &0x02000000) {
//"Status: Getrennt "
}
else
{
//"Status: Verbunden"
}
Hope this snippet helps.

WINAPI C++ Get current physical drive number

I have a function
DWORD GetPhysicalDriveSerialNumber(UINT nDriveNumber, CString& strSerialNumber)
{
DWORD dwResult = NO_ERROR;
strSerialNumber.Empty();
// Format physical drive path (may be '\\.\PhysicalDrive0', '\\.\PhysicalDrive1' and so on).
CString strDrivePath;
strDrivePath.Format(_T("\\\\.\\PhysicalDrive%u"), nDriveNumber);
// call CreateFile to get a handle to physical drive
HANDLE hDevice = ::CreateFile(strDrivePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == hDevice)
return ::GetLastError();
// set the input STORAGE_PROPERTY_QUERY data structure
STORAGE_PROPERTY_QUERY storagePropertyQuery;
ZeroMemory(&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY));
storagePropertyQuery.PropertyId = StorageDeviceProperty;
storagePropertyQuery.QueryType = PropertyStandardQuery;
// get the necessary output buffer size
STORAGE_DESCRIPTOR_HEADER storageDescriptorHeader = { 0 };
DWORD dwBytesReturned = 0;
if (!::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
&storageDescriptorHeader, sizeof(STORAGE_DESCRIPTOR_HEADER),
&dwBytesReturned, NULL))
{
dwResult = ::GetLastError();
::CloseHandle(hDevice);
return dwResult;
}
// allocate the necessary memory for the output buffer
const DWORD dwOutBufferSize = storageDescriptorHeader.Size;
BYTE* pOutBuffer = new BYTE[dwOutBufferSize];
ZeroMemory(pOutBuffer, dwOutBufferSize);
// get the storage device descriptor
if (!::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
pOutBuffer, dwOutBufferSize,
&dwBytesReturned, NULL))
{
dwResult = ::GetLastError();
delete[]pOutBuffer;
::CloseHandle(hDevice);
return dwResult;
}
// Now, the output buffer points to a STORAGE_DEVICE_DESCRIPTOR structure
// followed by additional info like vendor ID, product ID, serial number, and so on.
STORAGE_DEVICE_DESCRIPTOR* pDeviceDescriptor = (STORAGE_DEVICE_DESCRIPTOR*)pOutBuffer;
const DWORD dwSerialNumberOffset = pDeviceDescriptor->SerialNumberOffset;
if (dwSerialNumberOffset != 0)
{
// finally, get the serial number
strSerialNumber = CString(pOutBuffer + dwSerialNumberOffset);
}
// perform cleanup and return
delete[]pOutBuffer;
::CloseHandle(hDevice);
return dwResult;
}
I want to get current drive number(drive number of program located in)
Example(for my system):
If i will run porgram on disk c it must return 0(hdd 0)
If i will run progrman on disk d or e it must return 1(hdd 1)
Flash drive 2 etc.
How can I do this?

Obtain Device Information Set for Monitors: Returned Handle is always INVALID_HANDLE_VALUE

I am attempting to list the device information for all the monitors currently connected to the computer. I have a function that can do this and its 90% done except when I go to call the function SetupDiGetClassDevs() with the 2nd parameter set(not NULL) then the function always fails(returns INVALID_HANDLE_VALUE).
When I call GetLastError() I get the error 13(decimal), ie, "The data is invalid" which I am not sure what that means?
What is going wrong? Can you provide any advice on whats happening and how I can fix it?
Function Information:
HDEVINFO SetupDiGetClassDevs(
_In_opt_ const GUID *ClassGuid,
_In_opt_ PCTSTR Enumerator, // According to MSDN this param MUST be set if I want Device Information for a specific class(Monitors)
_In_opt_ HWND hwndParent,
_In_ DWORD Flags
);
My function that attempts to get a Device Information Set for Monitors only and output each monitors details(the error line is commented):
void printDeviceData(GUID guID)
{
// Device Classes: http://msdn.microsoft.com/en-us/library/windows/hardware/ff553426
// System Device Classes: http://msdn.microsoft.com/en-us/library/windows/hardware/ff553428
// Monitor Class GUI: {4d36e96e-e325-11ce-bfc1-08002be10318}
DWORD dataT = 0;
PCTSTR monitorGuID = _T("");
SP_DEVINFO_DATA deviceInfoData = {0};
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
deviceInfoData.ClassGuid = guID;
// Step 1: Get Device Information Set for Monitors only
// ERROR OCCURS HERE: SetupDiGetClassDevs() always fails
// Also tried these values for param 2: "Monitor" "PCI" but all cause the function to return INVALID_HANDLE_VALUE
HDEVINFO hDevInfo = SetupDiGetClassDevs(&guID, _T("{4d36e96e-e325-11ce-bfc1-08002be10318}"), NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE) {
//outputLastError(_T("Fail 1"));
printf("hDevInfo == INVALID_HANDLE_VALUE\n");
return;
}
else printf("SUCCESS 1\n");
if (SetupDiGetSelectedDevice(hDevInfo, &deviceInfoData) == FALSE) {
//outputLastError(_T("SetupDiGetSelectedDevice(hDevInfo, &deviceInfoData) == FALSE"));
printf("SetupDiGetSelectedDevice(hDevInfo, &deviceInfoData) == FALSE, %d, %x\n", GetLastError(), GetLastError());
return;
}
else printf("SUCCESS 2\n");
// Step 2: For each Monitor: Output Device information
const unsigned int FLAG_NUM = 30;
DWORD flags[] = {SPDRP_FRIENDLYNAME, SPDRP_ENUMERATOR_NAME, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME, SPDRP_DEVICEDESC,
SPDRP_ADDRESS, SPDRP_BUSNUMBER, SPDRP_BUSTYPEGUID, SPDRP_CHARACTERISTICS, SPDRP_CLASS, SPDRP_CLASSGUID,
SPDRP_COMPATIBLEIDS, SPDRP_CONFIGFLAGS, SPDRP_DEVICE_POWER_DATA, SPDRP_DEVTYPE, SPDRP_DRIVER,
SPDRP_ENUMERATOR_NAME, SPDRP_EXCLUSIVE, SPDRP_HARDWAREID, SPDRP_INSTALL_STATE, SPDRP_LEGACYBUSTYPE,
SPDRP_LOCATION_INFORMATION, SPDRP_LOCATION_PATHS, SPDRP_LOWERFILTERS, SPDRP_MFG,
SPDRP_PHYSICAL_DEVICE_OBJECT_NAME, SPDRP_UI_NUMBER, SPDRP_UI_NUMBER_DESC_FORMAT, SPDRP_UPPERFILTERS,
SPDRP_SECURITY_SDS, SPDRP_SECURITY, SPDRP_SERVICE };
for (int i=0; i<=FLAG_NUM; i++) {
DWORD buffersize = 0;
LPTSTR buffer = NULL;
while (!SetupDiGetDeviceRegistryProperty(hDevInfo, &deviceInfoData, flags[i], &dataT,
(PBYTE)buffer, buffersize, &buffersize))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
// Change the buffer size.
if (buffer)
LocalFree(buffer);
buffer = (LPTSTR)LocalAlloc(LPTR, buffersize);
}
else {
// Insert error handling here.
break;
}
}
printf("Data: %d: %s\n", i, buffer);
if (buffer)
LocalFree(buffer);
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
According to the documentation, Enumerator must be set to a valid device Instance ID which according to http://msdn.microsoft.com/en-us/library/windows/hardware/ff541327 has to be specified like this
"PCI\VEN_1000&DEV_0001&SUBSYS_00000000&REV_02\1&08"
I haven't tested it, but I'd assume that's where the invalid data come from.

Find and eject a USB device based on its VID/PID

I want to send an eject command to a specific USB device identified by it's VID and PID. I can find the device by using SetupDiEnumDeviceInfo() and SetupDiGetDeviceRegistryProperty() and matching the VID/PID numbers in the HARDWAREID string but that's as far as I've got.
I have a SP_DEVINFO_DATA struct and a HDEVINFO handle. How would I relate these to a drive letter or volume path so I can send it an eject command?
Well, I figured it out. The CodeProject article linked to by Luke shows how to match the drive letter to a device interface which is half the way there so I'll +1 that answer but it doesn't solve the whole problem.
I needed to figure out how to find the device instance for my USB device and find a way to match that to the device interface. The CM_Locate_DevNode() and CM_Get_Child() functions were the key to this. Finally I can use an IOCTL to eject the device.
The device I am dealing with is a USB CD-ROM drive which is why I have hard-coded the device type to CDROM. I can't believe how much code is required to do what I thought would be a fairly straightforward task (I quoted my client 2 hours to write this code, it's taken me four days to figure it all out!). Here's the final working code which will hopefully save one of you out there from going through the same hell as I just have:
#include <SetupAPI.h>
#include <cfgmgr32.h>
#include <winioctl.h>
// Finds the device interface for the CDROM drive with the given interface number.
DEVINST GetDrivesDevInstByDeviceNumber(long DeviceNumber)
{
const GUID *guid = &GUID_DEVINTERFACE_CDROM;
// Get device interface info set handle
// for all devices attached to system
HDEVINFO hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(hDevInfo == INVALID_HANDLE_VALUE)
return 0;
// Retrieve a context structure for a device interface of a device information set.
BYTE buf[1024];
PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)buf;
SP_DEVICE_INTERFACE_DATA spdid;
SP_DEVINFO_DATA spdd;
DWORD dwSize;
spdid.cbSize = sizeof(spdid);
// Iterate through all the interfaces and try to match one based on
// the device number.
for(DWORD i = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL,guid, i, &spdid); i++)
{
// Get the device path.
dwSize = 0;
SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize, NULL);
if(dwSize == 0 || dwSize > sizeof(buf))
continue;
pspdidd->cbSize = sizeof(*pspdidd);
ZeroMemory((PVOID)&spdd, sizeof(spdd));
spdd.cbSize = sizeof(spdd);
if(!SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, pspdidd,
dwSize, &dwSize, &spdd))
continue;
// Open the device.
HANDLE hDrive = CreateFile(pspdidd->DevicePath,0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if(hDrive == INVALID_HANDLE_VALUE)
continue;
// Get the device number.
STORAGE_DEVICE_NUMBER sdn;
dwSize = 0;
if(DeviceIoControl(hDrive,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0, &sdn, sizeof(sdn),
&dwSize, NULL))
{
// Does it match?
if(DeviceNumber == (long)sdn.DeviceNumber)
{
CloseHandle(hDrive);
SetupDiDestroyDeviceInfoList(hDevInfo);
return spdd.DevInst;
}
}
CloseHandle(hDrive);
}
SetupDiDestroyDeviceInfoList(hDevInfo);
return 0;
}
// Returns true if the given device instance belongs to the USB device with the given VID and PID.
bool matchDevInstToUsbDevice(DEVINST device, DWORD vid, DWORD pid)
{
// This is the string we will be searching for in the device harware IDs.
TCHAR hwid[64];
_stprintf(hwid, _T("VID_%04X&PID_%04X"), vid, pid);
// Get a list of hardware IDs for all USB devices.
ULONG ulLen;
CM_Get_Device_ID_List_Size(&ulLen, NULL, CM_GETIDLIST_FILTER_NONE);
TCHAR *pszBuffer = new TCHAR[ulLen];
CM_Get_Device_ID_List(NULL, pszBuffer, ulLen, CM_GETIDLIST_FILTER_NONE);
// Iterate through the list looking for our ID.
for(LPTSTR pszDeviceID = pszBuffer; *pszDeviceID; pszDeviceID += _tcslen(pszDeviceID) + 1)
{
// Some versions of Windows have the string in upper case and other versions have it
// in lower case so just make it all upper.
for(int i = 0; pszDeviceID[i]; i++)
pszDeviceID[i] = toupper(pszDeviceID[i]);
if(_tcsstr(pszDeviceID, hwid))
{
// Found the device, now we want the grandchild device, which is the "generic volume"
DEVINST MSDInst = 0;
if(CR_SUCCESS == CM_Locate_DevNode(&MSDInst, pszDeviceID, CM_LOCATE_DEVNODE_NORMAL))
{
DEVINST DiskDriveInst = 0;
if(CR_SUCCESS == CM_Get_Child(&DiskDriveInst, MSDInst, 0))
{
// Now compare the grandchild node against the given device instance.
if(device == DiskDriveInst)
return true;
}
}
}
}
return false;
}
// Eject the given drive.
void ejectDrive(TCHAR driveletter)
{
TCHAR devicepath[16];
_tcscpy(devicepath, _T("\\\\.\\?:"));
devicepath[4] = driveletter;
DWORD dwRet = 0;
HANDLE hVol = CreateFile(devicepath, GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if(hVol == INVALID_HANDLE_VALUE)
return;
if(!DeviceIoControl(hVol, FSCTL_LOCK_VOLUME, 0, 0, 0, 0, &dwRet, 0))
return;
if(!DeviceIoControl(hVol, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0, &dwRet, 0))
return;
DeviceIoControl(hVol, IOCTL_STORAGE_EJECT_MEDIA, 0, 0, 0, 0, &dwRet, 0);
CloseHandle(hVol);
}
// Find a USB device by it's Vendor and Product IDs. When found, eject it.
void usbEjectDevice(unsigned vid, unsigned pid)
{
TCHAR devicepath[8];
_tcscpy(devicepath, _T("\\\\.\\?:"));
TCHAR drivepath[4];
_tcscpy(drivepath, _T("?:\\"));
// Iterate through every drive letter and check if it is our device.
for(TCHAR driveletter = _T('A'); driveletter <= _T('Z'); driveletter++)
{
// We are only interested in CDROM drives.
drivepath[0] = driveletter;
if(DRIVE_CDROM != GetDriveType(drivepath))
continue;
// Get the "storage device number" for the current drive.
long DeviceNumber = -1;
devicepath[4] = driveletter;
HANDLE hVolume = CreateFile(devicepath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if(INVALID_HANDLE_VALUE == hVolume)
continue;
STORAGE_DEVICE_NUMBER sdn;
DWORD dwBytesReturned = 0;
if(DeviceIoControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL))
DeviceNumber = sdn.DeviceNumber;
CloseHandle(hVolume);
if(DeviceNumber < 0)
continue;
// Use the data we have collected so far on our drive to find a device instance.
DEVINST DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber);
// If the device instance corresponds to the USB device we are looking for, eject it.
if(DevInst)
{
if(matchDevInstToUsbDevice(DevInst, vid, pid))
ejectDrive(driveletter);
}
}
}

how to get USB hardware id using device id?

How to get hardware id of the usb device using device id...i am using vc++6.0 and OS is xp.
is it possible by using wmi.
Finally i solved my problem...thanks for your replies...
I am posting the code here, it may be useful for someone... by this code we can get all hardwareids of the devices which are connceted to our system..
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(NULL,
0, // Enumerator
0,
DIGCF_PRESENT | DIGCF_ALLCLASSES );
if (hDevInfo == INVALID_HANDLE_VALUE)
{
//Error handling here.
printf("Error Details:[%s]\n","INVALID_HANDLE_VALUE");
return 1;
}
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i=0;SetupDiEnumDeviceInfo(hDevInfo,i,
&DeviceInfoData);i++)
{
DWORD DataT;
LPTSTR buffer = NULL;
LPTSTR hwbuffer=NULL;
DWORD buffersize = 0;
//
// Call function with null to begin with,
// then use the returned buffer size (doubled)
// to Alloc the buffer. Keep calling until
// success or an unknown failure.
//
// Double the returned buffersize to correct
// for underlying legacy CM functions that
// return an incorrect buffersize value on
// DBCS/MBCS systems.
//
while (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
SPDRP_HARDWAREID,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
if (GetLastError() ==
ERROR_INSUFFICIENT_BUFFER)
{
// Change the buffer size.
if (buffer) LocalFree(buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = (char*)LocalAlloc(LPTR,buffersize * 2);
}
else
{
//Error handling here.
//printf("Error Details:[%s]\n",GetLastError());
break;
}
}
printf("Test Result:[%s]\n",buffer);
if (buffer) LocalFree(buffer);
}
if ( GetLastError()!=NO_ERROR &&
GetLastError()!=ERROR_NO_MORE_ITEMS )
{
// Error handling here.
printf("Error Details:[%s]\n",GetLastError());
return 1;
}
// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
return 0;
You might be somewhat confused because you assume the hardware ID. IoGetDeviceProperty(yourDevice, DevicePropertyHardwareID, ...) returns a list.