在Windows 7中,如何从驱动器字母获取可移动设备的物理驱动器号?

4
我正在尝试查找Windows 7上CDROM驱动器的驱动器号(即,我需要在\\.\PhysicalDriveN中找到N以打开块设备进行读取)。此页面指出,IOCTL_STORAGE_GET_DEVICE_NUMBER应该有效,但对于C:和D:(其中D:是可移动驱动器),它返回0作为驱动器号,因此肯定是不正确的。建议使用IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,但在D:上失败并显示ERROR_INVALID_FUNCTION。
我感觉可能错过了关键概念。
以下是我的代码:
#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 > 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, &vde, sizeof(vde), &bytesReturned, NULL);

    if (ioctlSuccess != 0){
      printf("%d\n", vde.Extents->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, &sdn, sizeof(sdn), &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;
}

无论我是以管理员身份运行还是普通用户身份运行,都会得到以下输出:

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
2个回答

5
< p > "\\.\PhysicalDriveN" 只适用于(类似)硬盘的设备,而不适用于可移动磁盘。如果某个设备类似于可移动磁盘(或软盘、CD-ROM等),"\\.\X:" 将打开原始驱动器(其他驱动器不支持分区,因此对于它们不存在 "\\.\x:""\\.\PhysicalDiskN" 之间的区别)。通常情况下,您需要使用 GetDriveType 确定您拥有的磁盘类型,仅当该函数返回 DRIVE_FIXED 时,才尝试查找驱动器编号并使用 "\\.\PhysicalDriveN"


啊哈!那似乎是关键的概念 :-) - regularfry
1
这是严格的吗?我需要原始访问可移动类型的USB驱动器,但是打开\.\X:只会给我USB驱动器上的第一个分区 - 我正在寻找一种从X:\映射到\.\PhysicalDriveX的方法,看起来如果这样做可以成功,那就是我的答案。 - rb_
1
请问您能否告诉我您阅读到的关于可移动设备没有创建 \.\PhysicalDriveX 的源代码?我基于这个假设进行了构建,但现在出现了一个错误,不得不重新设计软件的这一部分,因为似乎Windows会为USB闪存驱动器创建 \.\PhysicalDriveX 条目,在闪存驱动器被移除时会留下编号间隔... - Calmarius
@Calmarius:抱歉,我不能。它曾经在MSDN上出现过,但似乎在过去的2.5年里已被编辑过。我可能需要重新撰写这个答案(而微软真的需要修改GetDriveType)。对于像热插拔硬盘这样的东西,“固定”和“可移动”磁盘之间的分界线不再像以前那样清晰,我也不确定它们现在遵循什么规则。 - Jerry Coffin
USB闪存驱动器,硬盘驱动器等肯定有“PhysicalDriveN”,并且您可以在它们上创建多个卷(也许不能通过磁盘管理UI)。 - Alex P.

2

这是我编写的代码,使用C#.Net语言实现:

using System.Management; //Add in a reference to this as well in the project settings
public static string GetPhysicalDevicePath(char DriveLetter)
{
    ManagementClass devs = new ManagementClass( @"Win32_Diskdrive");
    {
        ManagementObjectCollection moc = devs.GetInstances();
        foreach(ManagementObject mo in moc)
        {
            foreach (ManagementObject b in mo.GetRelated("Win32_DiskPartition"))
            {
                foreach (ManagementBaseObject c in b.GetRelated("Win32_LogicalDisk"))
                {
                    string DevName = string.Format("{0}", c["Name"]);
                    if (DevName[0] == DriveLetter)
                        return string.Format("{0}", mo["DeviceId"]); 
                }
            }
        }
    }
    return "";
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接