Get drive type with SetupDiGetDeviceRegistryProperty
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开发者_如何学JAVA 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 issueIOCTL_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);
}
}
精彩评论