6

I'm trying to differentiate between a USB flash drive and a USB hard drive on Windows using the Win32 API.

The GetDriveType() function will return DRIVE_REMOVABLE if the drive is removable, and USB flash drives are of course removable. But I'm thinking that Windows probably considers USB hard drives removable as well (unfortunately I don't have access to a USB hard drive to test it out).

Thanks in advance.

user408962
  • 61
  • 1
  • 2
  • Just out of curiosity, why do you want to do this? Are you going to do something different depending on what type of drive it is? As others have said, the DriveType is not very consistent (though it is probably "good enough"). – Luke Aug 03 '10 at 13:47
  • [macOS equivalent of this same problem](https://stackoverflow.com/questions/65245018) – hippietrail Dec 11 '20 at 02:45

7 Answers7

2
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Method      OpenVolume
//  Purpose:    Open volume for removal. Change to ::CreateFile(volumeName, 0, 0, 0, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);
//              if you just want to inquire if it's removable. 
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

HANDLE OpenVolume(const char& driveLetter)
{
    char volumeName[8] = "";
    char* volumeFormat = "\\\\.\\%c:";
    sprintf(volumeName, volumeFormat, driveLetter);

    HANDLE volume = ::CreateFile(volumeName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
    if (volume == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;

    DWORD bytesReturned = 0;
    STORAGE_HOTPLUG_INFO Info = {0};
    if (::DeviceIoControl(volume, IOCTL_STORAGE_GET_HOTPLUG_INFO, 0, 0, &Info, sizeof(Info), &bytesReturned, NULL)) 
    {
        if (!(Info.MediaRemovable || Info.DeviceHotplug)) 
        {
            ::CloseHandle(volume);
            ::SetLastError(ERROR_INVALID_PARAMETER);
            return INVALID_HANDLE_VALUE;
        }
    }

    return volume;
}
Marty
  • 21
  • 1
2

Windows returns DRIVE_FIXED for external USB hard drives and usually returns DRIVE_REMOVABLE for USB flash sticks. For this reason if you want to access multiple partitions on a flash memory you have to install a filter driver to tell windows it's not a DRIVE_REMOVABLE but a DRIVE_FIXED instead. Windows only "sees" the first partition on flash sticks causing a lot of trouble for ESXi boot usb stick users ;-)

Camilo Estevez
  • 637
  • 1
  • 8
  • 16
2

If you want to determine that a device is USB device, you can open its handle and send IOCTL queries using DeviceIoControl() to get bus type a device is connected to.

EnumUsbDrivesLetters - the post is in Russian but it contains C++ source code, so the matter could be understood easily.

Cheers, Andriy

Andriy
  • 123
  • 12
  • Please do not copy-paste answers over a number of questions, linking to your own blogspot. This will be considered spamming. – Joris Meys Jun 10 '11 at 09:00
1

Actually windows doesn't, GetDriveType returns 3 (DRIVE_FIXED) for both my usb hard-drives.

monoceres
  • 4,722
  • 4
  • 38
  • 63
  • No kidding, thanks. And your USB hard drives are run-of-the-mill, and there are no special driver settings or anything like that that might cause Windows to consider them DRIVE_FIXED instead of DRIVE_REMOVABLE? – user408962 Aug 02 '10 at 19:07
  • They're just standard western digital drives and my windows installation is pretty fresh so nothing on the driver front has changed from the default settings. – monoceres Aug 02 '10 at 19:15
1

I thinks the key is drive properties, eg Cylinder count. You can use WMI interface to determine such information. Here is an example http://www.computerperformance.co.uk/vbscript/wmi_disks_physical.htm

Anton Semenov
  • 6,227
  • 5
  • 41
  • 69
0

The drive type is ultimately determined by the drivers; there's no fail-safe way to make the sort of determination that you're looking for.

I can say, however, that while I have seen a USB flash stick return DRIVE_FIXED, I have never seen a normal hard drive return DRIVE_REMOVEABLE. That's not to say that it's completely impossible for that to happen, but I've never seen it.

I'd say relying on those two values is probably the closest that you're going to get.

Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
  • Interesting you say you've seen a flash stick return DRIVE_FIXED, as I found this a few minutes before reading your comment: http://social.msdn.microsoft.com/forums/en-US/embeddedwindowscomponents/thread/cfffc7b6-5679-46fc-a1c9-4c08228b7b47/ – user408962 Aug 02 '10 at 19:23
  • It's not ultimately determined by the drivers, because the drivers determine it based on what the device reports back, which isn't always consistent. – Ana Betts Nov 22 '10 at 17:59
0

http://en.wikipedia.org/wiki/SCSI_Pass_Through_Interface will let you send raw SCSI commands to the device - you want to send down either INQUIRY or MODE SENSE to find out what you're looking for. However, a far better alternative may be the VDS APIs, if it will provide you correct information (I'm not sure whether it will in this case)

Ana Betts
  • 73,868
  • 16
  • 141
  • 209