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

时间:2010-01-14 19:46:39

标签: c# .net windows vb.net

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

因此,如果我在名为“Z”的计算机上有映射驱动器,我如何使用.NET来确定映射文件夹的计算机和路径?

代码可以假设它在带有映射驱动器的机器上运行。

我查看了Path,Directory,FileInfo对象,但似乎找不到任何东西。

我也寻找现有的问题,但找不到我想要的东西。

14 个答案:

答案 0 :(得分:37)

我扩展了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 :(得分:30)

我不记得我在哪里发现了这个,但它的工作原理是没有 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;
   }
}

<强>更新 以管理员显式运行将不会显示映射的驱动器。以下是对此行为的解释: https://stackoverflow.com/a/11268410/448100 (简而言之:管理员具有不同的用户上下文,因此无法访问普通用户的映射驱动器)

答案 2 :(得分:23)

以下是一些代码示例:

所有的魔力都源于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();

答案 3 :(得分:16)

我为此写了一个方法。如果它是映射驱动器,则返回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;
}

答案 4 :(得分:7)

我认为您可以使用“网络”密钥来自“当前用户”Hive,在注册表中。 已映射的驱动器在服务器上列出了它们的共享路径。

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

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

答案 5 :(得分:5)

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

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

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.如果你得到上面提到的异常,它应该可用。

我使用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;
    }
}

答案 6 :(得分:4)

QueryDosDevice将驱动器号转换为它扩展到的路径。

请注意,这将转换所有驱动器号,而不仅仅是那些映射到网络连接的驱动器号。您需要知道哪些是网络路径,或者解析输出以查看哪些是网络。

这是VB签名

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

C#one

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

答案 7 :(得分: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

答案 8 :(得分:2)

似乎需要P / Invoke:Converting a mapped drive letter to a network path using C#

这个人建立了一个托管类来处理它:C# Map Network Drive (API)

答案 9 :(得分:2)

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

答案 10 :(得分: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;
}

答案 11 :(得分:0)

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

答案 12 :(得分:0)

这个post描述了如何获取映射到本地文件夹的驱动器的绝对路径?

  

例如,我有一个“c:\ test”文件夹和一个“x:”驱动器   映射到c:\ test。

     

我正在寻找一个函数,当我传入时会返回“c:\ test”   “X:”

答案是:

  

SUBST使用DefineDosDevice(XP及更高版本)来创建驱动器/路径   映射。您可以使用QueryDosDevice获取SUBSTed的路径   驱动器:

class Location
{
    double lat, lon;
char *em;

    public:
        Location(int =0, int=0, const char* =NULL);
        ~Location();
        Location (const Location&);
        friend ostream& operator<< (ostream&, const Location &);



    protected:

    private:
};

class Adress

{
    char *des;
Location l1;
char *country;
    public:
        Adress(char *,const Location &, char *);
        virtual ~Adress();
        friend ostream& operator<< (ostream&, const Adress &);

    protected:

    private:
};

Adress::Adress(char *des, const Location &l1, char *country)
{
    if (des!=NULL)
    {
        this->des=new char [strlen (des)+1];
        strcpy (this->des, des);
    }
    if (country!=NULL)
    {
        this->country=new char [strlen (country)+1];
        strcpy (this->country, country);
    }

}
Location::Location(int lat, int lon, const char *em)
{
    this->lat=lat;
    this->lon=lon;
    if (em!=NULL)
    {
        this->em=new char [strlen (em)+1];
        strcpy (this->em, em);
    }
}
int main()
{
    Adress ("desc", Location (43.23, 32.12, "south"), "country");
    return 0;
}

答案 13 :(得分:0)

这是一种不在乎是本地还是远程的解决方案

    private string uncpath_check(string path)
    {
        string rval = path;
        string driveprefix = path.Substring(0, 2);
        string unc;

        if (driveprefix != "\\")
        {
            ManagementObject mo = new ManagementObject();
            try
            {
                mo.Path = new ManagementPath(String.Format("Win32_LogicalDisk='{0}'", driveprefix));
                unc = (string)mo["ProviderName"];
                rval = path.Replace(driveprefix, unc);
            }
            catch
            {
                throw;
            }
        }

        if (rval == null)
        { rval = path; }

        return rval;
    }