代码之家  ›  专栏  ›  技术社区  ›  Eric Schneider

如何确定映射驱动器的实际路径?

  •  43
  • Eric Schneider  · 技术社区  · 16 年前

    如何确定映射驱动器的实际路径?

    所以,如果我在一台名为“z”的机器上有一个映射的驱动器,我如何使用.NET来确定映射文件夹的机器和路径?

    代码可以假定它在带有映射驱动器的机器上运行。

    我查看了路径、目录、fileinfo对象,但似乎找不到任何内容。

    我也查找了现有的问题,但找不到我要查找的内容。

    13 回复  |  直到 7 年前
        1
  •  21
  •   BitSchupser    9 年前

    以下是一些代码示例:

    所有魔法都源于Windows函数:

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

    示例调用:

    var sb = new StringBuilder(512);
    var size = sb.Capacity;
    var error = Mpr.WNetGetConnection("Z:", sb, ref size);
    if (error != 0)
        throw new Win32Exception(error, "WNetGetConnection failed");
     var networkpath = sb.ToString();
    
        2
  •  36
  •   Vermis LordDawnhunter    11 年前

    我扩展了ibram的答案并创建了这个类(每个评论反馈都会更新)。我可能对它做了过多的记录,但应该是不言而喻的。

    /// <summary>
    /// A static class to help with resolving a mapped drive path to a UNC network path.
    /// If a local drive path or a UNC network path are passed in, they will just be returned.
    /// </summary>
    /// <example>
    /// using System;
    /// using System.IO;
    /// using System.Management;    // Reference System.Management.dll
    /// 
    /// // Example/Test paths, these will need to be adjusted to match your environment. 
    /// string[] paths = new string[] {
    ///     @"Z:\ShareName\Sub-Folder",
    ///     @"\\ACME-FILE\ShareName\Sub-Folder",
    ///     @"\\ACME.COM\ShareName\Sub-Folder", // DFS
    ///     @"C:\Temp",
    ///     @"\\localhost\c$\temp",
    ///     @"\\workstation\Temp",
    ///     @"Z:", // Mapped drive pointing to \\workstation\Temp
    ///     @"C:\",
    ///     @"Temp",
    ///     @".\Temp",
    ///     @"..\Temp",
    ///     "",
    ///     "    ",
    ///     null
    /// };
    /// 
    /// foreach (var curPath in paths) {
    ///     try {
    ///         Console.WriteLine(string.Format("{0} = {1}",
    ///             curPath,
    ///             MappedDriveResolver.ResolveToUNC(curPath))
    ///         );
    ///     }
    ///     catch (Exception ex) {
    ///         Console.WriteLine(string.Format("{0} = {1}",
    ///             curPath,
    ///             ex.Message)
    ///         );
    ///     }
    /// }
    /// </example>
    public static class MappedDriveResolver
    {
        /// <summary>
        /// Resolves the given path to a full UNC path if the path is a mapped drive.
        /// Otherwise, just returns the given path.
        /// </summary>
        /// <param name="path">The path to resolve.</param>
        /// <returns></returns>
        public static string ResolveToUNC(string path) {
            if (String.IsNullOrWhiteSpace(path)) {
                throw new ArgumentNullException("The path argument was null or whitespace.");
            }
    
            if (!Path.IsPathRooted(path)) {
                throw new ArgumentException(
                    string.Format("The path '{0}' was not a rooted path and ResolveToUNC does not support relative paths.",
                        path)
                );
            }
    
            // Is the path already in the UNC format?
            if (path.StartsWith(@"\\")) {
                return path;
            }
    
            string rootPath = ResolveToRootUNC(path);
    
            if (path.StartsWith(rootPath)) {
                return path; // Local drive, no resolving occurred
            }
            else {
                return path.Replace(GetDriveLetter(path), rootPath);
            }
        }
    
        /// <summary>
        /// Resolves the given path to a root UNC path if the path is a mapped drive.
        /// Otherwise, just returns the given path.
        /// </summary>
        /// <param name="path">The path to resolve.</param>
        /// <returns></returns>
        public static string ResolveToRootUNC(string path) {
            if (String.IsNullOrWhiteSpace(path)) {
                throw new ArgumentNullException("The path argument was null or whitespace.");
            }
    
            if (!Path.IsPathRooted(path)) {
                throw new ArgumentException(
                    string.Format("The path '{0}' was not a rooted path and ResolveToRootUNC does not support relative paths.",
                    path)
                );
            }
    
            if (path.StartsWith(@"\\")) {
                return Directory.GetDirectoryRoot(path);
            }
    
            // Get just the drive letter for WMI call
            string driveletter = GetDriveLetter(path);
    
            // Query WMI if the drive letter is a network drive, and if so the UNC path for it
            using (ManagementObject mo = new ManagementObject()) {
                mo.Path = new ManagementPath(string.Format("Win32_LogicalDisk='{0}'", driveletter));
    
                DriveType driveType = (DriveType)((uint)mo["DriveType"]);
                string networkRoot = Convert.ToString(mo["ProviderName"]);
    
                if (driveType == DriveType.Network) {
                    return networkRoot;
                }
                else {
                    return driveletter + Path.DirectorySeparatorChar;
                }
            }           
        }
    
        /// <summary>
        /// Checks if the given path is a network drive.
        /// </summary>
        /// <param name="path">The path to check.</param>
        /// <returns></returns>
        public static bool isNetworkDrive(string path) {
            if (String.IsNullOrWhiteSpace(path)) {
                throw new ArgumentNullException("The path argument was null or whitespace.");
            }
    
            if (!Path.IsPathRooted(path)) {
                throw new ArgumentException(
                    string.Format("The path '{0}' was not a rooted path and ResolveToRootUNC does not support relative paths.",
                    path)
                );
            }
    
            if (path.StartsWith(@"\\")) {
                return true;
            }
    
            // Get just the drive letter for WMI call
            string driveletter = GetDriveLetter(path);
    
            // Query WMI if the drive letter is a network drive
            using (ManagementObject mo = new ManagementObject()) {
                mo.Path = new ManagementPath(string.Format("Win32_LogicalDisk='{0}'", driveletter));
                DriveType driveType = (DriveType)((uint)mo["DriveType"]);
                return driveType == DriveType.Network;
            }
        }
    
        /// <summary>
        /// Given a path will extract just the drive letter with volume separator.
        /// </summary>
        /// <param name="path"></param>
        /// <returns>C:</returns>
        public static string GetDriveLetter(string path) {
            if (String.IsNullOrWhiteSpace(path)) {
                throw new ArgumentNullException("The path argument was null or whitespace.");
            }
    
            if (!Path.IsPathRooted(path)) {
                throw new ArgumentException(
                    string.Format("The path '{0}' was not a rooted path and GetDriveLetter does not support relative paths.",
                    path)
                );
            }
    
            if (path.StartsWith(@"\\")) {
                throw new ArgumentException("A UNC path was passed to GetDriveLetter");
            }
    
            return Directory.GetDirectoryRoot(path).Replace(Path.DirectorySeparatorChar.ToString(), "");
        }
    }
    
        3
  •  29
  •   ibram    7 年前

    我不记得在哪儿找到的,但它起作用了 没有 调用/调用。这是什么 再运行 张贴之前。

    你需要参考 system.management.dll(系统管理.dll) :

    using System.IO;
    using System.Management;
    

    代码:

    public void FindUNCPaths()
    {
       DriveInfo[] dis = DriveInfo.GetDrives();
       foreach( DriveInfo di in dis )
       {
          if(di.DriveType == DriveType.Network)
          {
             DirectoryInfo dir = di.RootDirectory;
             // "x:"
             MessageBox.Show( GetUNCPath( dir.FullName.Substring( 0, 2 ) ) );
          }
       }
    }
    
    public string GetUNCPath(string path)
    {
       if(path.StartsWith(@"\\")) 
       {
          return path;
       }
    
       ManagementObject mo = new ManagementObject();
       mo.Path = new ManagementPath( String.Format( "Win32_LogicalDisk='{0}'", path ) );
    
       // DriveType 4 = Network Drive
       if(Convert.ToUInt32(mo["DriveType"]) == 4 )
       {
          return Convert.ToString(mo["ProviderName"]);
       }
       else 
       {
          return path;
       }
    }
    

    更新: 显式运行 作为管理员 不会显示映射的驱动器。以下是对这种行为的解释: https://stackoverflow.com/a/11268410/448100 (简而言之:管理员具有不同的用户上下文,因此无法访问正常用户的映射驱动器)

        4
  •  15
  •   cramopy    9 年前

    我已经为这个写了一个方法。如果是映射驱动器,则返回UNC路径,否则返回未更改的路径。

    public static string UNCPath(string path)
    {
        using (RegistryKey key = Registry.CurrentUser.OpenSubKey("Network\\" + path[0]))
        {
            if (key != null)
            {
                path = key.GetValue("RemotePath").ToString() + path.Remove(0, 2).ToString();
            }
        }
        return path;
    }
    

    编辑

    您现在可以使用这个方法,即使已经有了UNC路径。如果给定UNC路径,上述版本的方法将引发异常。

    public static string UNCPath(string path)
    {
        if (!path.StartsWith(@"\\"))
        {
            using (RegistryKey key = Registry.CurrentUser.OpenSubKey("Network\\" + path[0]))
            {
                if (key != null)
                {
                    return key.GetValue("RemotePath").ToString() + path.Remove(0, 2).ToString();
                }
            }
        }
        return path;
    }
    
        5
  •  7
  •   Farzad Karimi    12 年前

    我认为您可以使用注册表中“当前用户”配置单元中的“网络”键。 映射的驱动器与它们在服务器上的共享路径一起列在那里。

    如果系统中没有映射的驱动器,那么“当前用户”配置单元中就没有“网络”键。

    现在,我使用的是这种方式,没有外部的dll或其他任何东西。

        6
  •  5
  •   Community Mohan Dere    8 年前

    我不能复制 ibram's Vermis' 回答由于我在一个关于类型初始值设定项异常的worms'answer下的注释中提到的问题。

    相反,我发现我可以查询当前计算机上的所有驱动器,然后通过它们进行循环,如下所示:

    using System.IO; //For DirectoryNotFound exception.
    using System.Management;
    
    
    /// <summary>
    /// Given a local mapped drive letter, determine if it is a network drive. If so, return the server share.
    /// </summary>
    /// <param name="mappedDrive"></param>
    /// <returns>The server path that the drive maps to ~ "////XXXXXX//ZZZZ"</returns>
    private string CheckUNCPath(string mappedDrive)
    {
        //Query to return all the local computer's drives.
        //See http://msdn.microsoft.com/en-us/library/ms186146.aspx, or search "WMI Queries"
        SelectQuery selectWMIQuery = new SelectQuery("Win32_LogicalDisk");
        ManagementObjectSearcher driveSearcher = new ManagementObjectSearcher(selectWMIQuery);
    
        //Soem variables to be used inside and out of the foreach.
        ManagementPath path = null;
        ManagementObject networkDrive = null;
        bool found = false;
        string serverName = null;
    
        //Check each disk, determine if it is a network drive, and then return the real server path.
        foreach (ManagementObject disk in driveSearcher.Get())
        {
            path = disk.Path;
    
            if (path.ToString().Contains(mappedDrive))
            {
                networkDrive = new ManagementObject(path);
    
                if (Convert.ToUInt32(networkDrive["DriveType"]) == 4)
                {
                    serverName = Convert.ToString(networkDrive["ProviderName"]);
                    found = true;
                    break;
                }
                else
                {
                    throw new DirectoryNotFoundException("The drive " + mappedDrive + " was found, but is not a network drive. Were your network drives mapped correctly?");
                }
            }
        }
    
        if (!found)
        {
            throw new DirectoryNotFoundException("The drive " + mappedDrive + " was not found. Were your network drives mapped correctly?");
        }
        else
        {
            return serverName;
        }
    }
    

    这适用于x64 Windows 7和.NET 4。它应该是有用的,以防你得到上述的例外情况。

    我用的是来自msdn的东西和来自 伊布兰 Vermis 答案,尽管在msdn上很难找到具体的例子。使用的资源:

    MSDN : Win32_LogicalDisk Class

    MSDN : System.Management namespace

    MSDN : WMI Queries example :

    using System;
    using System.Management;
    class Query_SelectQuery
    {
        public static int Main(string[] args) 
        {
            SelectQuery selectQuery = new 
                SelectQuery("Win32_LogicalDisk");
            ManagementObjectSearcher searcher =
                new ManagementObjectSearcher(selectQuery);
    
            foreach (ManagementObject disk in searcher.Get()) 
            {
                Console.WriteLine(disk.ToString());
            }
    
            Console.ReadLine();
            return 0;
        }
    }
    
        7
  •  4
  •   John Knoeller    16 年前

    QueryDosDevice 将驱动器号转换为它扩展到的路径。

    请注意,这将转换所有驱动器号,而不仅仅是映射到网络连接的驱动器号。您需要知道哪些是网络路径,或者分析输出以查看哪些是网络。

    这是vb签名

    Declare Function QueryDosDevice Lib "kernel32" Alias "QueryDosDeviceA" (
           ByVal lpDeviceName    As String, 
           ByVal lpTargetPath As String, 
           ByVal ucchMax As Integer) As Integer 
    

    和C一

    [DllImport("kernel32.dll")]
    static extern uint QueryDosDevice(string lpDeviceName, IntPtr lpTargetPath, uint ucchMax);
    
        8
  •  4
  •   tehDorf Aran Mulholland    12 年前

    可以使用WMI查询计算机上的win32_LogicalDrive集合。 Here is an example of how to do it with scripting . 在其他地方,把这个改成c是很好的解释。

    文章中略微修改了vb.net代码:

    Public Class Form1
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim strComputer = "."
    
            Dim objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    
            Dim colDrives = objWMIService.ExecQuery("Select * From Win32_LogicalDisk Where DriveType = 4")
    
            For Each objDrive In colDrives
                Debug.WriteLine("Drive letter: " & objDrive.DeviceID)
                Debug.WriteLine("Network path: " & objDrive.ProviderName)
            Next
        End Sub
    
    End Class
    
        9
  •  2
  •   Rubens Farias    16 年前

    似乎需要一个P/Invoke: Converting a mapped drive letter to a network path using C#

    这家伙建立了一个管理类来处理它: C# Map Network Drive (API)

        10
  •  2
  •   rerun    16 年前

    您还可以使用wmi win32_logicaldisk获取所需的所有信息。使用类中的providerName获取UNC路径。

        11
  •  2
  •   Loathing    11 年前

    与伊布拉姆的回答类似,只做了一些修改:

    public static String GetUNCPath(String path) {
        path = path.TrimEnd('\\', '/') + Path.DirectorySeparatorChar;
        DirectoryInfo d = new DirectoryInfo(path);
        String root = d.Root.FullName.TrimEnd('\\');
    
        if (!root.StartsWith(@"\\")) {
            ManagementObject mo = new ManagementObject();
            mo.Path = new ManagementPath(String.Format("Win32_LogicalDisk='{0}'", root));
    
            // DriveType 4 = Network Drive
            if (Convert.ToUInt32(mo["DriveType"]) == 4)
                root = Convert.ToString(mo["ProviderName"]);
            else
                root = @"\\" + System.Net.Dns.GetHostName() + "\\" + root.TrimEnd(':') + "$\\";
        }
    
        return Recombine(root, d);
    }
    
    private static String Recombine(String root, DirectoryInfo d) {
        Stack s = new Stack();
        while (d.Parent != null) {
            s.Push(d.Name);
            d = d.Parent;
        }
    
        while (s.Count > 0) {
            root = Path.Combine(root, (String) s.Pop());
        }
        return root;
    }
    
        12
  •  0
  •   Jerry Coffin    16 年前

    就Windows而言,需要的是调用 WNetGetConnection .我不知道.NET中的前端,所以您可能需要通过P/Invoke来调用它(幸运的是,它只有一个参数,P/Invoke代码并不太糟糕)。

        13
  •  0
  •   Carlos Liu    8 年前

    这个 post 描述如何获取映射到本地文件夹的驱动器的绝对路径?

    例如,我有一个“c:\test”文件夹和一个“x:”驱动器,它是 映射到C:\test。

    我正在寻找一个函数,当我传入时它将返回“c:\test” “X:”

    答案是:

    subst使用definedosdevice(xp和更高版本)创建驱动器/路径 映射。可以使用querydosdevice获取子字符串的路径 驱动器:

    [DllImport("kernel32.dll")]
    
    private    static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, int ucchMax);
    
    static String GetPhysicalPath(String path)
    
    {
    
        if (String.IsNullOrEmpty(path))
    
        {
    
            throw new ArgumentNullException("path");
    
        }
    
        // Get the drive letter
    
        string pathRoot = Path.GetPathRoot(path);
    
        if(String.IsNullOrEmpty(pathRoot))
    
        {
    
            throw new ArgumentNullException("path");
    
        }
    
        string lpDeviceName = pathRoot.Replace("\\", "");
    
    
    
        const String substPrefix = @"\??\";
    
        StringBuilder lpTargetPath = new StringBuilder(260);
    
    
    
        if (0 != QueryDosDevice(lpDeviceName, lpTargetPath, lpTargetPath.Capacity))
    
        {
    
            string result;
    
    
    
            // If drive is substed, the result will be in the format of "\??\C:\RealPath\".
    
            if (lpTargetPath..ToString().StartsWith(substPrefix))
    
            {
    
                // Strip the \??\ prefix.
    
                string root = lpTargetPath.ToString().Remove(0, substPrefix.Length);
    
    
    
                result = Path.Combine(root, path.Replace(Path.GetPathRoot(path), ""));
    
            }
    
            else
    
            {
    
                // TODO: deal with other types of mappings.
    
                // if not SUBSTed, just assume it's not mapped.
    
                result = path;
    
            }
    
            return result;
    
        }
    
        else
    
        {
    
            // TODO: error reporting
    
            return null;
    
        }
    
    }