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

发布于 2024-10-28 19:59:53 字数 2570 浏览 0 评论 0原文

我正在尝试从驱动器查找物理驱动器编号(例如,我需要 \\.\PhysicalDriveN 中的 N 来打开块设备进行读取) Windows 7 上 CDROM 驱动器的盘符。此页 表示 IOCTL_STORAGE_GET_DEVICE_NUMBER 应该可以工作,但它为 C: 和 D: 的驱动器号返回 0(其中 D: 是可移动驱动器),因此这是不正确的。还建议使用 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

I'm trying to look up the physical drive number (as in, I need the N in \\.\PhysicalDriveN to open the block device for reading) from the drive letter of a CDROM drive on Windows 7. This page 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:.

I can't help but feel that I've missed a crucial concept somewhere.

Here's my 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 > 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;
}

...and the output when I run it, either as Administrator or not:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

§对你不离不弃 2024-11-04 19:59:53

“\\.\PhysicalDriveN” 仅适用于(类似的东西)硬盘驱动器,不适用于可移动磁盘。如果某个东西的作用类似于可移动磁盘(或软盘、CD-ROM 等),"\\.\X:" 打开原始驱动器(其他驱动器不支持分区,因此区分"\\.\x:""\\.\PhysicalDiskN" 之间不存在)。您通常希望使用 GetDriveType 来确定您拥有哪种类型的磁盘,只有当显示它是 DRIVE_FIXED 时,您才会尝试查找驱动器编号并使用 “\\.\PhysicalDriveN” 与它。

The "\\.\PhysicalDriveN" only works for (things that act like) hard drives, not removable disks. If something acts like a removable disk (or floppy, CD-ROM, etc.), "\\.\X:" opens the raw drive (other drives don't support partitions, so the distinction between "\\.\x:" and "\\.\PhysicalDiskN" doesn't exist for them). You normally want to use GetDriveType to figure out what kind of disk you have, and only if that says it's a DRIVE_FIXED do you attempt to find the drive number and use "\\.\PhysicalDriveN" with it.

半边脸i 2024-11-04 19:59:53

这是 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 "";
}

It's C#.Net code, but this is what i've written to do the job:

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 "";
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文