![](/img/trans.png)
[英]With C#, How do I get “Application.StartupPath” to return mapped drive path and not UNC path?
[英]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具體的例子。 使用的資源:
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.