program story

물리 디스크를 나열하는 방법은 무엇입니까?

inputbox 2020. 10. 31. 09:39
반응형

물리 디스크를 나열하는 방법은 무엇입니까?


Windows에서 물리 디스크를 나열하는 방법은 무엇입니까? "\\\\.\PhysicalDrive0"사용 가능한 목록을 얻으려면 .


WMIC

wmic 는 매우 완벽한 도구입니다.

wmic diskdrive list

예를 들어 (너무 많은) 자세한 목록을 제공하십시오.

적은 정보를 위해

wmic diskdrive list brief 

Sebastian Godelet 은 주석에서 언급합니다 .

C에서 :

system("wmic diskdrive list");

설명 된대로 WinAPI를 호출 할 수도 있지만 ... " C 응용 프로그램을 사용하여 WMI에서 데이터를 얻는 방법 "에서 볼 수 있듯이 이것은 매우 복잡합니다 (일반적으로 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사용하여 .NET 을 구현하는 시스템의 디스크 목록을 가져올 수 있습니다 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 \ disk \ Enum

Count 는 PhysicalDrive #의 수이고 번호가 매겨진 각 레지스트리 값은 해당 물리적 ​​드라이브입니다.

예를 들어 레지스트리 값 "0"은 PhysicalDrive0입니다. 값은 PhysicalDrive0이 매핑 된 실제 장치입니다. 값은 여기에 포함로 전달 될 수 CM_Locate_DevNode 매개 변수 내에서 pDeviceID 플러그 앤 플레이 서비스를 사용 할 수 있습니다. 이를 통해 장치에 대한 풍부한 정보를 수집 할 수 있습니다. 드라이브 이름, 일련 번호 등이 필요한 경우 "Friendly Display Name"과 같은 장치 관리자의 속성과 같은.

시스템이나 다른 해커에서 실행되지 않을 수있는 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

이를 수행하는 유일한 확실한 방법은 x가 0에서 15 (16은 허용되는 최대 디스크 수) 인 CreateFile()모든 \\.\Physicaldiskx에서 호출 하는 것 입니다. 반환 된 핸들 값을 확인하십시오. 잘못 선택하면 GetLastError()에 대한 ERROR_FILE_NOT_FOUND . 다른 것을 반환하면 디스크가 존재하지만 어떤 이유로 액세스 할 수 없습니다.


GetLogicalDrives ()는 물리적 드라이브가 아닌 마운트 된 모든 디스크 파티션을 열거 합니다.

GetLogicalDrives를 사용하거나 사용하지 않고 드라이브 문자를 열거 한 다음 QueryDosDevice ()를 호출하여 문자가 매핑 된 실제 드라이브를 찾을 수 있습니다.

또는 HKEY_LOCAL_MACHINE \ SYSTEM \ MountedDevices에있는 레지스트리의 정보를 디코딩 할 수 있습니다. 그러나 바이너리 데이터 인코딩은 명확하지 않습니다. Russinovich와 Solomon의 책 Microsoft Windows Internals가있는 경우이 레지스트리 하이브는 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 Driver Development Kit의 설치는 상당히 긴 프로세스라고 생각하므로이 작업에 필요한 선언을 포함했습니다 DeviceIoControl.


Thic WMIC 명령 조합이 잘 작동합니다.

wmic volume list brief

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!


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

If you want "physical" access, we're developing this API that will eventually allows you to communicate with storage devices. It's open source and you can see the current code for some information. Check back for more features: https://github.com/virtium/vtStor


Here is a new solution of doing it with doing WMI calls.
Then all you need to do is just to call :

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

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.

참고URL : https://stackoverflow.com/questions/327718/how-to-list-physical-disks

반응형