Làm thế nào để liệt kê các đĩa vật lý trong Windows? Để có được một danh sách "\\\\.\PhysicalDrive0"
có sẵn.
Câu trả lời:
wmic là một công cụ rất hoàn chỉnh
wmic diskdrive list
cung cấp một danh sách chi tiết (quá nhiều), chẳng hạn
để biết ít thông tin hơn
wmic diskdrive list brief
Sebastian Godelet đề cập trong các bình luận :
Trong C:
system("wmic diskdrive list");
Như đã nhận xét, bạn cũng có thể gọi WinAPI, nhưng ... như được hiển thị trong " Cách lấy dữ liệu từ WMI bằng ứng dụng C? ", Điều này khá phức tạp (và thường được thực hiện với C ++, không phải C).
Hoặc với PowerShell:
Get-WmiObject Win32_DiskDrive
system("wmic diskdrive list");
trong C
Một cách để làm điều đó:
Liệt kê các ổ đĩa logic bằng cách sử dụng GetLogicalDrives
Đối với mỗi ổ đĩa logic, hãy mở một tệp có tên "\\.\X:"
(không có dấu ngoặc kép) trong đó X là ký tự ổ đĩa logic.
Lệnh gọi DeviceIoControl
chuyển xử lý tới tệp đã mở ở bước trước và dwIoControlCode
tham số được đặt thành 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);
Điều này trả về thông tin về vị trí thực của một khối logic, như một VOLUME_DISK_EXTENTS
cấu trúc.
Trong trường hợp đơn giản khi ổ đĩa nằm trên một ổ đĩa vật lý, số ổ đĩa vật lý có sẵn trong diskExtents.Extents[0].DiskNumber
DeviceIoControl(IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS)
cuộc gọi được đề xuất của anh ấy sẽ không thành công nếu một ổ đĩa trải dài trên nhiều đĩa. Nói cách khác, trước tiên bạn cần hỏi DeviceIoControl
kích thước của VOLUME_DISK_EXTENTS
struct, sau đó cấp phát lượng bộ nhớ đó, và chỉ sau đó gọi lại nó bằng bộ đệm được cấp phát. Nó hoạt động theo cách được hiển thị ở trên vì hầu hết các ổ đĩa chỉ nằm trên một đĩa.
VOLUME_DISK_EXTENTS
có đủ bộ nhớ cho một phạm vi, vì vậy bạn có thể gọi nó như Grodriguez đề xuất và sau đó kiểm tra success || ERROR_MORE_DATA == GetLastError()
vì dù sao chúng tôi cũng chỉ quan tâm đến phạm vi đầu tiên.
Điều này có thể là quá muộn 5 năm :). Nhưng khi tôi thấy chưa có câu trả lời cho điều này, thêm điều này.
Chúng ta có thể sử dụng các API thiết lập để lấy danh sách các ổ đĩa tức là các thiết bị trong hệ thống đang triển khai GUID_DEVINTERFACE_DISK
.
Sau khi chúng tôi có đường dẫn thiết bị của họ, chúng tôi có thể phát IOCTL_STORAGE_GET_DEVICE_NUMBER
triển "\\.\PHYSICALDRIVE%d"
vớiSTORAGE_DEVICE_NUMBER.DeviceNumber
Xem thêm SetupDiGetClassDevs
chức năng
#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;
}
Câu trả lời đơn giản hơn nhiều so với tất cả các câu trả lời trên. Danh sách ổ đĩa vật lý thực sự được lưu trữ trong khóa Registry, khóa này cũng cung cấp cho ánh xạ thiết bị.
HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ disk \ Enum
Đếm là số PhysicalDrive # và mỗi Giá trị đăng ký được đánh số là ổ vật lý tương ứng.
Ví dụ: Giá trị sổ đăng ký "0" là PhysicalDrive0. Giá trị là thiết bị thực tế PhysicalDrive0 được ánh xạ tới. Giá trị chứa ở đây có thể được chuyển vào CM_Locate_DevNode trong tham số pDeviceID để sử dụng các dịch vụ plug and play. Điều này sẽ cho phép bạn thu thập nhiều thông tin trên thiết bị. Chẳng hạn như các thuộc tính từ Trình quản lý thiết bị như "Tên hiển thị thân thiện" nếu bạn cần tên cho ổ đĩa, số sê-ri và hơn thế nữa.
Không cần các dịch vụ WMI có thể không chạy trên hệ thống hoặc các phương thức hack khác và chức năng này đã có mặt trong Windows ít nhất từ năm 2000 và tiếp tục là trường hợp của Windows 10.
Tôi đã sửa đổi một chương trình mã nguồn mở có tên "dskwipe" để lấy thông tin đĩa này ra khỏi nó. Dskwipe được viết bằng C, và bạn có thể lấy chức năng này ra khỏi nó. Mã nhị phân và mã nguồn có sẵn tại đây: dskwipe 0.3 đã được phát hành
Thông tin trả về sẽ giống như sau:
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
Câu trả lời đúng duy nhất là câu trả lời của @Grodriguez và đây là đoạn mã mà anh ấy quá lười biếng để viết:
#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;
}
}
Tôi nghĩ rằng việc cài đặt Bộ phát triển trình điều khiển Windows là một quá trình khá dài, vì vậy tôi đã bao gồm các khai báo mà một người cần sử dụng DeviceIoControl
cho tác vụ này.
DeviceIoControl
không chính xác. Bạn không thể cho rằng chỉ có một mức độ. Bạn cần hỏi DeviceIoControl
kích thước của VOLUME_DISK_EXTENTS
bộ đệm cần thiết .
DeviceIoControl
bộ nhớ cho một bộ nhớ VOLUME_DISK_EXTENTS
như bạn đã làm nhưng sau đó kiểm tra xem nó có bị lỗi không và nếu có, hãy xem nó có trả về không ERROR_MORE_DATA
trong GetLastError
và nếu như vậy, bố trí một bộ đệm mới cho NumberOfDiskExtents
số DISK_EXTENT
cấu trúc (mà nó trả lại) và gọi DeviceIoControl
một lần nữa và chắc chắn rằng nó thành công. Bạn rõ ràng không làm tất cả những điều này nếu cuộc gọi đầu tiên DeviceIoControl
thành công.
Cách chắc chắn duy nhất để làm điều này là gọi CreateFile()
trên tất cả các \\.\Physicaldiskx
vị trí x từ 0 đến 15 (16 là số đĩa tối đa được phép). Kiểm tra giá trị xử lý được trả về. Nếu kiểm tra không hợp lệ GetLastError()
cho ERROR_FILE_NOT_FOUND . Nếu nó trả về bất kỳ thứ gì khác thì đĩa tồn tại nhưng bạn không thể truy cập vì lý do nào đó.
15
? Tiếp tục liệt kê cho đến khi bạn thất bại. Tôi không chắc liệu một số số thiết bị có bị hệ điều hành bỏ qua hay không.
GetLogicalDrives () liệt kê tất cả các phân vùng đĩa được gắn kết, không phải ổ đĩa vật lý.
Bạn có thể liệt kê các ký tự ổ đĩa có (hoặc không có) GetLogicalDrives, sau đó gọi QueryDosDevice () để tìm ra ổ đĩa vật lý mà ký tự được ánh xạ tới.
Ngoài ra, bạn có thể giải mã thông tin trong sổ đăng ký tại HKEY_LOCAL_MACHINE \ SYSTEM \ MountedDevices. Tuy nhiên, các mã hóa dữ liệu nhị phân ở đó không rõ ràng. Nếu bạn có một bản sao cuốn sách Microsoft Windows Internals của Russinovich và Solomon, tổ hợp đăng ký này sẽ được thảo luận trong Chương 10.
Thic tổ hợp lệnh WMIC hoạt động tốt:
wmic volume list brief
Có thể muốn bao gồm các ổ đĩa A: và B: cũ mà bạn không bao giờ biết ai có thể đang sử dụng chúng! Tôi cảm thấy mệt mỏi với việc ổ USB va chạm với hai ổ SDHC chỉ dành cho Readyboost. Tôi đã gán chúng cho các chữ cái Cao Z: Y: với một tiện ích sẽ gán các ký tự ổ đĩa cho các thiết bị như bạn muốn. Tôi tự hỏi .... Tôi có thể tạo ổ đĩa Readyboost ký tự A:? ĐÚNG! Tôi có thể đặt ký tự ổ đĩa SDHC thứ hai của mình là B :? ĐÚNG!
Tôi đã sử dụng Ổ đĩa mềm ngày trước, chưa bao giờ nghĩ rằng A: hoặc B: sẽ có ích cho Readyboost.
Quan điểm của tôi là, đừng cho rằng A: & B: sẽ không được sử dụng bởi bất kỳ ai cho bất cứ điều gì Bạn thậm chí có thể thấy lệnh SUBST cũ đang được sử dụng!
Tôi vừa xem qua điều này trong RSS Reader của tôi hôm nay. Tôi có một giải pháp sạch hơn cho bạn. Ví dụ này là trong Delphi, nhưng rất có thể dễ dàng chuyển đổi sang C / C ++ (Tất cả đều là Win32).
Truy vấn tất cả các tên giá trị từ vị trí đăng ký sau: HKLM \ SYSTEM \ MountedDevices
Từng cái một, chuyển chúng vào hàm sau và bạn sẽ được trả về tên thiết bị. Khá sạch sẽ và đơn giản! Tôi tìm thấy mã này trên một blog ở đây.
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;
Nếu bạn muốn có quyền truy cập "vật lý", chúng tôi đang phát triển API này, API này cuối cùng sẽ cho phép bạn giao tiếp với các thiết bị lưu trữ. Đó là mã nguồn mở và bạn có thể xem mã hiện tại để biết một số thông tin. Kiểm tra lại để biết thêm các tính năng: https://github.com/virtium/vtStor
Đây là mộtgiải pháp mới để thực hiện nó với việc thực hiện các cuộc gọi WMI.
Sau đó, tất cả những gì bạn cần làm chỉ là gọi:
queryAndPrintResult(L"SELECT * FROM Win32_DiskDrive", L"Name");
Nếu bạn chỉ cần nhìn vào các đĩa hiện có, cái này sẽ đủ:
powershell "get-physicaldisk"
Lập danh sách tất cả các chữ cái trong Bảng chữ cái tiếng Anh Hoa Kỳ, bỏ qua a & b. "CDEFGHIJKLMNOPQRSTUVWXYZ". Mở từng ổ đĩa đó bằng CreateFile
vd CreateFile("\\.\C:")
. Nếu nó không trở lại INVALID_HANDLE_VALUE
thì bạn đã có một ổ đĩa 'tốt'. Tiếp theo, lấy tay cầm đó và chạy nó DeviceIoControl
để lấy Disk #. Xem câu trả lời liên quan của tôi để biết thêm chi tiết .