如何列举磁盘上所有逻辑卷的列表?我想要一个用
你尝试过什么?
我使用了
为什么不直接使用
CreateFile
打开的卷名。你尝试过什么?
我使用了
FindFirstVolume
/FindNextVolume
API来列举卷的列表。它返回一系列名称,例如:
\\?\Volume{0b777018-3313-11e2-8ccd-806e6f6e6963}\
\\?\Volume{0b777019-3313-11e2-8ccd-806e6f6e6963}\
\\?\Volume{758a2cf2-cf3a-11e4-8dce-c86000d0b92a}\
\\?\Volume{4f81d34b-34f4-11e2-9f6e-c86000d0b92a}\
CreateFile
来打开卷:0x00000003 (The system cannot find the path specified)
问题可能是如何将FindFirstVolume
返回的对象转换为卷名?
但真正的问题是如何首先枚举卷?
为什么不直接使用\\.\C:
?
我不是在问如何硬编码卷名;我是在问如何枚举卷名。
此外,并非每个卷都有驱动器号,例如:
\\?\Volume{0b777019-3313-11e2-8ccd-806e6f6e6963}\
==>\\.\C:
\\?\Volume{758a2cf2-cf3a-11e4-8dce-c86000d0b92a}\
==>\\.\D:
\\?\Volume{0b777018-3313-11e2-8ccd-806e6f6e6963}\
==> 没有驱动器号的系统保留卷\\?\Volume{4f81d34b-34f4-11e2-9f6e-c86000d0b92a}\
==> 安装在文件夹中的光盘驱动器
我发誓有一个API可以枚举卷。
GetLogicalDriveStrings
GetLogicalDriveStrings函数的问题在于它只返回逻辑驱动器:C:\
D:\
- 系统保留
- D:\CDROM
FindFirstVolume
确实能够正确返回这两个卷。
将卷转换为驱动器编号
- 使用CreateFile打开卷
\\?\Volume{0b777019-3313-11e2-8ccd-806e6f6e6963}
- 使用控制码
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
调用DeviceIoControl - 这将返回一系列
DISK_EXTENT
结构
DISK_EXTENT = record
DiskNumber: DWORD;
StartingOffset: Int64;
ExtentLength: Int64;
end;
您可以从中获取DiskNumber
。
function GetVolumeDiskExtents(VolumeName: string): TArray<DISK_EXTENT>;
var
hVolume: THandle;
vde: PVolumeDiskExtents;
bufferSize: Integer;
bytesReturned: DWORD;
le: DWORD;
begin
SetLength(Result, 0);
{
CreateFile requires the trailing backslash of a volume name removed.
While Volume API functions require the trailing backslash.
}
// VolumeName := ExcludeTrailingBackslash(VolumeName);
bufferSize := SizeOf(vde)+2048*SizeOf(DISK_EXTENT);
GetMem(vde, bufferSize);
try
hVolume := CreateFile(PChar(VolumeName),
GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hVolume = INVALID_HANDLE_VALUE) then
RaiseLastOSError;
try
if not (DeviceIoControl(hVolume, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
nil, 0,
vde, bufferSize,
{var}bytesReturned, nil)) then
begin
le := GetLastError;
if le = ERROR_INVALID_FUNCTION then //ie. CD-ROM
Exit;
raise Exception.CreateFmt('Could not get volume disk extents for volume "%s": %s (0x%s)', [VolumeName, SysErrorMessage(le), IntToHex(le, 8)]);
end;
finally
CloseHandle(hVolume);
end;
SetLength(Result, vde^.NumberOfDiskExtents);
Move(vde^.Extents[0], Result[0], SizeOf(DISK_EXTENT)*vde^.NumberOfDiskExtents);
finally
FreeMem(vde);
end;
end;
C:
->PhysicalDrive0
或Disk 0
(在我的情况下,Disk 0 是 SSD),D:
->PhysicalDrive1
或Disk 1
(在我的情况下,Disk 1 是 HDD)。 - huangPhysicalDisk0
)可以包含多个卷(例如C:
、D:
)。同样,一个卷(例如C:
)也可以存在于多个物理磁盘上(例如PhysicalDisk0
、PhysicalDisk1
),这是因为使用了 RAID 等技术。 - Ian BoydCreateFile
打开卷,然后使用IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
调用DeviceIoControl
句柄。 - huang