如何列出物理磁盘?

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

WMIC

wmic是一个非常完整的工具

wmic diskdrive list 

提供一个(太多)详细清单,例如

获取更less的信息

 wmic diskdrive list brief 

C

塞巴斯蒂安Godelet 在评论中提到:

在C:

 system("wmic diskdrive list"); 

电源shell

或者使用PowerShell:

 Get-WmiObject Win32_DiskDrive 

一种方法来做到这一点:

  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

这可能是5年来太晚:)。 但是,因为我没有看到这个答案,添加这个。

我们可以使用安装程序API来获取磁盘列表,即系统中实现GUID_DEVINTERFACE_DISK

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

另请参阅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; } 

我修改了一个名为“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 

唯一可行的方法是在所有的\\.\Physicaldiskx中调用CreateFile() ,其中x从0到15(16是允许的最大磁盘数)。 检查返回的句柄值。 如果无效检查了ERROR_FILE_NOT_FOUND的 GetLastError() 。 如果它返回其他东西,那么磁盘存在,但你不能访问它由于某种原因。

答案比以上所有答案都简单得多。 物理驱动器列表实际上存储在registry项中,该registry项还提供设备映射。

HKEY_LOCAL_MACHINE \系统\ CurrentControlSet \服务\硬盘\枚举

计数是PhysicalDrive#的编号,每个编号的registry值是相应的物理驱动器。

例如,registry值“0”是PhysicalDrive0。 该值是PhysicalDrive0映射到的实际设备。 这里包含的值可以传入参数pDeviceID中的CM_Locate_DevNode来使用即插即用服务。 这将允许您收集设备上的丰富信息。 如设备pipe理器中的属性,如“友好显示名称”,如果您需要驱动器的名称,序列号等。

没有必要在系统上运行WMI服务或其他hackery,而且这个function至less在2000年以后就已经存在于Windows中,而在Windows 10中也一直如此。

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

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

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

唯一正确的答案是@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来完成这个任务的声明。

从您自己的代码中,首先使用GetLogicalDrives()获取映射到系统中的所有驱动器,然后使用GetDriveType()查找每个驱动器的types。

我认为这是你的问题的一个很好的例子,有点晚了,但是……它是有效的

Thic WMIC命令组合正常工作:

 wmic volume list brief 

可能要包括老A:和B:驱动器,因为你永远不知道谁可能会使用它们! 我厌倦了USB驱动器碰撞我的两个SDHC驱动器只是为了Readyboost。 我一直把它们分配给高字母Z:Y:有一个实用程序,将分配驱动器字母设备,如你所愿。 我想知道….我可以做一个Readyboost驱动器字母A:? 是! 我可以把我的第二个SDHC驱动器号作为B:? 是!

我已经在当天使用了软盘驱动器,从来没有想过A:或者B:会为Readyboost派上用场。

我的观点是,不要假设A:&B:任何人都不会使用任何东西你甚至可能会发现旧的SUBST命令正在被使用!

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

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

将它们逐个传递到下面的函数中,并返回设备名称。 很干净,简单! 我在这里find了这个代码。

 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; 

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

制作美国英语字母表中所有字母的列表,跳过a&b。 “CDEFGHIJKLMNOPQRSTUVWXYZ”。 用CreateFile例如CreateFile("\\.\C:")打开每个驱动器。 如果它不返回INVALID_HANDLE_VALUE那么你有一个“好”的驱动器。 接下来获取该句柄,并通过DeviceIoControl运行它以获取磁盘#。 查看我的相关答案了解更多详情