Take the 2-minute tour ×

How to list physical disks in windows? In order to obtain a list of "\.\PhysicalDrive0" available.

share|improve this question

12 Answers 12

wmic is a very complete tool

wmic diskdrive list

provide a (too much) detailed list, for instance

for less info

wmic diskdrive list brief 

Sebastian Godelet mentions in the comments:

In C:

system("wmic diskdrive list");
share|improve this answer
-1 Does not answer the question, which is asking for how to do it in C. –  unixman83 Feb 16 '12 at 13:26
+1 Does not answer the question, but it is a very useful piece of information :-) –  Grodriguez Jul 27 '12 at 7:53
you could do a system("wmic diskdrive list"); in C –  Sebastian Godelet Nov 21 '12 at 13:28

I've modified an open-source program called "dskwipe" in order to pull this disk information out of it. Dskwipe is written in C, and you can pull this function out of it. The binary and source are available here: dskwipe 0.3 has been released

The returned information will look something like this:

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
share|improve this answer
i thought it was it, but it force brute search for the drives..isn't there an api that will just report back the devices ? –  CiNN Dec 9 '08 at 23:03
Yes. SetupApi in Win32, function names start with SetupDi –  Warren P Dec 16 '11 at 20:06

One way to do it:

  1. Enumerate logical drives using GetLogicalDrives

  2. For each logical drive, open a file named "\\.\X:" (without the quotes) where X is the logical drive letter.

  3. Call DeviceIoControl passing the handle to the file opened in the previous step, and the dwIoControlCode parameter set to IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:

    HANDLE hHandle;
    VOLUME_DISK_EXTENTS diskExtents;
    DWORD dwSize;
    iRes = DeviceIoControl(
        (LPVOID) &diskExtents,
        (DWORD) sizeof(diskExtents),
        (LPDWORD) &dwSize,

This returns information of the physical location of a logical volume, as a VOLUME_DISK_EXTENTS structure.

In the simple case where the volume resides on a single physical drive, the physical drive number is available in diskExtents.Extents[0].DiskNumber

share|improve this answer
+1 Certainly a more accurate answer than mine ;) –  VonC Jul 27 '12 at 8:14
What if there is an empty disk without any (mounted) volumes? –  j_kubik Jul 7 at 2:15

From your own code, use GetLogicalDrives() first to get all of the drives mapped in the system, and then GetDriveType() to find out which sort of drive each one is.

share|improve this answer
It is not correct because logical drives don't correspond to physical ones. –  Sergey Podobry Jan 18 '12 at 11:48

GetLogicalDrives() enumerates all mounted disk partitions, not physical drives.

You can enumerate the drive letters with (or without) GetLogicalDrives, then call QueryDosDevice() to find out which physical drive the letter is mapped to.

Alternatively, you can decode the information in the registry at HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices. The binary data encodings there are not obvious, however. If you have a copy of Russinovich and Solomon's book Microsoft Windows Internals, this registry hive is discussed in Chapter 10.

share|improve this answer
can you provide example code? –  Chibueze Opata Mar 15 '12 at 14:35
QueryDosDevice retuens partition, not the disk itself. Single disk is split to C: and D:, Win7 x64. So: c => "\Device\HarddiskVolume2"; d => "\Device\HarddiskVolume3'" –  Arioch 'The Jul 25 '12 at 12:47

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.

share|improve this answer

This might be 5 years too late :). But as I see no answer for this yet, adding this.

We can use Setup APIs to get the list of disks ie., devices in the system implementing GUID_DEVINTERFACE_DISK.

Once we have their device paths, we can issue IOCTL_STORAGE_GET_DEVICE_NUMBER to construct "\\.\PHYSICALDRIVE%d" with STORAGE_DEVICE_NUMBER.DeviceNumber

See also 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;

    DWORD bytesReturned;


    // 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,
                                            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,
                                         &deviceInterfaceData ) ) {


        SetupDiGetDeviceInterfaceDetail( diskClassDevices,
                                         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,
                                              NULL ),
             "SetupDiGetDeviceInterfaceDetail - 2" );

        disk = CreateFile( deviceInterfaceDetailData->DevicePath,
                           FILE_SHARE_READ | FILE_SHARE_WRITE,
                           NULL );
        CHK( INVALID_HANDLE_VALUE != disk,
             "CreateFile" );

        CHK( DeviceIoControl( disk,
                              sizeof( STORAGE_DEVICE_NUMBER ),
                              NULL ),

        CloseHandle( disk );
        disk = INVALID_HANDLE_VALUE;

        cout << deviceInterfaceDetailData->DevicePath << endl;
        cout << "\\\\?\\PhysicalDrive" << diskNumber.DeviceNumber << endl;
        cout << endl;
    CHK( ERROR_NO_MORE_ITEMS == GetLastError( ),
         "SetupDiEnumDeviceInterfaces" );



    if ( INVALID_HANDLE_VALUE != diskClassDevices ) {
        SetupDiDestroyDeviceInfoList( diskClassDevices );

    if ( INVALID_HANDLE_VALUE != disk ) {
        CloseHandle( disk );

    return error;
share|improve this answer
Adding another link (I didn't have enough rep to post in the answer) Setup API Functions –  Arunachaleshwar Ravichandran Aug 12 '13 at 9:19
Sounds interesting. More complete than my answer above. +1 –  VonC Aug 12 '13 at 10:26

I think this is a very good sample for your question, a little late but... its valid

share|improve this answer
As far as I can tell (and I've tested the code you linked too), volumes don't relate to partitions in a 1 to many fashion, and don't give the access the OP is asking for. –  Matt Joiner Oct 28 '10 at 10:34
This answer doesn't deserve -1. It is no worse than other answers on this page and it's in C. –  unixman83 Feb 16 '12 at 13:03

Thic WMIC command combination works fine:

wmic volume list brief
share|improve this answer

I just ran across this in my RSS Reader today. I've got a cleaner solution for you. This example is in Delphi, but can very easily be converted to C/C++ (It's all Win32).

Query all value names from the following registry location: HKLM\SYSTEM\MountedDevices

One by one, pass them into the following function and you will be returned the device name. Pretty clean and simple! I found this code on a blog here.

function VolumeNameToDeviceName(const VolName: String): String;
  s: String;
  TargetPath: Array[0..MAX_PATH] of WideChar;
  bSucceeded: Boolean;
  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
    Result := TargetPath;
  else begin
    // raise exception

share|improve this answer
i want to have the physical name so that i could play with unallocated space, so my guess it that this unallocated space wouldn't have a mounted volume guid... –  CiNN Dec 12 '08 at 8:45
'Fraid this isn't what we're looking for, and is similar to @Alnitak's answer. –  Matt Joiner Oct 28 '10 at 10:30
You're supposed to use SetupApi in windows xp and later, and no longer use the registry, which was the way to do it in Win98, but not any more. –  Warren P Dec 16 '11 at 20:07

Might want to include the old A: and B: drives as you never know who might be using them! I got tired of USB drives bumping my two SDHC drives that are just for Readyboost. I had been assigning them to High letters Z: Y: with a utility that will assign drive letters to devices as you wish. I wondered.... Can I make a Readyboost drive letter A: ? YES! Can I put my second SDHC drive letter as B: ? YES!

I've used Floppy Drives back in the day, never thought that A: or B: would come in handy for Readyboost.

My point is, don't assume A: & B: will not be used by anyone for anything You might even find the old SUBST command being used!

share|improve this answer

Make a list of all letters in the US English Alphabet, skipping a & b. "CDEFGHIJKLMNOPQRSTUVWXYZ". Open each of those drives with CreateFile e.g. CreateFile("\\.\C:"). If it does not return INVALID_HANDLE_VALUE then you got a 'good' drive. Next take that handle and run it through DeviceIoControl to get the Disk #. See my related answer for more details.

share|improve this answer
Got to say, this is pretty much what I am thinking... –  swdev Apr 14 at 22:55

Your Answer


