我如何确定映射驱动器的实际path?

我如何确定映射驱动器的实际path?

所以,如果我有一台名为“Z”的机器上的映射驱动器,我怎样才能确定映射的文件夹的机器和path?

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

我看着Path,Directory,FileInfo对象,但似乎无法find任何东西。

我也寻找现有的问题,但找不到我在找什么。

以下是一些代码示例:

  • 使用P / Invoke

所有的魔法都来自于Windows的function:

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

我扩大了ibram的答案,并创build了这个类(已根据评论反馈更新)。 我可能已经logging了它,但它应该是不言自明的。

 /// <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(), ""); } } 

我不记得我在哪里find这个,但它没有 p / invoke的作品。 这是之前发布的重新运行

您需要引用System.Management.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; } } 

我为此写了一个方法。 它返回一个UNCpath,如果它是一个映射驱动器,否则返回path不变。

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

编辑

即使已经有UNCpath,现在也可以使用Method。 如果给定一个UNCpath,该方法的上述版本将引发exception。

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

我认为你可以使用“networking”键从“当前用户”蜂巢,在registry中。 映射的驱动器在服务器上以共享path列出。

如果系统中没有映射的驱动器,那么在“当前用户”configuration单元中没有“networking”键。

现在,我用这种方式,没有外部的DLL,也没有其他的东西。

我不能复制ibram或vermis的答案,因为我在Vermis的回答下提到的问题,关于types初始化exception。

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

 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.如果遇到上述exception,应该可以使用。

我使用MSDN给出的东西以及ibram或Vermis的答案,但是在MSDN上find具体的例子有点困难。 使用的资源:

MSDN:Win32_LogicalDisk类

MSDN:System.Management命名空间

MSDN:WMI查询示例 :

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

您可以使用WMI来询问您计算机上的Win32_LogicalDrive集合。 这里是一个如何用脚本来做的例子 。 将其改为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 

QueryDosDevice将驱动器号转换为扩展到的path。

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

这是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); 

似乎它需要P / Invoke: 使用C#将映射的驱动器号转换为networkingpath

这家伙build立了一个托pipe类来处理它: C#地图networking驱动器(API)

您也可以使用WMI Win32_LogicalDisk来获取所有您需要的信息。 使用该类中的ProviderName来获取UNCpath。

类似于ibram的答案,只做了一些修改:

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

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