【问题标题】:Delphi - convert physical path (device File handle) to virtual pathDelphi - 将物理路径(设备文件句柄)转换为虚拟路径
【发布时间】:2012-12-04 04:55:19
【问题描述】:

如何转换路径

\Device\HarddiskVolume3\Windows

进入其对应的虚拟路径? (如本例中的 c:\Windows)

【问题讨论】:

    标签: delphi path virtual


    【解决方案1】:

    我个人更喜欢原生方式:

    function GetHDDDevicesWithDOSPath:TStringlist;
    var
      i: integer;
      root: string;
      device: string;
      buffer: string;
    begin
      setlength(buffer, 1000);
      result:=TStringlist.create;
      for i := Ord('c') to Ord('z') do
      begin
        root := Char(i) + ':';
        if (QueryDosDevice(PChar(root), pchar(buffer), 1000) <> 0) then
        begin
          device := pchar(buffer);
          result.add(format('%s = %s\',[device, root ]));
        end;
      end;
    end;
    

    注意:此代码示例取自:http://www.delphipraxis.net/165249-auflistung-devices.html

    这将返回逻辑驱动器和路径之间的映射。就我而言:

    \Device\HarddiskVolume2 = c:\
    \Device\HarddiskVolume3 = d:\
    \Device\IsoCdRom0 = e:\
    \Device\CdRom0 = f:\
    \Device\hgfs\;Z:0000000000084af9\vmware-host\Shared Folders = z:\
    

    您必须将路径中的“\device\harddisk”部分替换为对应的驱动器号。

    请注意,驱动器号取决于用户。 一些有用的链接:

    【讨论】:

    • 对于现代版本的 Delphi,您可以通过返回 TDictionary&lt;string, string&gt; 使结果更有用,这样调用者就不必再进行任何字符串解析来查找所需的条目。
    • 无论如何这都非常快。我稍微修改了代码,使用它来查找进程正在使用的文件的路径,遍历设备路径,直到找到要用于转换的匹配项。在我的测试环境中平均需要 40 微秒(0.04 毫秒)。
    【解决方案2】:

    其中一种方法是使用 WMI,例如 http://www.magsys.co.uk/delphi/magwmi.asp - 它还有一个演示,可用于从中获取代码示例。

    您可以找到许多 WMI Explorer 并探索 configuaartiona 类和构造查询。仅举几例免费的:

    • Microsoft WMI CIM Studio 不擅长查询,但可以很好地查看类
    • 来自 www.ks-soft.net 的 WMI Explorer 变成了我使用最多的浏览器

    您还需要在 Google 上搜索 WMI 查询语言示例并阅读 specifications:虽然 WMI 语言类似于 SQL 查询,但它有一些不同的语法和一组难以预测的非统一限制。


    我个人将它用于不同的方向:我需要制作一个按物理磁盘或网络服务器分组的卷(驱动器号)列表。

    我以(快速且非常难看,但足以在程序初始化时一次性工作)单元结束,如下所示。您可以对其进行流线化处理,但您肯定必须反转请求和函数。

    unit WMI_Helper;
    
    interface
    
    function WMINetDiskName(const disk: string { 'C:' - w/o slash } ): string;
    function WMIPhysDiskName(const disk: string { 'C:' - w/o slash } ): string;
    function WMIGetVolumeName(const disk: string { 'C:' - w/o slash } ): string;
    
    implementation
    
    uses magwmi, SysUtils, StrUtils, Windows, IOUtils;
    
    function WMIGetProp(const query, param, resultProp: string): string;
    begin
      if MagWmiGetOneQ(StringReplace(query, '%s', param, []), resultProp, Result) <= 0
      then
        Result := '';
      Result := Trim(Result);
    end;
    
    function WMINetDiskName(const disk: string { 'C:' - w/o slash } ): string;
    const
      req = 'select ProviderName from Win32_MappedLogicalDisk where DeviceID = "%s"';
      prop = 'ProviderName';
    var
      i: integer;
    begin
      Result := WMIGetProp(req, disk, prop);
    
      If not TPath.IsUNCPath(Result) then
        exit('');
    
      i := PosEx('\', TPath.GetPathRoot(Result), 3);
      if i <= 0 then
        exit('');
    
      SetLength(Result, i - 1);
    end;
    
    function WMIPhysDiskName(const disk: string { 'C:' - w/o slash } ): string;
    const
      resultProp = 'DeviceID';
      reqPart = 'ASSOCIATORS OF {Win32_LogicalDisk.DeviceID="%s"} WHERE ResultClass=Win32_DiskPartition';
      reqDisk = 'ASSOCIATORS OF {Win32_DiskPartition.DeviceID="%s"} WHERE ResultClass=Win32_DiskDrive';
    begin
      Result := WMIGetProp(reqPart, disk, resultProp);
      if Result > '' then
        Result := WMIGetProp(reqDisk, Result, resultProp);
    end;
    
    function WMIGetVolumeName(const disk: string { 'C:' - w/o slash } ): string;
    const
      prop = 'VolumeName';
      reqNet = 'select VolumeName from Win32_MappedLogicalDisk where DeviceID = "%s"';
      reqPhy = 'select VolumeName from Win32_LogicalDisk where DeviceID = "%s"';
    
    begin
      Result := WMIGetProp(IfThen(GetDriveType(PChar(disk)) = DRIVE_REMOTE, reqNet,
        reqPhy), disk, prop);
    end;
    
    end.
    

    我没有尝试过无字母卷(例如 c:\ 和 c:\Windows 将是一个分区,而 c:\Windows\Temp 将驻留在另一个磁盘上),但如果您需要考虑这种情况配置,我相信您可以在 WMI Explorer 中进行适当的查询并将其添加到您的程序中。

    【讨论】:

    • +1 用于解决方案,但(再次)WMI 易于使用、功能强大,但速度很慢。并且不能保证正常工作(存储库损坏、启动缓慢等)。提示:在 windows 服务中使用 WMI 时,请确保您的服务依赖于 WMI 服务
    • WMI 看起来确实很慢,调用 WMIPhysDiskName 大约需要 230 毫秒,而第一个答案中的另一种方法只需 0.1 毫秒即可列出所有设备。
    • 看看引擎盖下。在这段代码中,每个调用都是自包含的:它创建 TCP 连接,然后创建一个 COM 对象树,然后获取单个属性并销毁所有这些。您可以在 Delphi 中搜索 WMI 示例 - 有更复杂的代码,可以在适当的地方重用这些对象。对于我的任务来说,一次查询所有驱动器号就足够了(其中实际上 90% 的机会只有 C: 会存在并且属于 HDD 类型)。但是你可以重复使用对象。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-30
    • 1970-01-01
    • 1970-01-01
    • 2011-10-30
    相关资源
    最近更新 更多