如何确定映射驱动器的实际路径?如何确定映射驱动器的实际路径?
所以,如果我有一台名为“Z”的机器上映射的驱动器,我如何使用.NET确定映射文件夹的机器和路径?
代码可以假定它在映射的驱动器上运行。
我看着Path,Directory,FileInfo对象,但似乎无法找到任何东西。
我也寻找现有的问题,但找不到我在找什么。
如何确定映射驱动器的实际路径?如何确定映射驱动器的实际路径?
所以,如果我有一台名为“Z”的机器上映射的驱动器,我如何使用.NET确定映射文件夹的机器和路径?
代码可以假定它在映射的驱动器上运行。
我看着Path,Directory,FileInfo对象,但似乎无法找到任何东西。
我也寻找现有的问题,但找不到我在找什么。
这里有一些代码示例:
所有的魔法从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();
我已经确认链接工程的C#代码。我宁愿有一个非dll的导入版本,但总比没有好。 – eschneider 2010-01-15 21:40:13
而不是只提供一个链接,你可以请你提供一些在你的实际答案的情况下,以防链接变得不可用吗?谢谢。 – Deanna 2013-03-13 16:42:03
如果链接有一天无效,你需要知道的主要事情是它使用WNetGetConnection(你可以在MSDN上找到它)。 – eselk 2013-09-04 19:19:43
似乎这是一个需要的P/Invoke:Converting a mapped drive letter to a network path using C#
这家伙建立一个托管类对付它:C# Map Network Drive (API)
看起来像这样可以让你通过代码映射或取消映射驱动器,但是我没有看到从映射路径获取路径的任何内容。 – eschneider 2010-01-15 21:43:36
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);
我无法得到这个工作,也看起来它不会给文件夹,映射的驱动程序是一个服务器和一个文件夹... – eschneider 2010-01-15 21:37:21
如果你的意思是你想知道该路径,因为它显示在服务器上,那么你将需要问服务器。该信息对客户不可用。 – 2010-01-15 21:39:37
如果驱动器映射到机器上,代码正在运行,那么它应该工作。 – eschneider 2010-01-15 21:46:53
至于视窗关心,有什么需要的是WNetGetConnection
通话。我不知道.NET的前端,所以你可能不得不通过P/Invoke来调用它(幸运的是,它只有一个参数,P/Invoke代码不太可怕)。
您还可以使用WMI Win32_LogicalDisk获取所需的所有信息。使用该类中的ProviderName来获取UNC路径。
您可以使用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
无需使用任何特殊库,即可获取每个映射驱动器的网络共享的简单方法。这可以在VS Express 2012桌面Windows窗体应用程序中直接使用。 – tehDorf 2013-06-05 15:32:57
我不记得在那里我发现这一点,但它的工作原理没有的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;
}
}
我扩大对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 – deltree 2012-03-20 23:26:25
'Convert.ToUInt32(mo [“DriveType”])'会导致* System.Management.ManagementPath的类型初始值设定项引发异常*,您知道这个代码是否可以在Windows7上运行或者它可以是组策略吗? – 2013-06-04 05:52:38
@JeremyThompson这个异常(我也得到)的InnerException是[System.Threading.ThreadAbortException] {“异常的类型'System.Threading.ThreadAbortException'被抛出。”}。我不知道这个原因,但我仍然在寻找解决方案。我正在运行Win7 x64。 – Hydronium 2013-07-10 20:14:43
我想你可以使用“网络”键从“当前用户”配置单元,在注册表中。 已映射的驱动器在服务器上以共享路径列出。
如果系统中没有映射驱动器,那么在“当前用户”配置单元中没有“网络”键。
现在,我正在使用这种方式,没有外部DLL或其他任何东西。
我无法复制ibram's或Vermis'答案由于我在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;
}
}
这适用于64位的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;
}
}
我写了一个方法这一点。如果它是一个映射的驱动器,它将返回一个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;
}
到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;
}
退房@尼克的答案是不使用的PInvoke或任何特殊文库的方法。 – tehDorf 2013-06-05 15:39:04