Come si determina il percorso effettivo di un’unità mappata?

Come si determina il percorso effettivo di un’unità mappata?

Quindi, se ho un drive mappato su una macchina chiamata “Z”, come posso usare .NET per determinare la macchina e il percorso per la cartella mappata?

Il codice può presumere che sia in esecuzione sulla macchina con l’unità mappata.

Ho guardato Path, Directory, oggetti FileInfo, ma non riesco a trovare nulla.

Ho anche cercato domande esistenti, ma non sono riuscito a trovare quello che stavo cercando.

Ecco alcuni esempi di codice:

  • Utilizzando P / Invoke

Tutta la magia deriva da una funzione di 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); 

Invocazione di esempio:

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

Ho ampliato la risposta di ibram e ho creato questa class (che è stata aggiornata per feedback di commento). Probabilmente l’ho già documentato, ma dovrebbe essere auto-esplicativo.

 ///  /// 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. ///  ///  /// 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) /// ); /// } /// } ///  public static class MappedDriveResolver { ///  /// Resolves the given path to a full UNC path if the path is a mapped drive. /// Otherwise, just returns the given path. ///  /// The path to resolve. ///  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); } } ///  /// Resolves the given path to a root UNC path if the path is a mapped drive. /// Otherwise, just returns the given path. ///  /// The path to resolve. ///  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; } } } ///  /// Checks if the given path is a network drive. ///  /// The path to check. ///  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; } } ///  /// Given a path will extract just the drive letter with volume separator. ///  ///  /// C: 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(), ""); } } 

Non riesco a ricordare dove ho trovato questo, ma funziona senza p / invocare. È quello che rerun ha pubblicato prima.

è necessario fare riferimento a System.Management.dll :

 using System.IO; using System.Management; 

codice:

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

Ho scritto un metodo per questo. Restituisce un percorso UNC se si tratta di un’unità mappata, altrimenti restituisce il percorso invariato.

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

MODIFICARE

Ora puoi utilizzare il metodo anche con percorsi UNC già esistenti. La versione precedente del metodo genera un’eccezione se viene fornito un percorso 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; } 

Penso che tu possa usare il tasto “Rete” Dall’hive “Utente corrente”, nel registro. Le unità mappate sono elencate con il loro percorso condiviso sul server.

Se nel sistema non è presente un’unità mappata, non vi è alcuna chiave “Rete” nell’hive “Utente corrente”.

Ora, sto usando in questo modo, nessuna DLL esterna né altro.

Non sono riuscito a replicare la risposta di ibram o Vermis a causa del problema che ho menzionato in un commento sotto la risposta di Vermis, a proposito di un’eccezione di inizializzazione del tipo.

Invece, ho scoperto che potevo eseguire una query per tutte le unità attualmente sul computer e quindi eseguirne il loop, in questo modo:

 using System.IO; //For DirectoryNotFound exception. using System.Management; ///  /// Given a local mapped drive letter, determine if it is a network drive. If so, return the server share. ///  ///  /// The server path that the drive maps to ~ "////XXXXXX//ZZZZ" 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; } } 

Funziona per x64 Windows 7, per .NET 4. Dovrebbe essere utilizzabile nel caso in cui si ottenga quell’eccezione menzionata sopra.

L’ho fatto usando le cose fornite da MSDN e bit dalle risposte di Ibram o Vermis , sebbene fosse un po ‘difficile trovare esempi specifici su MSDN. Risorse utilizzate:

MSDN: class Win32_LogicalDisk

MSDN: spazio dei nomi System.Management

MSDN: esempio di query 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; } } 

QueryDosDevice traduce una lettera di unità nel percorso in cui si espande.

Notare che ciò tradurrà TUTTE le lettere di unità, non solo quelle che sono mappate alle connessioni di rete. È necessario sapere già quali sono i percorsi di rete o analizzare l’output per vedere quali sono di rete.

Ecco la firma VB

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

E il C #

 [DllImport("kernel32.dll")] static extern uint QueryDosDevice(string lpDeviceName, IntPtr lpTargetPath, uint ucchMax); 

È ansible utilizzare WMI per interrogare la raccolta Win32_LogicalDrive sul proprio computer. Ecco un esempio di come farlo con lo scripting . Cambiare questo aspetto in C # è abbastanza ben spiegato in altri posti.

Codice VB.NET leggermente modificato dall’articolo:

 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 

Sembra che sia necessario un P / Invoke: convertire una lettera di unità mappata in un percorso di rete usando C #

Questo ragazzo ha creato una class gestita per affrontarla: C # Map Network Drive (API)

È inoltre ansible utilizzare WMI Win32_LogicalDisk per ottenere tutte le informazioni necessarie. utilizzare il ProviderName dalla class per ottenere il percorso UNC.

Simile alla risposta di ibram con alcune modifiche:

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

Per quanto riguarda Windows, è necessaria una chiamata a WNetGetConnection . Non conosco un front-end per questo in .NET, quindi potresti doverlo chiamare tramite P / Invoke (fortunatamente, ha solo un parametro, il codice P / Invoke non è troppo terribile).

Questo post descrive come ottenere il percorso assoluto di un’unità che viene mappata su una cartella locale?

Ad esempio, ho una cartella “c: \ test” e un’unità “x:” che è mappata a c: \ test.

Sto cercando una funzione che restituirà “c: \ test” quando passo “x:”

La risposta è:

SUBST utilizza DefineDosDevice (XP e versioni successive) per creare il mapping di unità / percorso. È ansible utilizzare QueryDosDevice per ottenere il percorso di un’unità SUBSTed:

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