【问题标题】:How to get physical disk number by drive letter using Delphi如何使用Delphi通过驱动器号获取物理磁盘号
【发布时间】:2015-01-13 23:17:32
【问题描述】:

对不起,我对这个主题一无所知,所以请你帮忙。我在谷歌上找到了下面的代码,通过驱动器号获取物理磁盘号,尽管它有效,但大约需要 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                     = $00000007;
  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;

【问题讨论】:

  • 试试FILE_SHARE_READ or FILE_SHARE_WRITE
  • @SertacAkyuz 在哪里通过?创建文件?两者兼而有之?
  • @Jerry “100% 更快”意味着始终“双倍性能”或从 100mph 到 200mph 或 4 秒内 1 个信息到 2 秒内 1 个信息 ...
  • 天啊,你们需要治疗...我刚刚订阅了这里,尽我所能...如果没有人回答会怎样?我只是想为那些来找它的人留下正确的“答案”......
  • @SertacAkyuz,结果立竿见影!谢谢!

标签: delphi hardware disk


【解决方案1】:

Documentation for CreateFile 状态:

• 打开卷或软盘时,dwShareMode 参数必须具有 FILE_SHARE_WRITE 标志。

您使用的代码缺少标志。该代码还具有一个特殊的特性,即它不会通知失败。当CreateFile 失败时,您的GetPhysicalDiskNumber 返回'0',表明结果是第一个磁盘。

这就是我认为正在发生的事情:您正在测试一个系统无法锁定写访问的卷,并且在尝试这样做时超时(因此延迟)。但是你的函数仍然返回'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;

不过,您可以选择静默失败。在这种情况下,您可以最初将GetPhysicalDiskNumberResult 设置为'-1',然后继续为CreateFileDeviceIoControl 引发异常。

代码也无法释放它分配的内存,这是一个泄漏:

  ...
  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);
  ...

【讨论】:

  • 知道物理盘号就可以找到所有盘符?
  • @Marus - 你可能想看看this question
猜你喜欢
  • 1970-01-01
  • 2018-05-15
  • 1970-01-01
  • 2017-02-22
  • 2022-11-01
  • 2014-07-25
  • 1970-01-01
  • 2012-04-11
  • 2014-10-04
相关资源
最近更新 更多