title: How do you get the physical drive number of a removable device from the drive letter in Windows 7?
body: <p>I'm trying to look up the physical drive number (as in, I need the <code>N</code> in <code>\\.\PhysicalDriveN</code> to open the block device for reading) from the drive letter of a CDROM drive on Windows 7. <a href="http://msdn.microsoft.com/en-us/library/ms676078%28v=vs.85%29.aspx" rel="nofollow">This page</a> indicates that IOCTL_STORAGE_GET_DEVICE_NUMBER should work, but it returns 0 for the drive number for both C: and D: (where D: is the removable drive), so that can't be right. IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS is also suggested, but that fails with an ERROR_INVALID_FUNCTION on D:.</p>
  
  <p>I can't help but feel that I've missed a crucial concept somewhere.</p>
  
  <p>Here's my code:</p>
  
  <pre><code>#include "stdafx.h"
  #include "Windows.h"
  
  
  void printLastError(){
    DWORD lastError;
    DWORD bytesReturned;
    WCHAR outbuf[2048];
  
    lastError = GetLastError();
  
    bytesReturned = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
      NULL, lastError, LANG_USER_DEFAULT, outbuf, 2048, NULL);
  
    if (bytesReturned &gt; 0){
      wprintf(outbuf);
    } else {
      printf("Error %d while formatting error %d\n", GetLastError(),     lastError);
    }
  }
  
  void readDeviceNumberByExtents(HANDLE hFile){
    BOOL ioctlSuccess;
    DWORD bytesReturned;
  
    VOLUME_DISK_EXTENTS vde;
  
    ioctlSuccess = DeviceIoControl(hFile,
      IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
      NULL, 0, &amp;vde, sizeof(vde), &amp;bytesReturned, NULL);
  
      if (ioctlSuccess != 0){
        printf("%d\n", vde.Extents-&gt;DiskNumber );
      } else {
        printLastError();
    }
  }
  
  void readDeviceNumberByStorage(HANDLE hFile){
    BOOL ioctlSuccess;
    DWORD bytesReturned;
  
    STORAGE_DEVICE_NUMBER sdn;
  
    ioctlSuccess = DeviceIoControl(hFile,
      IOCTL_STORAGE_GET_DEVICE_NUMBER,
      NULL, 0, &amp;sdn, sizeof(sdn), &amp;bytesReturned, NULL);
  
    if (ioctlSuccess != 0){
      printf("%d\n", sdn.DeviceNumber );
    } else {
      printLastError();
    }
  }
  
  void runTest(WCHAR* driveName){
    HANDLE driveHandle;
    DWORD diskNumber;
  
    driveHandle = CreateFile(driveName,
      0,
      FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL,
      OPEN_EXISTING,
      FILE_ATTRIBUTE_NORMAL,
      NULL);
  
    if (driveHandle != INVALID_HANDLE_VALUE){
      wprintf(L"Opened %s\n", driveName);
  
      printf("Device number by extents: ");
      readDeviceNumberByExtents(driveHandle);
      printf("Device number by storage: ");
      readDeviceNumberByStorage(driveHandle);
  
      CloseHandle(driveHandle);
    } else {
      printf("Failure!\n");   
    }
  }
  
  int _tmain(int argc, _TCHAR* argv[])
  {
    runTest(L"\\\\.\\C:");
    printf("\n");
    runTest(L"\\\\.\\D:");
  
    getc(stdin);
    return 0;
  }
  </code></pre>
  
  <p>...and the output when I run it, either as Administrator or not:</p>
  
  <pre><code>Opened \\.\C:
  Device number by extents: 0
  Device number by storage: 0
  
  Opened \\.\D:
  Device number by extents: Incorrect function.
  Device number by storage: 0
  </code></pre>