web-dev-qa-db-fra.com

Comment lister les disques physiques?

Comment lister les disques physiques sous Windows? Pour obtenir une liste de "\\\\.\PhysicalDrive0" disponible.

69
CiNN

WMIC

wmic est un outil très complet

wmic diskdrive list

fournir une liste (trop) détaillée, par exemple

pour moins d'informations

wmic diskdrive list brief 

C

Sebastian Godelet mentionne dans les commentaires :

En C:

system("wmic diskdrive list");

Comme indiqué, vous pouvez également appeler WinAPI, mais ... comme indiqué dans " Comment obtenir des données à partir de WMI à l'aide d'une application C? ", ceci est assez complexe C).

PowerShell

Ou avec PowerShell:

Get-WmiObject Win32_DiskDrive
64
VonC

Une façon de le faire:

  1. Énumérer les lecteurs logiques à l'aide de GetLogicalDrives

  2. Pour chaque lecteur logique, ouvrez un fichier nommé "\\.\X:" (sans les guillemets) où X est la lettre du lecteur logique.

  3. Appelez DeviceIoControl en transmettant le descripteur au fichier ouvert à l'étape précédente et définissez le paramètre dwIoControlCode sur 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);
    

Ceci retourne des informations sur l'emplacement physique d'un volume logique, sous la forme VOLUME_DISK_EXTENTS structure.

Dans le cas simple où le volume réside sur un seul lecteur physique, le numéro du lecteur physique est disponible dans diskExtents.Extents[0].DiskNumber

43
Grodriguez

Cela pourrait être 5 ans trop tard :). Mais comme je ne vois pas encore de réponse à cela, ajoutez ceci.

Nous pouvons utiliser Setup APIs pour obtenir la liste des disques, c’est-à-dire les périphériques du système implémentant GUID_DEVINTERFACE_DISK .

Une fois que nous avons leurs chemins de périphérique, nous pouvons émettre IOCTL_STORAGE_GET_DEVICE_NUMBER pour construire "\\.\PHYSICALDRIVE%d" avec STORAGE_DEVICE_NUMBER.DeviceNumber

Voir aussi 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;
}
27
arun

La réponse est beaucoup plus simple que toutes les réponses ci-dessus. La liste des lecteurs physiques est en réalité stockée dans une clé de registre qui donne également le mappage du périphérique.

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\disk\Enum

Count est le nombre de disques PhysicalDrive # et chaque valeur de registre numérotée est le lecteur physique correspondant.

Par exemple, la valeur de registre "0" correspond à PhysicalDrive0. La valeur correspond au périphérique réel mappé sur PhysicalDrive0. La valeur contenue ici peut être passée dans CM_Locate_DevNode dans le paramètre pDeviceID pour utiliser les services plug-and-play. Cela vous permettra de recueillir une mine d'informations sur l'appareil. Telles que les propriétés du Gestionnaire de périphériques telles que "Nom d'affichage convivial" si vous avez besoin d'un nom pour le lecteur, de numéros de série, etc.

Il n’est pas nécessaire de recourir à des services WMI qui ne s'exécutent peut-être pas sur le système ou d’autres types de piratage. Cette fonctionnalité est présente dans Windows depuis au moins 2000 et continue de l’être dans Windows 10.

14
HooliganCoder

J'ai modifié un programme open-source appelé "dskwipe" afin d'extraire cette information de disque. Dskwipe est écrit en C et vous pouvez en extraire cette fonction. Le binaire et le source sont disponibles ici: dskwipe 0.3 a été publié

Les informations retournées ressembleront à ceci:

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
12
Mick

Le seul moyen sûr de procéder consiste à appeler CreateFile() sur tout \\.\Physicaldiskx Où x est compris entre 0 et 15 (16 correspond au nombre maximal de disques autorisé). Vérifiez la valeur de la poignée renvoyée. Si non valide, vérifiez GetLastError() pour ERROR_FILE_NOT_FOUND. S'il renvoie autre chose, le disque existe mais vous ne pouvez pas y accéder pour une raison quelconque.

10
anni

La seule réponse correcte est celle de @Grodriguez, et voici un code qu'il était trop paresseux pour écrire:

#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;
    }
}

Je pense que l'installation du kit de développement de pilotes Windows est un processus assez long. J'ai donc inclus les déclarations nécessaires pour utiliser DeviceIoControl dans cette tâche.

8
polkovnikov.ph

GetLogicalDrives () énumère toutes les partitions de disque montées, pas lecteurs physiques.

Vous pouvez énumérer les lettres de lecteur avec (ou sans) GetLogicalDrives, puis appeler QueryDosDevice () pour déterminer le lecteur physique auquel la lettre est mappée.

Vous pouvez également décoder les informations du registre à l'adresse HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices. Les codages de données binaires ne sont toutefois pas évidents. Si vous avez un exemplaire du livre Microsoft Windows Internals de Russinovich et Solomon, ce registre Hive est présenté au chapitre 10.

8
Die in Sente

La combinaison de commandes Thic WMIC fonctionne bien:

wmic volume list brief
2
user2506992

Vous voudrez peut-être inclure les anciens disques A: et B: car vous ne savez jamais qui les utilise! J'en avais marre des clés USB qui heurtaient mes deux disques SDHC réservés à Readyboost. Je les avais assignées aux lettres majuscules Z: Y: avec un utilitaire qui assignera les lettres de lecteur aux périphériques à votre guise. Je me demandais…. Puis-je créer une lettre de lecteur Readyboost A:? OUI! Puis-je mettre ma deuxième lettre de lecteur SDHC comme B:? OUI!

J'ai utilisé des lecteurs de disquettes dans la journée, jamais pensé que A: ou B: serait utile pour Readyboost.

Mon point est, ne supposez pas que A: & B: ne sera utilisé par personne pour quoi que ce soit. Vous pourriez même trouver l'ancienne commande SUBST utilisée!

2
liverwort

Je viens de découvrir cela dans mon lecteur RSS aujourd'hui. J'ai une solution plus propre pour vous. Cet exemple est en Delphi, mais peut très facilement être converti en C/C++ (c'est tout Win32).

Interrogez tous les noms de valeur à partir de l'emplacement de registre suivant: HKLM\SYSTEM\MountedDevices

Un par un, transmettez-les à la fonction suivante et vous recevrez le nom du périphérique. Assez propre et simple! J'ai trouvé ce code sur un blog ici.

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;
1
Mick

Ici est une nouvelle solution en faisant des appels WMI.
Ensuite, tout ce que vous avez à faire est simplement d'appeler:

queryAndPrintResult(L"SELECT * FROM Win32_DiskDrive", L"Name");
1
Just Shadow

Si vous souhaitez un accès "physique", nous développons cette API qui vous permettra éventuellement de communiquer avec des périphériques de stockage. C'est open source et vous pouvez voir le code actuel pour quelques informations. Revenez pour plus de fonctionnalités: https://github.com/virtium/vtStor

1
phandinhlan