2010-01-14 78 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; 
}