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

时间:2021-12-08 13:59:17

How do I determine a mapped drive's actual path?

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

So if I have a mapped drive on a machine called "Z" how can I using .NET determine the machine and path for the mapped folder?

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

The code can assume it's running on the machine with the mapped drive.

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

I looked at Path, Directory, FileInfo objects, but can't seem to find anything.

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

I also looked for existing questions, but could not find what I'm looking for.

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

13 个解决方案

#1


18  

Here are some code samples:

以下是一些代码示例:

All of the magic derives from a Windows function:

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

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

#2


36  

I expanded on ibram's answer and created this class (which has been updated per comment feedback). I've probably over documented it, but it should be self-explanatory.

我扩展了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(), "");
    }
}

#3


26  

I can't remember where I found this, but it works without p/invoke. It's what rerun posted before.

我不记得我在哪里发现了这个,但它没有p / invoke就能工作。这是重新运行之前发布的内容。

you need to reference System.Management.dll:

你需要引用System.Management.dll:

using System.IO;
using System.Management;

code:

码:

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

#4


11  

I've written a method for this. It returns a UNC path if it is a mapped drive, otherwise it returns the path unchanged.

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

EDIT

编辑

You now can use the Method even with already UNC paths. The above version of the method throws an exception if given a UNC 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;
}

#5


7  

I think you can use the "Network" key From the "Current User" Hive, In the Registry. The Mapped Drives Are Listed There With Their Shared Path On Server.

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

If there is no mapped drive in the system, so there is no "Network" Key In The "Current User" Hive.

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

Now, I'm using this way, no external dll nor anything else.

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

#6


5  

I could not replicate ibram's or Vermis' answer due to the problem I mentioned in a comment under Vermis' answer, about a type initializer exception.

我无法复制ibram或Vermis的答案,因为我在Vermis回答的评论中提到的问题,关于类型初始化程序异常。

Instead, I discovered I could query for all the drives currently on the computer and then loop through them, like so:

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

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

This works for x64 Windows 7, for .NET 4. It should be usable in case you're getting that exception that was mentioned above.

这适用于x64 Windows 7,适用于.NET 4.如果您收到上面提到的异常,它应该可用。

I did this using the stuff given from MSDN and bits from ibram's or Vermis' answers, though it was a bit difficult to find specific examples on the MSDN. Resources used:

我使用MSDN提供的东西和ibram或Vermis的答案中的位来做到这一点,尽管在MSDN上找到具体的例子有点困难。使用的资源:

MSDN : Win32_LogicalDisk Class

MSDN:Win32_LogicalDisk类

MSDN : System.Management namespace

MSDN:System.Management命名空间

MSDN : WMI Queries example:

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

#7


4  

QueryDosDevice translates a drive letter into the path that it expands to.

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

Note that this will translate ALL drive letters, not just those that are mapped to network connections. You need to already know which are network paths, or to parse the output to see which are network.

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

Here's the VB signature

这是VB签名

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

And the C# one

而C#one

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

#8


4  

You can use WMI to interrogate the Win32_LogicalDrive collection on your machine. Here is an example of how to do it with scripting. Changing this over to C# is pretty well explained in other places.

您可以使用WMI查询计算机上的Win32_LogicalDrive集合。以下是如何使用脚本执行此操作的示例。在其他地方很好地解释了将其更改为C#。

Slightly modified VB.NET code from the article:

从文章中略微修改了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

#9


2  

Seems it's need a P/Invoke: Converting a mapped drive letter to a network path using C#

似乎需要P / Invoke:使用C#将映射的驱动器号转换为网络路径

This guy built a managed class to deal with it: C# Map Network Drive (API)

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

#10


2  

You can also use WMI Win32_LogicalDisk to get all the information you need. use the ProviderName from the class to get the UNC path.

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

#11


2  

Similar to ibram's answer with a few modifications:

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

#12


0  

As far as Windows cares, what's needed is a call to WNetGetConnection. I don't know of a front-end for that in .NET, so you may have to call it via P/Invoke (fortunately, it has only one parameter, the P/Invoke code isn't too awful).

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

#13


0  

This post describe how to get the absolute path of a drive which is mapped to a local folder?

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

For example, I have a "c:\test" folder and an "x:" drive which is mapped to c:\test.

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

I'm looking for a function which will return "c:\test" when I pass in "x:"

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

The answer is:

答案是:

SUBST uses DefineDosDevice (XP and later) to create the drive/path mapping. You can use the QueryDosDevice to get the path of a SUBSTed drive:

SUBST使用DefineDosDevice(XP和更高版本)来创建驱动器/路径映射。您可以使用QueryDosDevice获取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;

    }

}

#1


18  

Here are some code samples:

以下是一些代码示例:

All of the magic derives from a Windows function:

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

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

#2


36  

I expanded on ibram's answer and created this class (which has been updated per comment feedback). I've probably over documented it, but it should be self-explanatory.

我扩展了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(), "");
    }
}

#3


26  

I can't remember where I found this, but it works without p/invoke. It's what rerun posted before.

我不记得我在哪里发现了这个,但它没有p / invoke就能工作。这是重新运行之前发布的内容。

you need to reference System.Management.dll:

你需要引用System.Management.dll:

using System.IO;
using System.Management;

code:

码:

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

#4


11  

I've written a method for this. It returns a UNC path if it is a mapped drive, otherwise it returns the path unchanged.

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

EDIT

编辑

You now can use the Method even with already UNC paths. The above version of the method throws an exception if given a UNC 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;
}

#5


7  

I think you can use the "Network" key From the "Current User" Hive, In the Registry. The Mapped Drives Are Listed There With Their Shared Path On Server.

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

If there is no mapped drive in the system, so there is no "Network" Key In The "Current User" Hive.

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

Now, I'm using this way, no external dll nor anything else.

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

#6


5  

I could not replicate ibram's or Vermis' answer due to the problem I mentioned in a comment under Vermis' answer, about a type initializer exception.

我无法复制ibram或Vermis的答案,因为我在Vermis回答的评论中提到的问题,关于类型初始化程序异常。

Instead, I discovered I could query for all the drives currently on the computer and then loop through them, like so:

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

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

This works for x64 Windows 7, for .NET 4. It should be usable in case you're getting that exception that was mentioned above.

这适用于x64 Windows 7,适用于.NET 4.如果您收到上面提到的异常,它应该可用。

I did this using the stuff given from MSDN and bits from ibram's or Vermis' answers, though it was a bit difficult to find specific examples on the MSDN. Resources used:

我使用MSDN提供的东西和ibram或Vermis的答案中的位来做到这一点,尽管在MSDN上找到具体的例子有点困难。使用的资源:

MSDN : Win32_LogicalDisk Class

MSDN:Win32_LogicalDisk类

MSDN : System.Management namespace

MSDN:System.Management命名空间

MSDN : WMI Queries example:

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

#7


4  

QueryDosDevice translates a drive letter into the path that it expands to.

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

Note that this will translate ALL drive letters, not just those that are mapped to network connections. You need to already know which are network paths, or to parse the output to see which are network.

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

Here's the VB signature

这是VB签名

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

And the C# one

而C#one

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

#8


4  

You can use WMI to interrogate the Win32_LogicalDrive collection on your machine. Here is an example of how to do it with scripting. Changing this over to C# is pretty well explained in other places.

您可以使用WMI查询计算机上的Win32_LogicalDrive集合。以下是如何使用脚本执行此操作的示例。在其他地方很好地解释了将其更改为C#。

Slightly modified VB.NET code from the article:

从文章中略微修改了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

#9


2  

Seems it's need a P/Invoke: Converting a mapped drive letter to a network path using C#

似乎需要P / Invoke:使用C#将映射的驱动器号转换为网络路径

This guy built a managed class to deal with it: C# Map Network Drive (API)

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

#10


2  

You can also use WMI Win32_LogicalDisk to get all the information you need. use the ProviderName from the class to get the UNC path.

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

#11


2  

Similar to ibram's answer with a few modifications:

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

#12


0  

As far as Windows cares, what's needed is a call to WNetGetConnection. I don't know of a front-end for that in .NET, so you may have to call it via P/Invoke (fortunately, it has only one parameter, the P/Invoke code isn't too awful).

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

#13


0  

This post describe how to get the absolute path of a drive which is mapped to a local folder?

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

For example, I have a "c:\test" folder and an "x:" drive which is mapped to c:\test.

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

I'm looking for a function which will return "c:\test" when I pass in "x:"

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

The answer is:

答案是:

SUBST uses DefineDosDevice (XP and later) to create the drive/path mapping. You can use the QueryDosDevice to get the path of a SUBSTed drive:

SUBST使用DefineDosDevice(XP和更高版本)来创建驱动器/路径映射。您可以使用QueryDosDevice获取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;

    }

}