2010-01-14 89 views
35

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

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

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

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

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

+1

退房@尼克的答案是不使用的PInvoke或任何特殊文库的方法。 – tehDorf 2013-06-05 15:39:04

回答

17

这里有一些代码示例:

所有的魔法从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(); 
+0

我已经确认链接工程的C#代码。我宁愿有一个非dll的导入版本,但总比没有好。 – eschneider 2010-01-15 21:40:13

+3

而不是只提供一个链接,你可以请你提供一些在你的实际答案的情况下,以防链接变得不可用吗?谢谢。 – Deanna 2013-03-13 16:42:03

+2

如果链接有一天无效,你需要知道的主要事情是它使用WNetGetConnection(你可以在MSDN上找到它)。 – eselk 2013-09-04 19:19:43

3

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); 
+0

我无法得到这个工作,也看起来它不会给文件夹,映射的驱动程序是一个服务器和一个文件夹... – eschneider 2010-01-15 21:37:21

+0

如果你的意思是你想知道该路径,因为它显示在服务器上,那么你将需要问服务器。该信息对客户不可用。 – 2010-01-15 21:39:37

+0

如果驱动器映射到机器上,代码正在运行,那么它应该工作。 – eschneider 2010-01-15 21:46:53

0

至于视窗关心,有什么需要的是WNetGetConnection通话。我不知道.NET的前端,所以你可能不得不通过P/Invoke来调用它(幸运的是,它只有一个参数,P/Invoke代码不太可怕)。

2

您还可以使用WMI Win32_LogicalDisk获取所需的所有信息。使用该类中的ProviderName来获取UNC路径。

4

您可以使用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 
+0

无需使用任何特殊库,即可获取每个映射驱动器的网络共享的简单方法。这可以在VS Express 2012桌面Windows窗体应用程序中直接使用。 – tehDorf 2013-06-05 15:32:57

24

我不记得在那里我发现这一点,但它的工作原理没有的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; 
    } 
} 
+0

这对我的需求非常合适,似乎是最简单的解决方案。我很惊讶我没有在其他地方看到这个。 – JimDel 2012-01-11 01:17:13

+0

当path =“C:\\”'未找到'ManagementException'时,在Windows 8上失败。 – Loathing 2014-11-30 07:06:23

+0

@Loathing您是否找到'ManagementException'的解决方案?我也遇到了这个错误。谢谢。 – 2015-02-24 20:12:12

35

我扩大对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(), ""); 
    } 
} 
+1

整整一小段代码+1 – deltree 2012-03-20 23:26:25

+1

'Convert.ToUInt32(mo [“DriveType”])'会导致* System.Management.ManagementPath的类型初始值设定项引发异常*,您知道这个代码是否可以在Windows7上运行或者它可以是组策略吗? – 2013-06-04 05:52:38

+1

@JeremyThompson这个异常(我也得到)的InnerException是[System.Threading.ThreadAbortException] {“异常的类型'System.Threading.ThreadAbortException'被抛出。”}。我不知道这个原因,但我仍然在寻找解决方案。我正在运行Win7 x64。 – Hydronium 2013-07-10 20:14:43

7

我想你可以使用“网络”键从“当前用户”配置单元,在注册表中。 已映射的驱动器在服务器上以共享路径列出。

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

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

5

我无法复制ibram'sVermis'答案由于我在Vermis的回答下提到的问题,关于类型初始值设定项异常。

相反,我发现我能为所有驱动器当前查询的电脑上,然后通过他们循环,就像这样:

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

这适用于64位的Windows 7,对于.NET 4.应当如果你得到上面提到的那个例外情况,可以使用它。

我用MSDN提供的东西以及ibram'sVermis'回答的位来做这件事,尽管在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; 
    } 
} 
10

我写了一个方法这一点。如果它是一个映射的驱动器,它将返回一个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; 
} 
+2

我发现这个功能非常好。整洁,简短。 – JustBaron 2016-05-18 09:34:37

+0

注册表中是否有其他路径来查找此值?因为我发现只有一个(请参见截图):[链接](http://imgur.com/AxA9FJN) – kamp 2016-06-15 10:19:06

+1

它看起来最简单的解决方案,适用于早期的.Net框架(如2.0),其中没有“System.Management “名称空间,它没有额外的库。它只需要命名空间使用“Microsoft.Win32”。 – 2017-06-08 16:03:02

2

到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; 
} 
相关问题