如何使用 Delphi 通过驱动器号获取物理磁盘号
How to get physical disk number by drive letter using Delphi
对不起,我对这个问题一无所知,所以请求你的帮助。我在下面 Google 上找到这段代码,通过驱动器号获取物理磁盘号,尽管它有效,但需要大约 4 或 5 秒才能得到结果。我想知道是否有更快的方法以及如何做?谢谢!
function GetPhysicalDiskNumber(Drive: Char): Byte;
function GetLD(Drive: Char): Cardinal;
var
Buffer : String;
begin
Buffer := Format('\.\%s:',[Drive]);
Result := CreateFile(PChar(Buffer),GENERIC_READ Or GENERIC_WRITE,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0);
If Result = INVALID_HANDLE_VALUE Then
begin
Result := CreateFile(PChar(Buffer),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0);
end;
end;
type
PDiskInfo = ^TDiskInfo;
TDiskInfo = record
BootStatus,
StartHead : Byte;
StartSecClu : Array[0..1] Of Byte;
ParitionType,
LastHead : Byte;
LastSecClu : Array[0..1] Of Byte;
ABSSector,
TTLSector : Integer;
Reserved : Array[0..47] Of Byte;
Signature : Array[0..1] Of Byte;
end;
TDiskExtent = record
DiskNumber: Cardinal;
StartingOffset: Int64;
ExtentLength: Int64;
end;
DISK_EXTENT = TDiskExtent;
PDiskExtent = ^TDiskExtent;
TVolumeDiskExtents = record
NumberOfDiskExtents: Cardinal;
Extents: array[0..0] of TDiskExtent;
end;
VOLUME_DISK_EXTENTS = TVolumeDiskExtents;
PVolumeDiskExtents = ^TVolumeDiskExtents;
const
FILE_DEVICE_DISK = [=11=]000007;
METHOD_BUFFERED = 0;
FILE_ANY_ACCESS = 0;
IOCTL_DISK_BASE = FILE_DEVICE_DISK;
IOCTL_VOLUME_BASE = DWORD('V');
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS = ((IOCTL_VOLUME_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or (0 shl 2) or METHOD_BUFFERED);
var
LD : DWORD;
DiskExtents : PVolumeDiskExtents;
DiskExtent : TDiskExtent;
BytesReturned : Cardinal;
begin
Result := 0;
LD := GetLD(Drive);
If LD = INVALID_HANDLE_VALUE Then Exit;
Try
DiskExtents := AllocMem(Max_Path);
DeviceIOControl(LD,IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,nil,0,DiskExtents,Max_Path,BytesReturned,nil);
If DiskExtents^.NumberOfDiskExtents > 0 Then
begin
DiskExtent := DiskExtents^.Extents[0];
Result := DiskExtent.DiskNumber;
end;
Finally
CloseHandle(LD);
end;
end;
Documentation for CreateFile
状态:
• When opening a volume or floppy disk, the dwShareMode parameter must have the FILE_SHARE_WRITE flag.
您使用的代码缺少标志。该代码还有一个特殊的特性,即它不会通知失败。当CreateFile
失败时,你的GetPhysicalDiskNumber
returns'0',提示结果是第一盘。
这就是我认为正在发生的事情:您正在测试一个系统无法锁定写入访问的卷,并且在尝试这样做时超时(因此延迟)。但是你的函数还是returns'0',所以你认为它在工作。
无论如何,你需要旗帜。此外,我会在 CreateFile
失败时引发异常,以便您了解发生了什么。
function GetLD(Drive: Char): Cardinal;
var
Buffer : String;
begin
Buffer := Format('\.\%s:',[Drive]);
Result := CreateFile(PChar(Buffer), GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
Win32Check(Result <> INVALID_HANDLE_VALUE);
end;
不过您可以选择静默失败。在这种情况下,您可以最初将 GetPhysicalDiskNumber
的 Result
设置为 '-1',然后继续为 CreateFile
和 DeviceIoControl
.
引发异常
代码也无法释放它分配的内存,这是一个泄漏:
...
try
DiskExtents := AllocMem(Max_Path);
try
Win32Check(DeviceIOControl(LD, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, nil, 0,
DiskExtents, Max_Path, BytesReturned, nil));
if DiskExtents^.NumberOfDiskExtents > 0 then
begin
DiskExtent := DiskExtents^.Extents[0];
Result := DiskExtent.DiskNumber;
end;
finally
FreeMem(DiskExtents);
end;
finally
CloseHandle(LD);
...
对不起,我对这个问题一无所知,所以请求你的帮助。我在下面 Google 上找到这段代码,通过驱动器号获取物理磁盘号,尽管它有效,但需要大约 4 或 5 秒才能得到结果。我想知道是否有更快的方法以及如何做?谢谢!
function GetPhysicalDiskNumber(Drive: Char): Byte;
function GetLD(Drive: Char): Cardinal;
var
Buffer : String;
begin
Buffer := Format('\.\%s:',[Drive]);
Result := CreateFile(PChar(Buffer),GENERIC_READ Or GENERIC_WRITE,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0);
If Result = INVALID_HANDLE_VALUE Then
begin
Result := CreateFile(PChar(Buffer),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0);
end;
end;
type
PDiskInfo = ^TDiskInfo;
TDiskInfo = record
BootStatus,
StartHead : Byte;
StartSecClu : Array[0..1] Of Byte;
ParitionType,
LastHead : Byte;
LastSecClu : Array[0..1] Of Byte;
ABSSector,
TTLSector : Integer;
Reserved : Array[0..47] Of Byte;
Signature : Array[0..1] Of Byte;
end;
TDiskExtent = record
DiskNumber: Cardinal;
StartingOffset: Int64;
ExtentLength: Int64;
end;
DISK_EXTENT = TDiskExtent;
PDiskExtent = ^TDiskExtent;
TVolumeDiskExtents = record
NumberOfDiskExtents: Cardinal;
Extents: array[0..0] of TDiskExtent;
end;
VOLUME_DISK_EXTENTS = TVolumeDiskExtents;
PVolumeDiskExtents = ^TVolumeDiskExtents;
const
FILE_DEVICE_DISK = [=11=]000007;
METHOD_BUFFERED = 0;
FILE_ANY_ACCESS = 0;
IOCTL_DISK_BASE = FILE_DEVICE_DISK;
IOCTL_VOLUME_BASE = DWORD('V');
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS = ((IOCTL_VOLUME_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or (0 shl 2) or METHOD_BUFFERED);
var
LD : DWORD;
DiskExtents : PVolumeDiskExtents;
DiskExtent : TDiskExtent;
BytesReturned : Cardinal;
begin
Result := 0;
LD := GetLD(Drive);
If LD = INVALID_HANDLE_VALUE Then Exit;
Try
DiskExtents := AllocMem(Max_Path);
DeviceIOControl(LD,IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,nil,0,DiskExtents,Max_Path,BytesReturned,nil);
If DiskExtents^.NumberOfDiskExtents > 0 Then
begin
DiskExtent := DiskExtents^.Extents[0];
Result := DiskExtent.DiskNumber;
end;
Finally
CloseHandle(LD);
end;
end;
Documentation for CreateFile
状态:
• When opening a volume or floppy disk, the dwShareMode parameter must have the FILE_SHARE_WRITE flag.
您使用的代码缺少标志。该代码还有一个特殊的特性,即它不会通知失败。当CreateFile
失败时,你的GetPhysicalDiskNumber
returns'0',提示结果是第一盘。
这就是我认为正在发生的事情:您正在测试一个系统无法锁定写入访问的卷,并且在尝试这样做时超时(因此延迟)。但是你的函数还是returns'0',所以你认为它在工作。
无论如何,你需要旗帜。此外,我会在 CreateFile
失败时引发异常,以便您了解发生了什么。
function GetLD(Drive: Char): Cardinal;
var
Buffer : String;
begin
Buffer := Format('\.\%s:',[Drive]);
Result := CreateFile(PChar(Buffer), GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
Win32Check(Result <> INVALID_HANDLE_VALUE);
end;
不过您可以选择静默失败。在这种情况下,您可以最初将 GetPhysicalDiskNumber
的 Result
设置为 '-1',然后继续为 CreateFile
和 DeviceIoControl
.
代码也无法释放它分配的内存,这是一个泄漏:
...
try
DiskExtents := AllocMem(Max_Path);
try
Win32Check(DeviceIOControl(LD, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, nil, 0,
DiskExtents, Max_Path, BytesReturned, nil));
if DiskExtents^.NumberOfDiskExtents > 0 then
begin
DiskExtent := DiskExtents^.Extents[0];
Result := DiskExtent.DiskNumber;
end;
finally
FreeMem(DiskExtents);
end;
finally
CloseHandle(LD);
...