c# - afficher - obtenir le chemin unc d'un lecteur mappé




Comment puis-je déterminer le chemin réel d'un lecteur mappé? (9)

Comment puis-je déterminer le chemin réel d'un lecteur mappé?

Donc, si j'ai un lecteur mappé sur une machine appelée "Z", comment puis-je utiliser. NET déterminer la machine et le chemin d'accès pour le dossier mappé?

Le code peut supposer qu'il s'exécute sur la machine avec le lecteur mappé.

J'ai regardé les objets Path, Directory, FileInfo, mais je n'arrive pas à trouver quoi que ce soit.

J'ai aussi cherché des questions existantes, mais je n'ai pas trouvé ce que je cherchais.


Ce post décrit comment obtenir le chemin absolu d'un lecteur qui est mappé à un dossier local?

Par exemple, j'ai un dossier "c: \ test" et un lecteur "x:" qui est mappé à c: \ test.

Je cherche une fonction qui retournera "c: \ test" quand je passe dans "x:"

La réponse est:

SUBST utilise DefineDosDevice (XP et versions ultérieures) pour créer le mappage lecteur / chemin. Vous pouvez utiliser le QueryDosDevice pour obtenir le chemin d'accès d'un lecteur 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;

    }

}

En ce qui concerne Windows, il faut appeler WNetGetConnection . Je ne connais pas de frontal pour cela dans .NET, donc vous devrez peut-être l'appeler via P / Invoke (heureusement, il n'a qu'un seul paramètre, le code P / Invoke n'est pas trop horrible).


J'ai développé la réponse de ibram et créé cette classe (qui a été mise à jour par commentaire). Je l'ai probablement plus documenté, mais cela devrait être explicite.

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

Je n'ai pas pu répliquer la ibram's ou de Vermis' raison du problème que j'ai mentionné dans un commentaire sous la réponse de Vermis, à propos d'une exception d'initialisation de type.

Au lieu de cela, j'ai découvert que je pouvais interroger tous les lecteurs actuellement sur l'ordinateur et les boucler, comme ceci:

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

Cela fonctionne pour x64 Windows 7, pour .NET 4. Il devrait être utilisable dans le cas où vous obtenez cette exception qui a été mentionnée ci-dessus.

Je l'ai fait en utilisant les données fournies par MSDN et des bits provenant des ibram's de ibram's ou de Vermis' , même s'il était difficile de trouver des exemples spécifiques sur le MSDN. Ressources utilisées:

MSDN: Classe Win32_LogicalDisk

MSDN: Espace de noms System.Management

MSDN: exemple de requêtes 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;
    }
}

Je pense que vous pouvez utiliser la clé "Réseau" De la ruche "Utilisateur actuel", Dans le registre. Les lecteurs mappés sont répertoriés avec leur chemin d'accès partagé sur le serveur.

S'il n'y a pas de lecteur mappé dans le système, il n'y a pas de clé "Réseau" dans la ruche "Utilisateur actuel".

Maintenant, j'utilise de cette façon, pas de DLL externe ni rien d'autre.



Voici quelques exemples de code:

Toute la magie dérive d'une fonction 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);

Exemple d'invocation

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

Vous pouvez également utiliser WMI Win32_LogicalDisk pour obtenir toutes les informations dont vous avez besoin. utilisez le ProviderName de la classe pour obtenir le chemin UNC.


QueryDosDevice traduit une lettre de lecteur dans le chemin vers lequel il se développe.

Notez que cela traduira TOUTES les lettres de lecteur, pas seulement celles qui sont mappées aux connexions réseau. Vous devez déjà savoir quels sont les chemins réseau ou analyser la sortie pour voir quels sont les réseaux.

Voici la signature VB

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

Et le C # un

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




vb.net