【问题标题】:Convert from Windows NT device path to drive letter path从 Windows NT 设备路径转换为驱动器号路径
【发布时间】:2018-06-27 11:23:21
【问题描述】:

如何使用来自设备路径的驱动器号解析路径?

例如转换

\Device\HarddiskVolume4\Windows\System32\RuntimeBroker.exe

进入

C:\Windows\System32\RuntimeBroker.exe

假设HarddiskVolume4 映射到这台计算机上的C:

我找到了this question,但我想在 C# 中使用它。

【问题讨论】:

  • 您链接下的所有解决方案都不是最好的。清洁高效的任务解决方案 - 使用 IOCTL_MOUNTMGR_QUERY_POINTS 。但我只能将其粘贴到 c++ 而不能粘贴到 c#
  • 在您的情况下,有一个逻辑驱动器“C:”安装点,但假设您可以使用QueryDosDevice 遍历驱动器号安装点通常是错误的。卷可以安装在文件夹中或只有“卷{GUID}”名称。我认为最简单的解决方案是在路径前加上“\\?\GLOBALROOT”;以最少的访问权限打开文件;并致电GetFinalPathNameByHandle 尝试获取其VOLUME_NAME_DOSVOLUME_NAME_GUID。否则,您需要如上所述通过DeviceIoControl 查询“\\.\MountPointManager”IOCTL_MOUNTMGR_QUERY_POINTS
  • @eryksun 这看起来很有趣。我会调查的!
  • 取决于您需要的驱动器号名称形式。如果您需要拨打CreateFileW - 您可以简单地添加“\\\\?\\GLOBALROOT”前缀。或使用NtOpenFile。但是,如果您需要在 shell api 中使用它 - 正确的方法是通过 IOCTL_MOUNTMGR_QUERY_POINTS 获得 MOUNTMGR_MOUNT_POINT 数组并找到 DeviceName 正是您路径的前缀。并将此前缀替换为SymbolicLinkName 前缀,当它以MOUNTMGR_IS_DRIVE_LETTER 形式出现时

标签: c# windows winapi path drive-letter


【解决方案1】:
string devicePath = @"\Device\HarddiskVolume4\Windows\System32\RuntimeBroker.exe";
string driveLetterPath = DevicePathMapper.FromDevicePath(devicePath);

// driveLetterPath == C:\Windows\System32\RuntimeBroker.exe

由于我们想要一个带有驱动器号的路径,我们需要将\Device\HarddiskVolume4 替换为正确的驱动器号,例如C:。为此使用QueryDosDevice 并将dos 设备映射到每个驱动器号。然后我们就可以搜索替换dos设备路径了。

这是一种可能的实现方式。它使用内部扩展方法:

public static class DevicePathMapper {
    [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)]
    private static extern uint QueryDosDevice([In] string lpDeviceName, [Out] StringBuilder lpTargetPath, [In] int ucchMax);

    public static string FromDevicePath(string devicePath) {
        var drive = Array.Find(DriveInfo.GetDrives(), d => devicePath.StartsWith(d.GetDevicePath(), StringComparison.InvariantCultureIgnoreCase));
        return drive != null ?
            devicePath.ReplaceFirst(drive.GetDevicePath(), drive.GetDriveLetter()) :
            null;
    }

    private static string GetDevicePath(this DriveInfo driveInfo) {
        var devicePathBuilder = new StringBuilder(128);
        return QueryDosDevice(driveInfo.GetDriveLetter(), devicePathBuilder, devicePathBuilder.Capacity + 1) != 0 ?
            devicePathBuilder.ToString() :
            null;
    }

    private static string GetDriveLetter(this DriveInfo driveInfo) {
        return driveInfo.Name.Substring(0, 2);
    }

    private static string ReplaceFirst(this string text, string search, string replace) {
        int pos = text.IndexOf(search);
        if (pos < 0) {
            return text;
        }
        return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-08
    • 2011-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-04
    • 1970-01-01
    相关资源
    最近更新 更多