Converting a mapped drive letter to a network path using C#

Occasionally you might have the need to convert a mapped drive letter to a UNC or network path. For example, a drive letter such as  “Z” might be mapped to a network share:

image

In this example, the “Z” drive is mapped to a “Personal” folder on a server named “Home”.

If you want to store for example a UNC path to a file rather than a drive letter, you’ll need to convert the “Z” drive to the corresponding UNC root path. Here’s the C# code I wrote to do this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;

namespace WiredPrairie.Samples
{
    public static class Pathing
    {
        [DllImport("mpr.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern int WNetGetConnection(
            [MarshalAs(UnmanagedType.LPTStr)] string localName, 
            [MarshalAs(UnmanagedType.LPTStr)] StringBuilder remoteName, 
            ref int length);
        /// <summary>
        /// Given a path, returns the UNC path or the original. (No exceptions
        /// are raised by this function directly). For example, "P:\2008-02-29"
        /// might return: "\\networkserver\Shares\Photos\2008-02-09"
        /// </summary>
        /// <param name="originalPath">The path to convert to a UNC Path</param>
        /// <returns>A UNC path. If a network drive letter is specified, the
        /// drive letter is converted to a UNC or network path. If the 
        /// originalPath cannot be converted, it is returned unchanged.</returns>
        public static string GetUNCPath(string originalPath)
        {
            StringBuilder sb = new StringBuilder(512);
            int size = sb.Capacity;

            // look for the {LETTER}: combination ...
            if (originalPath.Length > 2 && originalPath[1] == ':')
            {
                // don't use char.IsLetter here - as that can be misleading
                // the only valid drive letters are a-z && A-Z.
                char c = originalPath[0];
                if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
                {
                    int error = WNetGetConnection(originalPath.Substring(0, 2), 
                        sb, ref size);
                    if (error == 0)
                    {                        
                        DirectoryInfo dir = new DirectoryInfo(originalPath);

                        string path = Path.GetFullPath(originalPath)
                            .Substring(Path.GetPathRoot(originalPath).Length);
                        return Path.Combine(sb.ToString().TrimEnd(), path);
                    }
                }
            }
            
            return originalPath;
        }
    }
}

All of the magic takes place in a Windows API function call, WNetGetConnection.

I’m using this function so that I can verify that given two file names, I can be assured that they are pointing to the same physical location. (Is “Z:\Backups\Backup1.zip” the same as “\\home\Personal\Backups\Backup1.zip”).

17 Comments

  1. Actually… there were quite a few problems with the above code. It needed some serious editing just to get it to compile, I’m not sure if it works yet though. I hope I did it right.

  2. This is working only when i run the code through vs 2008,while acessing the page in IE with nt login this is not working.

  3. Sweet, exactly what I was looking for.

    Thanks for posting this it saved a bunch of my time.

    1. While that’s true it would be more correct, on Windows, it’s hard coded in the .NET 4.0 framework to be a “:”. :)

      (And this call wouldn’t make sense on anything but Windows with a mapped drive letter, so portability really isn’t an issue).

Comments are closed.