Wie liste ich physische Festplatten in Windows auf? Um eine Liste der "\\\\.\PhysicalDrive0"
verfügbaren zu erhalten.
Antworten:
wmic ist ein sehr vollständiges Werkzeug
wmic diskdrive list
Geben Sie zum Beispiel eine (zu viele) detaillierte Liste an
für weniger info
wmic diskdrive list brief
Sebastian Godelet erwähnt in den Kommentaren :
In C:
system("wmic diskdrive list");
Wie kommentiert, können Sie auch die WinAPI aufrufen, aber ... wie unter " So erhalten Sie Daten von WMI mit einer C-Anwendung? " Gezeigt , ist dies recht komplex (und wird im Allgemeinen mit C ++ und nicht mit C ausgeführt).
Oder mit PowerShell:
Get-WmiObject Win32_DiskDrive
system("wmic diskdrive list");
in C
Ein Weg, es zu tun:
Zählen Sie logische Laufwerke mit auf GetLogicalDrives
Öffnen Sie für jedes logische Laufwerk eine Datei mit dem Namen "\\.\X:"
(ohne Anführungszeichen), wobei X der Buchstabe des logischen Laufwerks ist.
Rufen Sie auf, DeviceIoControl
indem Sie das Handle an die im vorherigen Schritt geöffnete Datei übergeben und den dwIoControlCode
Parameter auf Folgendes setzen 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);
Dies gibt Informationen über den physischen Speicherort eines logischen Volumes als VOLUME_DISK_EXTENTS
Struktur zurück.
In dem einfachen Fall, in dem sich das Volume auf einem einzelnen physischen Laufwerk befindet, ist die Nummer des physischen Laufwerks in verfügbar diskExtents.Extents[0].DiskNumber
DeviceIoControl(IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS)
Aufrufs fehlschlägt, wenn sich ein Volume über mehrere Festplatten erstreckt. Mit anderen Worten, Sie müssen zuerst nach DeviceIoControl
der Größe der VOLUME_DISK_EXTENTS
Struktur fragen , dann so viel Speicher zuweisen und erst dann mit dem zugewiesenen Puffer erneut aufrufen. Dies funktioniert wie oben gezeigt, da sich die meisten Volumes auf nur einer Festplatte befinden.
VOLUME_DISK_EXTENTS
enthält genügend Speicher für eine Ausdehnung, sodass Sie es so aufrufen können, wie es Grodriguez vorschlägt, und dann nachsehen können, success || ERROR_MORE_DATA == GetLastError()
da wir uns sowieso nur um die erste Ausdehnung kümmern.
Dies könnte 5 Jahre zu spät sein :). Aber da ich noch keine Antwort darauf sehe, füge ich dies hinzu.
Wir können Setup-APIs verwenden , um die Liste der Festplatten abzurufen, dh der Geräte im System, die implementiert werden GUID_DEVINTERFACE_DISK
.
Sobald wir ihre Gerätepfade haben, können wir ausgeben IOCTL_STORAGE_GET_DEVICE_NUMBER
zu konstruieren , "\\.\PHYSICALDRIVE%d"
mitSTORAGE_DEVICE_NUMBER.DeviceNumber
Siehe auch SetupDiGetClassDevs
Funktion
#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;
}
Die Antwort ist viel einfacher als alle oben genannten Antworten. Die Liste der physischen Laufwerke wird tatsächlich in einem Registrierungsschlüssel gespeichert, der auch die Gerätezuordnung enthält.
HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ disk \ Enum
Count ist die Anzahl der PhysicalDrive # und jeder nummerierte Registrierungswert ist das entsprechende physische Laufwerk.
Der Registrierungswert "0" ist beispielsweise PhysicalDrive0. Der Wert ist das tatsächliche Gerät, dem PhysicalDrive0 zugeordnet ist. Der hier enthaltene Wert kann in geben wird CM_Locate_DevNode innerhalb Parameter pDeviceID die Plug - and - Play - Dienste zu nutzen. Auf diese Weise können Sie eine Fülle von Informationen auf dem Gerät sammeln. B. die Eigenschaften des Geräte-Managers wie "Benutzerfreundlicher Anzeigename", wenn Sie einen Namen für das Laufwerk, Seriennummern und mehr benötigen.
Es sind keine WMI-Dienste erforderlich, die möglicherweise nicht auf dem System oder einem anderen Hacker ausgeführt werden. Diese Funktionalität ist in Windows seit mindestens 2000 vorhanden und ist in Windows 10 weiterhin der Fall.
Ich habe ein Open-Source-Programm namens "dskwipe" geändert, um diese Festplatteninformationen daraus zu ziehen. Dskwipe ist in C geschrieben, und Sie können diese Funktion daraus ziehen. Die Binärdatei und die Quelle sind hier verfügbar: dskwipe 0.3 wurde veröffentlicht
Die zurückgegebenen Informationen sehen ungefähr so aus:
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
Der einzig sichere Weg, dies zu tun, ist anzurufen CreateFile()
alle bei \\.\Physicaldiskx
denen x zwischen 0 und 15 liegt (16 ist die maximal zulässige Anzahl von Festplatten). Überprüfen Sie den zurückgegebenen Handle-Wert. Wenn ungültig, GetLastError()
auf ERROR_FILE_NOT_FOUND prüfen . Wenn etwas anderes zurückgegeben wird, ist die Festplatte vorhanden, Sie können jedoch aus irgendeinem Grund nicht darauf zugreifen.
15
? Zählen Sie weiter, bis Sie versagen. Ich bin nicht sicher, ob eine Gerätenummer vom Betriebssystem übersprungen wird.
Die einzig richtige Antwort ist die von @Grodriguez, und hier ist ein Code, den er zu faul war, um ihn zu schreiben:
#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;
}
}
Ich denke, dass die Installation des Windows Driver Development Kit ein ziemlich langwieriger Prozess ist, daher habe ich die Deklarationen beigefügt, die DeviceIoControl
für diese Aufgabe verwendet werden müssen.
DeviceIoControl
falsch an. Sie können nicht davon ausgehen, dass es nur einen Umfang gibt. Sie müssen nach DeviceIoControl
der Größe des benötigten VOLUME_DISK_EXTENTS
Puffers fragen .
DeviceIoControl
im Grunde den Speicher für eine Single auf, VOLUME_DISK_EXTENTS
wie Sie es getan haben, prüfen dann aber, ob sie fehlgeschlagen ist, und prüfen, ob sie zurückgegeben wurde Weisen Sie ERROR_MORE_DATA
in GetLastError
und wenn ja, einen neuen Puffer für die NumberOfDiskExtents
Anzahl der zurückgegebenen DISK_EXTENT
Strukturen zu, rufen Sie ihn DeviceIoControl
erneut auf und stellen Sie sicher, dass er erfolgreich ist. Sie tun dies offensichtlich nicht, wenn der erste Anruf DeviceIoControl
erfolgreich ist.
GetLogicalDrives () listet alle gemounteten Festplattenpartitionen auf, keine physischen Laufwerke.
Sie können die Laufwerksbuchstaben mit (oder ohne) GetLogicalDrives auflisten und dann QueryDosDevice () aufrufen, um herauszufinden, welchem physischen Laufwerk der Buchstabe zugeordnet ist.
Alternativ können Sie die Informationen in der Registrierung unter HKEY_LOCAL_MACHINE \ SYSTEM \ MountedDevices dekodieren. Die dortigen binären Datencodierungen sind jedoch nicht offensichtlich. Wenn Sie eine Kopie von Russinovichs und Solomons Buch Microsoft Windows Internals haben, wird diese Registrierungsstruktur in Kapitel 10 erläutert.
Diese WMIC-Befehlskombination funktioniert einwandfrei:
wmic volume list brief
Vielleicht möchten Sie die alten A: - und B: -Laufwerke einbeziehen, da Sie nie wissen, wer sie möglicherweise verwendet! Ich habe es satt, dass USB-Laufwerke meine beiden SDHC-Laufwerke, die nur für Readyboost bestimmt sind, anstoßen. Ich habe sie hohen Buchstaben Z: Y: mit einem Dienstprogramm zugewiesen, das Geräten Laufwerksbuchstaben nach Ihren Wünschen zuweist. Ich habe mich gefragt ... Kann ich einen Readyboost-Laufwerksbuchstaben A: erstellen? JA! Kann ich meinen zweiten SDHC-Laufwerksbuchstaben als B: eingeben? JA!
Ich habe früher Floppy Drives verwendet und hätte nie gedacht, dass A: oder B: für Readyboost nützlich sein würden.
Mein Punkt ist, nehmen Sie nicht an, dass A: & B: von niemandem für irgendetwas verwendet wird. Vielleicht finden Sie sogar den alten SUBST-Befehl, der verwendet wird!
Ich bin heute in meinem RSS-Reader darauf gestoßen. Ich habe eine sauberere Lösung für Sie. Dieses Beispiel befindet sich in Delphi, kann jedoch sehr einfach in C / C ++ konvertiert werden (es ist alles Win32).
Fragen Sie alle Wertnamen vom folgenden Registrierungsspeicherort ab: HKLM \ SYSTEM \ MountedDevices
Übergeben Sie sie nacheinander an die folgende Funktion, und Sie erhalten den Gerätenamen zurück. Ziemlich sauber und einfach! Ich habe diesen Code in einem Blog hier gefunden.
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;
Wenn Sie "physischen" Zugriff wünschen, entwickeln wir diese API, mit der Sie eventuell mit Speichergeräten kommunizieren können. Es ist Open Source und Sie können den aktuellen Code für einige Informationen sehen. Weitere Funktionen finden Sie unter: https://github.com/virtium/vtStor
Hier ist eine neue Lösung für WMI-Aufrufe.
Dann müssen Sie nur noch anrufen:
queryAndPrintResult(L"SELECT * FROM Win32_DiskDrive", L"Name");
Erstellen Sie eine Liste aller Buchstaben im englischen US-Alphabet und überspringen Sie a & b. "CDEFGHIJKLMNOPQRSTUVWXYZ". Öffnen Sie jedes dieser Laufwerke mit CreateFile
z CreateFile("\\.\C:")
. Wenn es nicht zurückkehrt, haben INVALID_HANDLE_VALUE
Sie ein "gutes" Laufwerk. Nehmen Sie als nächstes dieses Handle und führen Sie es durch DeviceIoControl
, um die Disk # zu erhalten. Siehe meine verwandte Antwort für weitere Details .