85

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

4

15 回答 15

79

#WMIC wmic是一个非常完善的工具

wmic diskdrive list

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

了解较少的信息

wmic diskdrive list brief 

#C Sebastian Godelet在评论中提到:

在 C 中:

system("wmic diskdrive list");

如评论所述,您也可以调用 WinAPI,但是...如“如何使用 C 应用程序从 WMI 获取数据? ”中所示,这非常复杂(通常使用 C++,而不是 C 完成)。


#PowerShell 或使用 PowerShell:

Get-WmiObject Win32_DiskDrive

2022 年 2 月更新,微软在“我们不再开发的 Windows 10 功能”中宣布

WMIC 工具在 Windows 10 版本 21H1 和 Windows Server 的 21H1 通用可用性通道版本中已弃用。

此工具已被用于 WMI 的 Windows PowerShell取代。

注意:此弃用仅适用于命令行管理工具。WMI 本身不受影响。

于 2008-11-29T17:24:03.130 回答
52

一种方法:

  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

于 2012-07-27T08:09:49.473 回答
36

这可能为时已晚 5 年 :)。但是由于我还没有看到这个答案,所以添加了这个。

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

一旦我们有了他们的设备路径,我们就可以发出来IOCTL_STORAGE_GET_DEVICE_NUMBER构建"\\.\PHYSICALDRIVE%d"STORAGE_DEVICE_NUMBER.DeviceNumber

另见SetupDiGetClassDevs功能

#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;
}
于 2013-08-12T09:02:24.817 回答
25

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

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\disk\Enum

Count是 PhysicalDrive# 的编号,每个编号的 Registry Value 是对应的物理驱动器。

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

不需要可能不在系统或其他黑客上运行的 WMI 服务,并且此功能至少自 2000 年以来就已存在于 Windows 中,并且在 Windows 10 中仍然如此。

于 2016-05-20T12:34:54.863 回答
13

我修改了一个名为“dskwipe”的开源程序,以便从中提取磁盘信息。Dskwipe 是用 C 语言编写的,您可以从中提取此功能。二进制文件和源代码可在此处获得:dskwipe 0.3 已发布

返回的信息将如下所示:

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
于 2008-12-08T17:55:21.687 回答
12

唯一正确的答案是@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用于此任务的声明。

于 2015-02-16T21:33:41.590 回答
11

GetLogicalDrives() 枚举所有已安装的磁盘分区,而不是物理驱动器。

您可以使用(或不使用)GetLogicalDrives 枚举驱动器号,然后调用 QueryDosDevice() 以找出该字母映射到的物理驱动器。

或者,您可以解码注册表中 HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices 中的信息。然而,那里的二进制数据编码并不明显。如果你有 Russinovich 和 Solomon 的书 Microsoft Windows Internals 的副本,这个注册表配置单元将在第 10 章中讨论。

于 2008-11-29T18:11:28.337 回答
10

The only sure shot way to do this is to call CreateFile() on all \\.\Physicaldiskx where x is from 0 to 15 (16 is maximum number of disks allowed). Check the returned handle value. If invalid check GetLastError() for ERROR_FILE_NOT_FOUND. If it returns anything else then the disk exists but you cannot access it for some reason.

于 2012-04-19T12:26:38.143 回答
5

Thic WMIC 命令组合工作正常:

wmic volume list brief
于 2013-06-20T21:51:13.063 回答
3

如果您只需要查看现有磁盘,这个就足够了:

powershell "get-physicaldisk"
于 2020-12-04T23:59:32.787 回答
2

可能想要包括旧的 A: 和 B: 驱动器,因为你永远不知道谁可能在使用它们!我厌倦了 USB 驱动器碰撞我的两个仅用于 Readyboost 的 SDHC 驱动器。我一直将它们分配给高字母 Z: Y: 使用一个实用程序,它可以根据需要为设备分配驱动器号。我想知道.... 我可以制作一个 Readyboost 驱动器号 A: 吗?是的!我可以将我的第二个 SDHC 驱动器号设置为 B: 吗?是的!

我以前使用过软盘驱动器,从没想过 A: 或 B: 会在 Readyboost 中派上用场。

我的意思是,不要假设 A: & B: 不会被任何人用于任何事情您甚至可能会发现正在使用旧的 SUBST 命令!

于 2014-01-01T09:47:46.313 回答
2

是一个通过 WMI 调用来实现它的新解决方案。
然后你需要做的就是打电话:

queryAndPrintResult(L"SELECT * FROM Win32_DiskDrive", L"Name");
于 2018-02-12T09:25:59.427 回答
1

我今天刚刚在我的 RSS 阅读器中遇到了这个问题。我有一个更清洁的解决方案给你。这个例子是在 Delphi 中,但可以很容易地转换为 C/C++(都是 Win32)。

从以下注册表位置查询所有值名称: HKLM\SYSTEM\MountedDevices

将它们一一传递给以下函数,您将返回设备名称。相当干净和简单!我在这里的博客上找到了这段代码。

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;
于 2008-12-10T16:31:40.670 回答
1

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

于 2015-04-27T18:43:42.880 回答
-3

列出美国英语字母表中的所有字母,跳过 a 和 b。“CDEFGHIJKLMNOPQRSTUVWXYZ”。CreateFile用例如打开每个驱动器CreateFile("\\.\C:")。如果它没有返回INVALID_HANDLE_VALUE,那么你有一个“好”的驱动器。接下来拿起那个句柄并运行它DeviceIoControl以获得磁盘#。有关详细信息,请参阅我的相关答案

于 2012-02-18T08:12:34.000 回答