如何确定映射驱动器的实际路径?
因此,如果我在名为“Z”的计算机上有映射驱动器,我如何使用.NET来确定映射文件夹的计算机和路径?
代码可以假设它在带有映射驱动器的机器上运行。
我查看了Path,Directory,FileInfo对象,但似乎找不到任何东西。
我也寻找现有的问题,但找不到我想要的东西。
答案 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's或Vermis'回答。
相反,我发现我可以查询当前计算机上的所有驱动器,然后循环遍历它们,如下所示:
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's或Vermis'个答案中的位来做到这一点,尽管在MSDN上找到具体示例有点困难。使用的资源:
MSDN : Win32_LogicalDisk Class
MSDN : System.Management namespace
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;
}