gpt4 book ai didi

windows - 如何枚举磁盘卷名?

转载 作者:可可西里 更新时间:2023-11-01 13:19:43 25 4
gpt4 key购买 nike

如何枚举磁盘上所有逻辑卷的列表?我想要适合用 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}\ ==> 安装在文件夹中的 CD ROM

我发誓有一个 API 可以枚举卷。

获取逻辑驱动字符串

GetLogicalDriveStrings 的问题功能是它只返回逻辑驱动器:

  • C:\
  • D:\

而不是。就我而言,它遗漏了两卷:

  • 系统保留
  • D:\CDROM

FindFirstVolume 确实正确返回。

将卷转换为驱动器号

  1. 使用 CreateFile
  2. 打开卷 \\?\Volume{0b777019-3313-11e2-8ccd-806e6f6e6963}
  3. 使用IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS控制代码调用DeviceIoControl
  4. 这将返回一系列 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;

红利阅读

最佳答案

你问题的答案隐藏在Naming a Volume里面.使用卷 GUID 路径时,规则略有不同:

All volume and mounted folder functions that take a volume GUID path as an input parameter require the trailing backslash. [...] but this is not the case with the CreateFile function. You can open a volume by calling CreateFile and omit the trailing backslash from the volume name you specify. CreateFile processes a volume GUID path with an appended backslash as the root directory of the volume.

解决方案很简单:从卷 GUID 路径中去除尾部反斜杠以使用 CreateFile 打开卷。

换句话说,虽然音量管理功能如下:

  • 获取音量信息
  • GetVolumePathNamesForVolumeName

确实采用FindFirstVolume/FindNextVolume 返回的完整卷名,CreateFile 要求删除返回的尾部反斜杠:

  • \\?\Volume{0b777018-3313-11e2-8ccd-806e6f6e6963}
  • \\?\Volume{0b777019-3313-11e2-8ccd-806e6f6e6963}
  • \\?\Volume{758a2cf2-cf3a-11e4-8dce-c86000d0b92a}
  • \\?\Volume{4f81d34b-34f4-11e2-9f6e-c86000d0b92a}

关于windows - 如何枚举磁盘卷名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29212597/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com