매핑된 드라이브의 실제 경로를 확인하려면 어떻게 해야 합니까?
매핑된 드라이브의 실제 경로를 확인하려면 어떻게 해야 합니까?
그렇다면 "Z"라는 컴퓨터에 매핑된 드라이브가 있다면 .NET을 사용하여 매핑된 폴더의 컴퓨터와 경로를 어떻게 확인할 수 있습니까?
코드는 매핑된 드라이브가 있는 컴퓨터에서 실행되고 있다고 가정할 수 있습니다.
경로, 디렉터리, 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 없이 작동합니다.전에 재방송에서 올린 글입니다.
시스템을 참조해야 합니다.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;
}
레지스트리의 "현재 사용자" 하이브에서 "네트워크" 키를 사용할 수 있습니다.매핑된 드라이브가 서버에 공유 경로와 함께 나열됩니다.
시스템에 매핑된 드라이브가 없으므로 "현재 사용자" 하이브에 "네트워크" 키가 없습니다.
지금은 외부 dll이나 다른 것을 사용하지 않고 이 방법을 사용하고 있습니다.
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
제가 Vermis의 답변 아래에 있는 코멘트에서 언급한 유형 이니셜라이저 예외에 대한 문제 때문에 ibram의 답변이나 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 윈도우즈 7, .NET 4에서 작동합니다.위에서 언급한 예외가 발생할 경우 사용할 수 있습니다.
저는 MSDN에서 주어진 자료와 아이브람이나 버미스의 답변에서 나온 비트를 사용하여 이것을 했습니다. 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;
}
}
몇 가지 수정 사항을 포함한 아이브람의 답변과 유사합니다.
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" 폴더와 "x:" 드라이브가 c:\test에 매핑되어 있습니다.
"x:"에 합격하면 "c:\test"를 반환하는 함수를 찾고 있습니다.
답은 다음과 같습니다.
SUB는 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;
}
언급URL : https://stackoverflow.com/questions/2067075/how-do-i-determine-a-mapped-drives-actual-path
'programing' 카테고리의 다른 글
오류 값을 설정하는 방법은 무엇입니까? (0) | 2023.06.15 |
---|---|
read.csv에서 colClass 지정 (0) | 2023.06.15 |
Select 문에서 변수 선언 및 설정 (0) | 2023.06.15 |
왜 (x)++의 크기가 컴파일됩니까? (0) | 2023.06.15 |
Oracle: DDL 및 트랜잭션 롤백 (0) | 2023.06.15 |