Search code examples
c#windowswinapipathdrive-letter

Convert from Windows NT device path to drive letter path


How can I resolve a path with drive letter from a device path?

For example, convert

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

into

C:\Windows\System32\RuntimeBroker.exe

Assuming HarddiskVolume4 maps to C: on this computer.

I have found this question, but I want to use it in C#.


Solution

  • string devicePath = @"\Device\HarddiskVolume4\Windows\System32\RuntimeBroker.exe";
    string driveLetterPath = DevicePathMapper.FromDevicePath(devicePath);
    
    // driveLetterPath == C:\Windows\System32\RuntimeBroker.exe
    

    Since we want a path with a drive letter we need to replace \Device\HarddiskVolume4 with the correct drive letter, e.g. C:. For that use QueryDosDevice and map a dos device to each drive letter. Then we can search and replace for the dos device path.

    This is a possible implementation. It uses extension methods internal:

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