Get drive type with SetupDiGetDeviceRegistryProperty

前端 未结 3 898
广开言路
广开言路 2020-12-17 08:22

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

相关标签:
3条回答
  • 2020-12-17 08:45

    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.

    0 讨论(0)
  • 2020-12-17 08:47

    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);
       }       
    
    }
    
    0 讨论(0)
  • 2020-12-17 09:02

    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;
    }
    
    0 讨论(0)
提交回复
热议问题