Как перечислить физические диски?

Как вывести список физических дисков в 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

Один из способов сделать это:

  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,

Как только у нас есть пути к устройствам, мы можем выдать 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 чтобы получить диск №. Смотрите мой ответ для более подробной информации.

Другие вопросы по тегам