簡體   English   中英

如何確定映射驅動器的實際路徑?

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

如何確定映射驅動器的實際路徑?

因此,如果我在名為“Z”的機器上有一個映射驅動器,我如何使用 .NET 確定映射文件夾的機器和路徑?

代碼可以假設它在帶有映射驅動器的機器上運行。

我查看了 Path、Directory、FileInfo 對象,但似乎找不到任何東西。

我還查找了現有問題,但找不到我要查找的內容。

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

我不記得我在哪里找到的,但它可以在沒有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 (簡而言之:管理員具有不同的用戶上下文,因此無法訪問普通用戶的映射驅動器)

下面是一些代碼示例:

所有的魔法都來自於一個 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();

我為此編寫了一個方法。 如果是映射驅動器,則返回 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;
}

我認為您可以使用注冊表中“當前用戶”配置單元中的“網絡”鍵。 映射的驅動器及其在服務器上的共享路徑在此處列出。

如果系統中沒有映射驅動器,則“當前用戶”Hive 中沒有“網絡”鍵。

現在,我正在使用這種方式,沒有外部 dll 或其他任何東西。

我無法復制IBRAM的蚓部的回答,由於我在評論中提到下蚓部問題的回答,關於類型的初始化異常。

相反,我發現我可以查詢當前計算機上的所有驅動器,然后循環遍歷它們,如下所示:

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的蚓部的答案,雖然這是一個有點難以找到在MSDN具體的例子。 使用的資源:

MSDN:Win32_LogicalDisk 類

MSDN:System.Management 命名空間

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

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

您可以使用 WMI 查詢計算機上的 Win32_LogicalDrive 集合。 下面是一個如何使用腳本執行此操作的示例 將其更改為 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

類似於 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;
}

似乎需要一個 P/Invoke:使用 C# 將映射的驅動器號轉換為網絡路徑

這家伙構建了一個托管類來處理它: C# Map Network Drive (API)

您還可以使用 WMI Win32_LogicalDisk 來獲取您需要的所有信息。 使用類中的 ProviderName 來獲取 UNC 路徑。

就 Windows 而言,需要的是調用WNetGetConnection 我不知道 .NET 中的前端,因此您可能必須通過 P/Invoke 調用它(幸運的是,它只有一個參數,P/Invoke 代碼並不太糟糕)。

這篇文章描述了如何獲取映射到本地文件夾的驅動器的絕對路徑?

例如,我有一個“c:\\test”文件夾和一個映射到 c:\\test 的“x:”驅動器。

我正在尋找一個函數,當我傳入“x:”時它會返回“c:\\test”

答案是:

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;

    }

}

這是一個不在乎是本地還是遠程的解決方案

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM