I would like to know whether i can get the drive information using the
SP_DEVICE_INTERFACE_DETAIL_DATA's DevicePath
my device path looks like below
"\?\usb#vid_04f2&pid_0111#5&39fe81e&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}"
also please tell me in the winapi they say "To determine whether a drive is a USB-type drive, call SetupDiGetDeviceRegistryProperty and specify the SPDRP_REMOVAL_POLICY property."
i too use SetupDiGetDeviceRegistryProperty like below
while ( !SetupDiGetDeviceRegistryProperty( hDevInfo,&DeviceInfoData,
SPDRP_REMOVAL_POLICY,&DataT,( PBYTE )buffer,buffersize,&buffersize ))
but i dont know how can i get the drive type using the above..
Please help me up
I've created a GetMountedVolumes method with optional mask to specify what type of volumes should be included in the search (readable, writeable, removeable, hotplugable, eraseable).
I abstained from Setup API methods at all and only used null access volume handle for DeviceIoControl calls (no administrative privileges are required). I will share my code, may be this will help others to implement methods to determine drive (volume) type without using Setup API.
enum VolumesFlags {
VolumeReadable = 1,
VolumeWriteable = 2,
VolumeEraseable = 4,
VolumeRemoveable = 8,
VolumeHotplugable = 16,
VolumeMounted = 128
};
bool GetMountedVolumes(std::vector<std::wstring> &Volumes,
unsigned int Flags = VolumeReadable | VolumeWriteable,
unsigned int Mask = VolumeReadable | VolumeWriteable) {
wchar_t Volume[MAX_PATH] = {0};
wchar_t* VolumeEndPtr = Volume;
Flags |= VolumeMounted;
Mask |= VolumeMounted;
Flags &= Mask;
HANDLE hFind = FindFirstVolume(Volume, sizeof(Volume) / sizeof(wchar_t));
if (hFind != INVALID_HANDLE_VALUE) {
do {
bool IsMatching = false;
VolumeEndPtr = &Volume[wcslen(Volume) - 1];
*VolumeEndPtr = L'\0';
HANDLE hDevice = CreateFile(Volume, 0, 0, 0, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);
if (hDevice != INVALID_HANDLE_VALUE) {
unsigned int CurrentFlags = 0;
DWORD ReturnedSize;
STORAGE_HOTPLUG_INFO Info = {0};
if (DeviceIoControl(hDevice, IOCTL_STORAGE_GET_HOTPLUG_INFO, 0, 0, &Info, sizeof(Info), &ReturnedSize, NULL)) {
if (Info.MediaRemovable) {
CurrentFlags |= VolumeRemoveable;
}
if (Info.DeviceHotplug) {
CurrentFlags |= VolumeHotplugable;
}
}
DWORD MediaTypeSize = sizeof(GET_MEDIA_TYPES);
GET_MEDIA_TYPES* MediaType = (GET_MEDIA_TYPES*) new char[MediaTypeSize];
while (DeviceIoControl(hDevice, IOCTL_STORAGE_GET_MEDIA_TYPES_EX, 0, 0, MediaType, MediaTypeSize, &ReturnedSize, NULL) == FALSE && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
delete [] (char*) MediaType;
MediaTypeSize *= 2;
MediaType = (GET_MEDIA_TYPES*) new char[MediaTypeSize];
}
if (MediaType->MediaInfoCount > 0) {
DWORD Characteristics = 0;
// Supports: Disk, CD, DVD
if (MediaType->DeviceType == FILE_DEVICE_DISK || MediaType->DeviceType == FILE_DEVICE_CD_ROM || MediaType->DeviceType == FILE_DEVICE_DVD) {
if (Info.MediaRemovable) {
Characteristics = MediaType->MediaInfo[0].DeviceSpecific.RemovableDiskInfo.MediaCharacteristics;
} else {
Characteristics = MediaType->MediaInfo[0].DeviceSpecific.DiskInfo.MediaCharacteristics;
}
if (Characteristics & MEDIA_CURRENTLY_MOUNTED) {
CurrentFlags |= VolumeMounted;
}
if (Characteristics & (MEDIA_READ_ONLY | MEDIA_READ_WRITE)) {
CurrentFlags |= VolumeReadable;
}
if (((Characteristics & MEDIA_READ_WRITE) != 0 || (Characteristics & MEDIA_WRITE_ONCE) != 0) && (Characteristics & MEDIA_WRITE_PROTECTED) == 0 && (Characteristics & MEDIA_READ_ONLY) == 0) {
CurrentFlags |= VolumeWriteable;
}
if (Characteristics & MEDIA_ERASEABLE) {
CurrentFlags |= VolumeEraseable;
}
}
}
delete [] (char*) MediaType;
CloseHandle(hDevice);
CurrentFlags &= Mask;
if (CurrentFlags == Flags) {
*VolumeEndPtr = L'\\';
wchar_t VolumePaths[MAX_PATH] = {0};
if (GetVolumePathNamesForVolumeName(Volume, VolumePaths, MAX_PATH, &ReturnedSize)) {
if (*VolumePaths) {
Volumes.push_back(VolumePaths);
}
}
}
}
} while (FindNextVolume(hFind, Volume, sizeof(Volume) / sizeof(wchar_t)));
FindVolumeClose(hFind);
}
return Volumes.size() > 0;
}
Probably what you are looking for you will be find here http://support.microsoft.com/kb/264203/en. Another link http://support.microsoft.com/kb/305184/en can be also interesting for you.
UPDATED: Example from http://support.microsoft.com/kb/264203/en shows you how to use to determine whether USB-Drive is removable. You can also use SetupDiGetDeviceRegistryProperty with SPDRP_REMOVAL_POLICY on the device instance (use SetupDiEnumDeviceInfo, SetupDiGetDeviceInstanceId and then SetupDiGetDeviceRegistryProperty). If returned DWORD has CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL or CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL as value, the drive is removable.
Moreover the code example show how to open device handle which you can use with DeviceIoControl function to retrieve a lot of useful information which you can need. IOCTL_STORAGE_QUERY_PROPERTY (see http://msdn.microsoft.com/en-us/library/ff566997%28v=VS.85%29.aspx) with different QueryType and PropertyId only one example. You can use IOCTL_STORAGE_GET_DEVICE_NUMBER for example to receive storage volumes and their disk number.
If you will have full STORAGE_DEVICE_NUMBER information about your USB device we will be able to find all other information about it with different ways. One of the easiest is: just enumerate all drive letters with QueryDosDevice and query STORAGE_DEVICE_NUMBER for every drive. If you will find full match in STORAGE_DEVICE_NUMBER you will find the drive letter.
Given your Storage Device Path:
Open the device using CreateFile
use DeviceIOControl to issue IOCTL_STORAGE_QUERY_PROPERTY
this populates STORAGE_DEVICE_DESCRIPTOR structure
which has a STORAGE_BUS_TYPE enumeration:
STORAGE_DEVICE_DESCRIPTOR {
DWORD Version;
DWORD Size;
BYTE DeviceType;
BYTE DeviceTypeModifier;
BOOLEAN RemovableMedia;
BOOLEAN CommandQueueing;
DWORD VendorIdOffset;
DWORD ProductIdOffset;
DWORD ProductRevisionOffset;
DWORD SerialNumberOffset;
STORAGE_BUS_TYPE BusType; //<---------------
DWORD RawPropertiesLength;
BYTE RawDeviceProperties[1];
}
The different storage bus types are
BusTypeScsi: SCSI
BusTypeAtapi: ATAPI
BusTypeAta: ATA
BusType1394: IEEE-1394
BusTypeSsa: SSA
BusTypeFibre: Fiber Channel
BusTypeUsb: USB
BusTypeRAID: RAID
BusTypeiSCSI: iSCSI
BusTypeSas: Serial Attached SCSI (SAS)
BusTypeSata: SATA
So example psueudo-code
STORAGE_BUS_TYPE GetStorageDeviceBusType(String StorageDevicePath)
{
/*
Given a storage device path of
\?\usb#vid_04f2&pid_0111#5&39fe81e&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
return its StorageBusType, e.g.:
BusTypeUsb
*/
//Open the disk for reading (must be an administrator)
HANDLE diskHandle = CreateFile(StorageDevicePath,
GENERIC_READ, //desired access
FILE_SHARE_READ | FILE_SHARE_WRITE, //share mode
null, //security attributes
OPEN_EXISTING, //creation disposition
FILE_ATTRIBUTE_NORMAL, //flags and attributes
0);
if (diskHandle == INVALID_HANDLE_VALUE)
RaiseLastWin32Error();
try
{
BOOL res;
DWORD bytesReturned;
//Set up what we want to query from the drive
STORAGE_PROPERTY_QUERY query= {};
query.QueryType = PropertyStandardQuery;
query.PropertyID = StorageDeviceProperty;
DWORD bufferSize;
// Query for the header to get the required buffer size
STORAGE_DESCRIPTOR_HEADER header;
res = DeviceIoControl(diskHandle, IOCTL_STORAGE_QUERY_PROPERTY,
ref query, sizeof(STORAGE_PROPERTY_QUERY),
ref header, sizeof(STORAGE_DESCRIPTOR_HEADER),
out bytesReturned, null);
if (!res) RaiseLastWin32Error();
bufferSize = header.Size;
//Allocate the buffer and query for the full property
STORAGE_DEVICE_DESCRIPTOR *deviceDescriptor = GetMem(bufferSize);
try
{
//Issue IOCTL_STORAGE_QUERY_PROPERTY to get STORAGE_DEVICE_DESCRIPTOR
res = DeviceIoControl(diskHandle, IOCTL_STORAGE_QUERY_PROPERTY,
#query, sizeof(STORAGE_PROPERTY_QUERY),
deviceDescriptor, bufferSize,
out bytesReturned, null));
if (!res)
RaiseLastWin32Error();
return deviceDescriptor.BusType;
}
finally
{
FreeMem(deviceDescriptor);
}
}
finally
{
CloseHandle(diskHandle);
}
}
Related
I'm writing a program that processes USB drives, to get information about connecting a new device, I signed up for a window message WM_DEVICECHANGE. But I, of course, do not receive messages about the devices that were connected before my program was launched. To process such devices, I wrote a search function, but I get a strange result. It finds my flash drive, but does not recognize it to be removable. Why?
Function
bool FindConnectedRemovableUsbstorDevices(std::list<std::wstring>& UsbList)
{
std::wstring ClassGuidString(L"{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}");
GUID ClassGuid;
BYTE buf[1024];
PSP_DEVICE_INTERFACE_DETAIL_DATA_W pspdidd = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA_W>(buf);
SP_DEVICE_INTERFACE_DATA spdid;
SP_DEVINFO_DATA spdd;
DWORD size;
SP_DEVINFO_DATA dev_data;
DWORD properties;
if(NOERROR != CLSIDFromString(ClassGuidString.c_str(), &ClassGuid))
return false;
HDEVINFO dev_info = INVALID_HANDLE_VALUE;
dev_info = SetupDiGetClassDevs(&ClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (dev_info == INVALID_HANDLE_VALUE)
return false;
DWORD index = 0;
BOOL ret = FALSE;
spdid.cbSize = sizeof(spdid);
while (true)
{
ret = SetupDiEnumDeviceInterfaces(dev_info, NULL, &ClassGuid, index, &spdid);
if (!ret)
break;
size = 0;
SetupDiGetDeviceInterfaceDetail(dev_info, &spdid, NULL, 0, &size, NULL);
//Get required size
if (size == 0 || size >= sizeof(buf))
continue;
//prepare structs
ZeroMemory(reinterpret_cast<PVOID>(pspdidd), 1024);
pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!
ZeroMemory(reinterpret_cast<PVOID>(&spdd), sizeof(spdd));
spdd.cbSize = sizeof(spdd);
BOOL res = SetupDiGetDeviceInterfaceDetail(dev_info, &spdid, pspdidd, size, &size, &spdd);
//Get info
if (!res)
continue;
HANDLE drive = CreateFileW(pspdidd->DevicePath, FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);//open device
if (drive == INVALID_HANDLE_VALUE)
continue;
printf("\n%S\r\n", pspdidd->DevicePath);
DWORD bytes_returned = 0;
BOOL b = DeviceIoControl(drive, IOCTL_STORAGE_CHECK_VERIFY2, NULL, 0, NULL, 0, &bytes_returned, NULL);
if (!b) //check is card reader?
{
printf("IOCTL_STORAGE_CHECK_VERIFY2 error = %d\r\n", GetLastError());
goto stop_process_device;
}
bytes_returned = 0;
STORAGE_DEVICE_NUMBER sdn;
//Get Drive number
b = DeviceIoControl(drive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &bytes_returned, NULL);
if (!b)
goto stop_process_device;
RtlZeroMemory(&dev_data, sizeof(SP_DEVINFO_DATA));
dev_data.cbSize = sizeof(dev_data);
if (SetupDiEnumDeviceInfo(dev_info, sdn.DeviceNumber, &dev_data))
{
//check property
b = SetupDiGetDeviceRegistryProperty(dev_info, &dev_data, SPDRP_REMOVAL_POLICY, NULL,
reinterpret_cast<PBYTE>(&properties), sizeof(properties), NULL);
if (b && properties != CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL)
{
UsbList.push_back(pspdidd->DevicePath);
printf("REMOVAL\r\n");
}
}
stop_process_device:
CloseHandle(drive);
index++;
}
SetupDiDestroyDeviceInfoList(dev_info);
return true;
}
And output
\\?\usbstor#disk&ven_generic-&prod_ms#ms-pro#hg&rev_1.00#20090703819900000&1#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
IOCTL_STORAGE_CHECK_VERIFY2 error = 21
\\?\ide#diskst3500418as_____________________________cc38____#5&5c6cfd6&0&1.0.0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
REMOVAL
\\?\usbstor#disk&ven_generic-&prod_sd#mmc&rev_1.00#20090703819900000&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
IOCTL_STORAGE_CHECK_VERIFY2 error = 21
\\?\scsi#disk&ven_ocz&prod_revodrive3_x2#5&19ad1f72&0&000000#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
\\?\ide#diskst1000lm014-1ej164______________________sm30____#5&2ea7e938&0&0.1.0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
\\?\usbstor#disk&ven_sandisk&prod_extreme&rev_0001#aa010823150434152862&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
\\?\ide#diskwdc_wd1002fbys-02a6b0___________________03.00c06#5&2ea7e938&0&0.0.0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
REMOVAL
Error 21 is empty card reader.
Sandisk is my flash. In Debug i saw that SetupDiGetDeviceRegistryProperty return property CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL, but i really don't know why...
If you just want to find the connected removable devices, there's a much simpler alternative using GetLogicalDriveStrings() and GetDriveType():
#define MAX_DRIVES 256
bool FindConnectedRemovableUsbstorDevices(std::list<std::wstring>& UsbList)
{
wchar_t drives[MAX_DRIVES];
wchar_t* temp = drives;
if (GetLogicalDriveStringsW(MAX_DRIVES, drives) == 0)
return false;
while (*temp != NULL)
{
if (GetDriveTypeW(temp) == 2 /* DRIVE_REMOVABLE */)
UsbList.push_back(temp);
// Go to the next drive
temp += lstrlenW(temp) + 1;
}
return true;
}
I don't know why my fisrt method of detection removable media works so strange, but method of RbMm works great. I send IOCTL query to every found device with IOCTL_STORAGE_QUERY_PROPERTY with StorageDeviceProperty and look for STORAGE_DEVICE_DESCRIPTOR.RemovableMedia field. All my devices recognized successfully and right.
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.
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?
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
I'm creating file deletion tool, so working with raw disk access. Have made some functions to read data.
A bit sorry because posting so much code, but not sure where is the real problem.
struct Extent
{
LONGLONG ClustersCount;
LARGE_INTEGER Lcn; //lcn - logical cluster number - the offset of a cluster from some arbitary point within volume
Extent() : ClustersCount(), Lcn()
{}
Extent(LONGLONG clustersCount, LARGE_INTEGER lcn) : ClustersCount(clustersCount), Lcn(lcn)
{}
};
typedef std::vector<Extent> ExtentsVector;
bool GetFileExtentPoints(const std::wstring& filePath, ExtentsVector& output)
{
output.clear();
DWORD err = ERROR_SUCCESS;
HANDLE file = CreateFile(filePath.c_str(), FILE_READ_ATTRIBUTES, (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), NULL, OPEN_EXISTING, 0, 0);
if (file != INVALID_HANDLE_VALUE)
{
STARTING_VCN_INPUT_BUFFER vcnStartBuffer = {};
RETRIEVAL_POINTERS_BUFFER pointsBuffer = {};
DWORD deviceIoControlDataritten = 0;
do
{
if (DeviceIoControl(file, FSCTL_GET_RETRIEVAL_POINTERS, &vcnStartBuffer, sizeof(vcnStartBuffer), &pointsBuffer, sizeof(pointsBuffer), &deviceIoControlDataritten, NULL))
{
Extent extent(pointsBuffer.Extents->NextVcn.QuadPart - pointsBuffer.StartingVcn.QuadPart, pointsBuffer.Extents[0].Lcn);
output.push_back(extent);
CloseHandle(file);
return true;
}
if (pointsBuffer.ExtentCount == 0) //small files could be stroed in master file table, so this part shouldn't always return false
{
CloseHandle(file);
return false;
}
Extent extent(pointsBuffer.Extents->NextVcn.QuadPart - pointsBuffer.StartingVcn.QuadPart, pointsBuffer.Extents[0].Lcn);
output.push_back(extent);
vcnStartBuffer.StartingVcn = pointsBuffer.Extents->NextVcn;
}
while (ERROR_MORE_DATA == GetLastError());
CloseHandle(file);
}
return false;
}
bool PermanentDeleteFile/*for now just read...*/(const std::wstring& filePath)
{
ExtentsVector extents;
if (!GetFileExtentPoints(filePath, extents))
return false;
DWORD sectorsPerCluster = 0;
DWORD bytesPerSector = 0;
LARGE_INTEGER fileSize = {};
HANDLE file = CreateFile(filePath.c_str(), FILE_READ_ATTRIBUTES, (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), NULL, OPEN_EXISTING, 0, 0);
if (file != INVALID_HANDLE_VALUE)
{
TCHAR drive[] = L"?:\\";
drive[0] = filePath[0];
if (!GetDiskFreeSpace(drive, §orsPerCluster, &bytesPerSector, NULL, NULL))
{
CloseHandle(file);
return false;
}
if (!GetFileSizeEx(file, &fileSize))
{
CloseHandle(file);
return false;
}
CloseHandle(file);
}
LONGLONG clusterSize = sectorsPerCluster * bytesPerSector;
LONGLONG clustersCount = fileSize.QuadPart / clusterSize + ((fileSize.QuadPart % clusterSize == 0) ? 0 : 1);
TCHAR rawDrive[] = L"\\\\.\\?:";
rawDrive[4] = filePath[0];
HANDLE driveHandle = CreateFile(rawDrive, /*GENERIC_WRITE*/GENERIC_READ/**/, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
if (driveHandle != INVALID_HANDLE_VALUE)
{
for (ExtentsVector::iterator it = extents.begin(); it != extents.end(); ++it)
{
LARGE_INTEGER distance = {};
distance.QuadPart = it->Lcn.QuadPart * clusterSize;
BOOL b = SetFilePointerEx(driveHandle, distance, NULL, FILE_BEGIN);
if (b)
{
std::string buffer;
buffer.resize(clusterSize * it->ClustersCount);
DWORD read = 0;
BOOL B = ReadFile(driveHandle, &buffer[0], clusterSize * it->ClustersCount, &read, NULL);
B = FALSE;//here I have breakpoint and for FAT type drives buffer contains invalid data
}
else
{
CloseHandle(driveHandle);
return false;
}
}
}
return false;
}
GetFileExtentPoints should collect clusters entries and cluster chain size for latter actions according to given file.
The place where the problem is seen is in PermanentDeleteFile I have marked that place with comment.
I have tried to read all my FAT32 drive and found that data I'm looking for is in drive but in other place so, as I understand FAT uses some kind of data offset. After that read this. As I think the offset is described by first 3 bytes in drive, but don't understand how to use it. In my case it is 0xEB 0x58 0x90. Want to ask, how to decode file system header into data offset.
BTW. I'm coding with C++ and using WinAPI.
EDIT: I have change my line into distance.QuadPart = it->Lcn.QuadPart * clusterSize + 0x01000000;, this works for FAT, however I don't want to have hardcoded constants, so can someone tell, if it is always this value, or it is calculated some way.