Windowsで物理ディスクを一覧表示する方法は? "\\\\.\PhysicalDrive0"
のリストを取得するために利用可能。
wmic は非常に完全なツールです
wmic diskdrive list
たとえば、(多すぎる)詳細なリストを提供する
少ない情報で
wmic diskdrive list brief
セバスチャン・ゴデレット 言及 コメント内 :
Cで:
system("wmic diskdrive list");
コメントしたように、WinAPIを呼び出すこともできますが、...「 Cアプリケーションを使用してWMIからデータを取得する方法? 」に示すように、これは非常に複雑です(一般的にC++ではなく、 C)。
またはPowerShellで:
Get-WmiObject Win32_DiskDrive
それを行う1つの方法:
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年遅すぎるかもしれません:)。しかし、これに対する答えがまだないようで、これを追加します。
Setup APIs を使用して、ディスクのリスト、つまり GUID_DEVINTERFACE_DISK
を実装するシステム内のデバイスを取得できます。
デバイスパスを取得したら、 IOCTL_STORAGE_GET_DEVICE_NUMBER
を発行して、"\\.\PHYSICALDRIVE%d"
でSTORAGE_DEVICE_NUMBER.DeviceNumber
を構築できます。
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;
}
答えは上記のすべての答えよりもはるかに簡単です。物理ドライブのリストは実際にはレジストリキーに保存され、デバイスマッピングも提供します。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\disk\Enum
CountはPhysicalDrive#の数であり、各レジストリ値は対応する物理ドライブです。
たとえば、レジストリ値「0」はPhysicalDrive0です。値は、PhysicalDrive0がマップされる実際のデバイスです。ここに含まれる値は、パラメーター内の CM_Locate_DevNodepDeviceIDに渡して、プラグアンドプレイサービスを使用できます。これにより、デバイスに関する豊富な情報を収集できます。ドライブ、シリアル番号などの名前が必要な場合は、「フレンドリ表示名」などのデバイスマネージャーのプロパティなど。
システムまたはその他のハッカーで実行されていない可能性のあるWMIサービスは不要です。この機能は、少なくとも2000年からWindowsに存在し、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
これを行う唯一の確実な方法は、すべての_\\.\Physicaldiskx
_でCreateFile()
を呼び出すことです。ここで、xは0〜15です(16は許可されるディスクの最大数です)。返されたハンドル値を確認してください。無効な場合は、ERROR_FILE_NOT_FOUNDのGetLastError()
を確認してください。他の何かを返す場合、ディスクは存在しますが、何らかの理由でアクセスできません。
唯一の正しい答えは@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
を使用するために必要な宣言を含めました。
GetLogicalDrives()は、マウントされているすべてのディスクパーティション、not物理ドライブを列挙します。
GetLogicalDrivesを使用して(または使用せずに)ドライブ文字を列挙し、QueryDosDevice()を呼び出して、文字がどの物理ドライブにマップされているかを確認できます。
または、HKEY_LOCAL_MACHINE\SYSTEM\MountedDevicesにあるレジストリの情報をデコードできます。ただし、そこにあるバイナリデータのエンコーディングは明らかではありません。 RussinovichとSolomonの本Microsoft Windows Internalsのコピーがある場合、このレジストリHiveについては第10章で説明します。
Thic WMICコマンドの組み合わせは正常に機能します。
wmic volume list brief
古いA:およびB:ドライブを含めたいと思うかもしれません。 USBドライブがReadyboost専用の2つのSDHCドライブにぶつかるのにうんざりしました。私はそれらを大文字のZに割り当てていました:Y:あなたが望むようにデバイスにドライブ文字を割り当てるユーティリティで。私は疑問に思った.... Readyboostドライブ文字Aを作成できますか?はい! 2番目のSDHCドライブ文字をBとして入力できますか?はい!
私はその日、フロッピードライブを使用していましたが、A:やB:がReadyboostに役立つとは思っていませんでした。
私のポイントは、A:&B:は誰にも使用されないと仮定しないことです。古いSUBSTコマンドが使用されていることさえあります。
今日、私はRSSリーダーでこれに出くわしました。よりクリーンなソリューションをお届けします。この例はDelphiにありますが、非常に簡単にC/C++に変換できます(すべてWin32です)。
次のレジストリの場所からすべての値の名前を照会します:HKLM\SYSTEM\MountedDevices
1つずつ、次の関数に渡すと、デバイス名が返されます。かなりきれいでシンプル! このコードはブログで見つけました。
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;
ここは、newの解決策ですWMI呼び出しを行うことで。
それから、あなたがする必要があるのはただ電話するだけです:
queryAndPrintResult(L"SELECT * FROM Win32_DiskDrive", L"Name");
「物理」アクセスが必要な場合は、最終的にストレージデバイスと通信できるようにするこのAPIを開発しています。それはオープンソースであり、いくつかの情報については現在のコードを見ることができます。その他の機能を確認してください: https://github.com/virtium/vtStor