Как перечислить физические диски?
Как вывести список физических дисков в Windows? Для того, чтобы получить список "\\\\.\PhysicalDrive0"
имеется в наличии.
16 ответов
WMIC
wmic - очень полный инструмент
wmic diskdrive list
предоставить (слишком много) подробный список, например
для меньшего количества информации
wmic diskdrive list brief
С
Sebastian упоминает в комментариях:
В С:
system("wmic diskdrive list");
Как уже говорилось, вы также можете вызвать WinAPI, но... как показано в разделе " Как получить данные из WMI с помощью приложения C?", Это довольно сложно (и обычно выполняется с C++, а не с C).
PowerShell
Или с PowerShell:
Get-WmiObject Win32_DiskDrive
Один из способов сделать это:
Перечислять логические диски, используя
GetLogicalDrives
Для каждого логического диска откройте файл с именем
"\\.\X:"
(без кавычек) где X - буква логического диска.Вызов
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
,
Как только у нас есть пути к устройствам, мы можем выдать 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;
}
Ответ гораздо проще, чем все вышеперечисленные ответы. Список физических дисков фактически хранится в ключе реестра, который также отображает устройство.
HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ диск \Enum
Количество - это номер PhysicalDrive#, а каждому пронумерованному значению реестра соответствует соответствующий физический диск.
Например, значением реестра "0" является PhysicalDrive0. Значение - это фактическое устройство, которому сопоставлен PhysicalDrive0. Содержимое здесь может быть передано в CM_Locate_DevNode в параметре pDeviceID для использования сервисов plug and play. Это позволит вам собрать массу информации на устройстве. Такие, как свойства из диспетчера устройств, такие как "Дружественное отображаемое имя", если вам нужно имя для диска, серийные номера и многое другое.
Нет необходимости в службах WMI, которые могут не работать в системе или в других хакерских целях, и эта функциональность присутствует в Windows по крайней мере с 2000 года и продолжает действовать в Windows 10.
Я изменил программу с открытым исходным кодом под названием "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
Единственный правильный ответ - @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 Driver Development Kit довольно длительный процесс, поэтому я включил декларации, которые необходимо использовать DeviceIoControl
для этой задачи.
Единственный надежный способ сделать это - позвонить CreateFile()
на все \\.\Physicaldiskx
где x - от 0 до 15 (16 - максимально допустимое количество дисков). Проверьте возвращенное значение дескриптора. Если недействительный чек GetLastError()
для ERROR_FILE_NOT_FOUND. Если он возвращает что-то еще, значит, диск существует, но вы не можете получить к нему доступ по какой-то причине.
GetLogicalDrives() перечисляет все подключенные разделы диска, а не физические диски.
Вот довольно старое сравнение. Таким образом, возможности каждого сервера, несомненно, улучшились.
Изменить: Вот текущее сравнение.
Оба они более чем достаточно стабильны для производственного использования. Это действительно сводится к особенностям.
Thic WMIC комбинация команд работает отлично:
wmic volume list brief
Если вам нужно только посмотреть на существующие диски, этого будет достаточно:
powershell "get-physicaldisk"
Возможно, стоит включить старые диски A: и B:, так как вы никогда не знаете, кто их использует! Я устал от USB-накопителей, сталкивающихся с моими двумя SDHC-дисками, предназначенными только для Readyboost Я назначил их старшим буквам Z: Y: с помощью утилиты, которая назначит буквы дисков устройствам по вашему желанию. Я задавался вопросом.... Могу ли я сделать букву диска Readyboost A:? ДА! Могу ли я поставить мою вторую букву диска SDHC как B:? ДА!
Я использовал флоппи-дисководы в те времена, никогда не думал, что A: или B: пригодится для Readyboost.
Суть в том, что не думайте, что A: & B: не будет использоваться никем ни для чего. Вы даже можете обнаружить, что используется старая команда SUBST!
Вот новое решение сделать это с помощью вызовов WMI.
Тогда все, что вам нужно сделать, это просто позвонить:
queryAndPrintResult(L"SELECT * FROM Win32_DiskDrive", L"Name");
Я только что столкнулся с этим в моем читателе RSS сегодня. У меня есть более чистое решение для вас. Этот пример написан на Delphi, но его очень легко конвертировать в C/C++ (это все Win32).
Запросите все имена значений из следующего расположения реестра: HKLM \ SYSTEM \ MountingDevices
Один за другим передайте их в следующую функцию, и вам будет возвращено имя устройства. Довольно чисто и просто! Я нашел этот код в блоге здесь.
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, который в конечном итоге позволит вам связываться с устройствами хранения. Это открытый исходный код, и вы можете увидеть текущий код для получения дополнительной информации. Проверьте дополнительные возможности: https://github.com/virtium/vtStor
В Windows Powershell
Get-WmiObject -Class Win32_DiskDrive -ComputerName <COMPUTERNAME> | select Name,SerialNumber,SCSITargetID,Size
Составьте список всех букв английского алфавита США, пропуская a & b. "CDEFGHIJKLMNOPQRSTUVWXYZ". Откройте каждый из этих дисков с CreateFile
например CreateFile("\\.\C:")
, Если не вернется INVALID_HANDLE_VALUE
тогда у тебя "хороший" драйв. Затем возьмите эту ручку и пропустите DeviceIoControl
чтобы получить диск №. Смотрите мой ответ для более подробной информации.