代码之家  ›  专栏  ›  技术社区  ›  CiNN

如何列出物理磁盘?

  •  63
  • CiNN  · 技术社区  · 16 年前

    如何在windows中列出物理磁盘? 为了获得 "\\\\.\PhysicalDrive0" 可用。

    14 回复  |  直到 6 年前
        1
  •  61
  •   VonC    6 年前

    小精灵

    wmic 是一个非常完整的工具

    wmic diskdrive list
    

    例如,提供一个(太多)详细的列表

    为了得到更少的信息

    wmic diskdrive list brief 
    

    C

    Sebastian Godelet 提到 in the comments :

    在C:

    system("wmic diskdrive list");
    

    如前所述,您也可以调用winapi,但是…如所示“ How to obtain data from WMI using a C Application? “这是相当复杂的(一般用C++,而不是C)。

    动力壳

    或者使用powershell:

    Get-WmiObject Win32_DiskDrive
    
        2
  •  40
  •   Grodriguez    12 年前

    一种方法是:

    1. 使用枚举逻辑驱动器 GetLogicalDrives

    2. 对于每个逻辑驱动器,打开名为 "\\.\X:" (不带引号)其中x是逻辑驱动器号。

    3. 呼叫 DeviceIoControl 将句柄传递给在上一步中打开的文件,然后 dwIoControlCode 参数设置为 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS :

      HANDLE hHandle;
      VOLUME_DISK_EXTENTS diskExtents;
      DWORD dwSize;
      [...]
      
      iRes = DeviceIoControl(
          hHandle,
          IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
          NULL,
          0,
          (LPVOID) &diskExtents,
          (DWORD) sizeof(diskExtents),
          (LPDWORD) &dwSize,
          NULL);
      

    它返回逻辑卷的物理位置信息,如 VOLUME_DISK_EXTENTS 结构。

    在卷位于单个物理驱动器上的简单情况下,物理驱动器号在 diskExtents.Extents[0].DiskNumber

        3
  •  27
  •   Community CDub    10 年前

    这可能已经晚了5年:)。但是我还没有找到答案,加上这个。

    我们可以使用 Setup APIs 获取磁盘列表,即系统中实现 GUID_DEVINTERFACE_DISK .

    一旦我们找到他们的设备路径,我们就可以发布 IOCTL_STORAGE_GET_DEVICE_NUMBER 构建 "\\.\PHYSICALDRIVE%d" 具有 STORAGE_DEVICE_NUMBER.DeviceNumber

    也见 SetupDiGetClassDevs function

    #include <Windows.h>
    #include <Setupapi.h>
    #include <Ntddstor.h>
    
    #pragma comment( lib, "setupapi.lib" )
    
    #include <iostream>
    #include <string>
    using namespace std;
    
    #define START_ERROR_CHK()           \
        DWORD error = ERROR_SUCCESS;    \
        DWORD failedLine;               \
        string failedApi;
    
    #define CHK( expr, api )            \
        if ( !( expr ) ) {              \
            error = GetLastError( );    \
            failedLine = __LINE__;      \
            failedApi = ( api );        \
            goto Error_Exit;            \
        }
    
    #define END_ERROR_CHK()             \
        error = ERROR_SUCCESS;          \
        Error_Exit:                     \
        if ( ERROR_SUCCESS != error ) { \
            cout << failedApi << " failed at " << failedLine << " : Error Code - " << error << endl;    \
        }
    
    int main( int argc, char **argv ) {
    
        HDEVINFO diskClassDevices;
        GUID diskClassDeviceInterfaceGuid = GUID_DEVINTERFACE_DISK;
        SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
        PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData;
        DWORD requiredSize;
        DWORD deviceIndex;
    
        HANDLE disk = INVALID_HANDLE_VALUE;
        STORAGE_DEVICE_NUMBER diskNumber;
        DWORD bytesReturned;
    
        START_ERROR_CHK();
    
        //
        // Get the handle to the device information set for installed
        // disk class devices. Returns only devices that are currently
        // present in the system and have an enabled disk device
        // interface.
        //
        diskClassDevices = SetupDiGetClassDevs( &diskClassDeviceInterfaceGuid,
                                                NULL,
                                                NULL,
                                                DIGCF_PRESENT |
                                                DIGCF_DEVICEINTERFACE );
        CHK( INVALID_HANDLE_VALUE != diskClassDevices,
             "SetupDiGetClassDevs" );
    
        ZeroMemory( &deviceInterfaceData, sizeof( SP_DEVICE_INTERFACE_DATA ) );
        deviceInterfaceData.cbSize = sizeof( SP_DEVICE_INTERFACE_DATA );
        deviceIndex = 0;
    
        while ( SetupDiEnumDeviceInterfaces( diskClassDevices,
                                             NULL,
                                             &diskClassDeviceInterfaceGuid,
                                             deviceIndex,
                                             &deviceInterfaceData ) ) {
    
            ++deviceIndex;
    
            SetupDiGetDeviceInterfaceDetail( diskClassDevices,
                                             &deviceInterfaceData,
                                             NULL,
                                             0,
                                             &requiredSize,
                                             NULL );
            CHK( ERROR_INSUFFICIENT_BUFFER == GetLastError( ),
                 "SetupDiGetDeviceInterfaceDetail - 1" );
    
            deviceInterfaceDetailData = ( PSP_DEVICE_INTERFACE_DETAIL_DATA ) malloc( requiredSize );
            CHK( NULL != deviceInterfaceDetailData,
                 "malloc" );
    
            ZeroMemory( deviceInterfaceDetailData, requiredSize );
            deviceInterfaceDetailData->cbSize = sizeof( SP_DEVICE_INTERFACE_DETAIL_DATA );
    
            CHK( SetupDiGetDeviceInterfaceDetail( diskClassDevices,
                                                  &deviceInterfaceData,
                                                  deviceInterfaceDetailData,
                                                  requiredSize,
                                                  NULL,
                                                  NULL ),
                 "SetupDiGetDeviceInterfaceDetail - 2" );
    
            disk = CreateFile( deviceInterfaceDetailData->DevicePath,
                               GENERIC_READ,
                               FILE_SHARE_READ | FILE_SHARE_WRITE,
                               NULL,
                               OPEN_EXISTING,
                               FILE_ATTRIBUTE_NORMAL,
                               NULL );
            CHK( INVALID_HANDLE_VALUE != disk,
                 "CreateFile" );
    
            CHK( DeviceIoControl( disk,
                                  IOCTL_STORAGE_GET_DEVICE_NUMBER,
                                  NULL,
                                  0,
                                  &diskNumber,
                                  sizeof( STORAGE_DEVICE_NUMBER ),
                                  &bytesReturned,
                                  NULL ),
                 "IOCTL_STORAGE_GET_DEVICE_NUMBER" );
    
            CloseHandle( disk );
            disk = INVALID_HANDLE_VALUE;
    
            cout << deviceInterfaceDetailData->DevicePath << endl;
            cout << "\\\\?\\PhysicalDrive" << diskNumber.DeviceNumber << endl;
            cout << endl;
        }
        CHK( ERROR_NO_MORE_ITEMS == GetLastError( ),
             "SetupDiEnumDeviceInterfaces" );
    
        END_ERROR_CHK();
    
    Exit:
    
        if ( INVALID_HANDLE_VALUE != diskClassDevices ) {
            SetupDiDestroyDeviceInfoList( diskClassDevices );
        }
    
        if ( INVALID_HANDLE_VALUE != disk ) {
            CloseHandle( disk );
        }
    
        return error;
    }
    
        4
  •  13
  •   HooliganCoder    9 年前

    答案远比以上所有答案简单。物理驱动器列表实际上存储在一个注册表项中,该注册表项还提供设备映射。

    hkey_local_machine\system\currentcontrolset\services\disk\enum本地计算机

    伯爵 是PhysicalDrive的编号,每个编号的注册表值都是相应的物理驱动器。

    例如,注册表值“0”是PhysicalDrive0。该值是PhysicalDrive0映射到的实际设备。此处包含的值可以传递到 CM_Locate_DevNode 参数内 PDEVICID 使用即插即用服务。这将允许您在设备上收集大量信息。例如设备管理器中的属性,如“友好显示名称”(如果需要驱动器名称、序列号等)。

    不需要不在系统或其他黑客上运行的wmi服务,并且此功能至少从2000年起就存在于windows中,并且在windows 10中继续存在。

        5
  •  12
  •   Mick    16 年前

    我修改了一个名为“dskwipe”的开源程序,以便从中提取磁盘信息。dskwipe是用c编写的,您可以从中提取这个函数。二进制文件和源文件如下: dskwipe 0.3 has been released

    返回的信息如下所示:

    Device Name                         Size Type      Partition Type
    ------------------------------ --------- --------- --------------------
    \\.\PhysicalDrive0               40.0 GB Fixed
    \\.\PhysicalDrive1               80.0 GB Fixed
    \Device\Harddisk0\Partition0     40.0 GB Fixed
    \Device\Harddisk0\Partition1     40.0 GB Fixed     NTFS
    \Device\Harddisk1\Partition0     80.0 GB Fixed
    \Device\Harddisk1\Partition1     80.0 GB Fixed     NTFS
    \\.\C:                           80.0 GB Fixed     NTFS
    \\.\D:                            2.1 GB Fixed     FAT32
    \\.\E:                           40.0 GB Fixed     NTFS
    
        6
  •  9
  •   Charles Menguy jdw6415    13 年前

    唯一可靠的办法就是打电话 CreateFile() 在所有 \\.\Physicaldiskx 其中x从0到15(16是允许的最大磁盘数)。检查返回的句柄值。如果支票无效 GetLastError() 对于 找不到错误文件 . 如果它返回任何其他内容,则磁盘存在,但由于某种原因您无法访问它。

        7
  •  8
  •   Die in Sente    16 年前

    getLogicalDrive()枚举所有已装入的磁盘分区, 物理驱动器。

    您可以使用(或不使用)getLogicalDrive枚举驱动器号,然后调用queryDosDevice()找出该驱动器号映射到哪个物理驱动器。

    或者,您可以在注册表中的hkey_local_machine\system\mounteddevices对信息进行解码。但是,那里的二进制数据编码并不明显。如果您有一本russinovich和solomon的书microsoft windows internals,这个注册表配置单元将在第10章中讨论。

        8
  •  8
  •   polkovnikov.ph    9 年前

    唯一正确的答案是@grodriguez的,这里有一个他懒得写的代码:

    #include <windows.h>
    #include <iostream>
    #include <bitset>
    #include <vector>
    using namespace std;
    
    typedef struct _DISK_EXTENT {
        DWORD         DiskNumber;
        LARGE_INTEGER StartingOffset;
        LARGE_INTEGER ExtentLength;
    } DISK_EXTENT, *PDISK_EXTENT;
    
    typedef struct _VOLUME_DISK_EXTENTS {
        DWORD       NumberOfDiskExtents;
        DISK_EXTENT Extents[ANYSIZE_ARRAY];
    } VOLUME_DISK_EXTENTS, *PVOLUME_DISK_EXTENTS;
    
    #define CTL_CODE(DeviceType, Function, Method, Access) \
        (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
    #define IOCTL_VOLUME_BASE ((DWORD)'V')
    #define METHOD_BUFFERED 0
    #define FILE_ANY_ACCESS 0x00000000
    #define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS CTL_CODE(IOCTL_VOLUME_BASE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS)
    
    int main() {
        bitset<32> drives(GetLogicalDrives());
        vector<char> goodDrives;
        for (char c = 'A'; c <= 'Z'; ++c) {
            if (drives[c - 'A']) {
                if (GetDriveType((c + string(":\\")).c_str()) == DRIVE_FIXED) {
                    goodDrives.push_back(c);
                }
            }
        }
        for (auto & drive : goodDrives) {
            string s = string("\\\\.\\") + drive + ":";
            HANDLE h = CreateFileA(
                s.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_RANDOM_ACCESS, NULL
            );
            if (h == INVALID_HANDLE_VALUE) {
                cerr << "Drive " << drive << ":\\ cannot be opened";
                continue;
            }
            DWORD bytesReturned;
            VOLUME_DISK_EXTENTS vde;
            if (!DeviceIoControl(
                h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
                NULL, 0, &vde, sizeof(vde), &bytesReturned, NULL
            )) {
                cerr << "Drive " << drive << ":\\ cannot be mapped into physical drive";
                continue;
            }
            cout << "Drive " << drive << ":\\ is on the following physical drives: ";
            for (int i = 0; i < vde.NumberOfDiskExtents; ++i) {
                cout << vde.Extents[i].DiskNumber << ' ';
            }
            cout << endl;
        }
    }
    

    我认为安装windows驱动程序开发工具包是一个相当长的过程,所以我已经包含了需要使用的声明 DeviceIoControl 为了这个任务。

        9
  •  2
  •   Jens Erat    11 年前

    thic wmic命令组合工作正常:

    wmic volume list brief
    
        10
  •  2
  •   liverwort    11 年前

    可能想包括旧的A:和B:驱动器,因为你永远不知道谁可能在使用它们! 我厌倦了USB驱动器撞到我的两个SDHC驱动器,只是为了方便。 我已经将它们分配给了高字母z:y:和一个实用程序,可以根据您的意愿将驱动器号分配给设备。我想……我能做一个现成的驱动器号A:?对! 我可以把我的第二个SDHC驱动器号设为B:?对!

    我以前用过软驱,从没想过A:或B:会派上用场 准备好了。

    我的观点是,不要假设a:&b:不会被任何人用来做任何事情 您甚至可能会发现使用的是旧的subst命令!

        11
  •  1
  •   Mick    16 年前

    我今天在我的rss阅读器上看到了这个。我有更干净的解决方案给你。这个例子是在Delphi中,但是可以很容易地转换成C/C++(它都是Win32)。

    从以下注册表位置查询所有值名称: hklm\system\mounteddevices设备

    一个接一个地,将它们传递到下面的函数中,您将返回设备名。非常干净简单! I found this code on a blog here.

    function VolumeNameToDeviceName(const VolName: String): String;
    var
      s: String;
      TargetPath: Array[0..MAX_PATH] of WideChar;
      bSucceeded: Boolean;
    begin
      Result := ”;
      // VolumeName has a format like this: \\?\Volume{c4ee0265-bada-11dd-9cd5-806e6f6e6963}\
      // We need to strip this to Volume{c4ee0265-bada-11dd-9cd5-806e6f6e6963}
      s :=  Copy(VolName, 5, Length(VolName) - 5);
    
      bSucceeded := QueryDosDeviceW(PWideChar(WideString(s)), TargetPath, MAX_PATH) <> 0;
      if bSucceeded then
      begin
        Result := TargetPath;
      end
      else begin
        // raise exception
      end;
    
    end;
    
        12
  •  1
  •   phandinhlan    10 年前

    如果您想要“物理”访问,我们正在开发这个api,它最终将允许您与存储设备通信。它是开源的,您可以查看当前代码以获取一些信息。查看更多功能: https://github.com/virtium/vtStor

        13
  •  1
  •   Just Shadow    7 年前

    Here 是一个 新的 通过执行wmi调用来完成此任务的解决方案。
    那么你只需要打电话给:

    queryAndPrintResult(L"SELECT * FROM Win32_DiskDrive", L"Name");
    
        14
  •  -2
  •   Community CDub    8 年前

    列出美式英语字母表中的所有字母,跳过A&B“cdefghijklmnopqrstuvwxyz”。打开每个驱动器 CreateFile 例如 CreateFile("\\.\C:") . 如果它不回来 INVALID_HANDLE_VALUE 那你的车开得很好。下一步拿着那个把手,把它穿过去 DeviceIoControl 以获取磁盘。 See my related answer for more details .