如何確定映射驅動器的實際路徑?如何確定映射驅動器的實際路徑?
所以,如果我有一臺名爲「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