可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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
回答1:
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.
回答2:
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<: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; }
回答3:
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; //
}
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); } }