128 lines
4.3 KiB
C#
128 lines
4.3 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.ComponentModel;
|
|
using System.Threading;
|
|
|
|
public class NetworkShareAccess : IDisposable
|
|
{
|
|
private readonly string _networkPath;
|
|
private readonly string _username;
|
|
private readonly string _password;
|
|
|
|
private bool _isConnected = false;
|
|
private static readonly object _lock = new object();
|
|
|
|
public NetworkShareAccess(string networkPath, string username, string password)
|
|
{
|
|
_networkPath = networkPath?.Trim().Replace('/', '\\') ?? throw new ArgumentNullException(nameof(networkPath));
|
|
if (!_networkPath.StartsWith(@"\\"))
|
|
throw new ArgumentException("Network path must start with \\\\");
|
|
|
|
_username = username ?? throw new ArgumentNullException(nameof(username));
|
|
_password = password ?? throw new ArgumentNullException(nameof(password));
|
|
}
|
|
|
|
public void ConnectToNetworkPath()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
if (_isConnected) return;
|
|
|
|
int retries = 0;
|
|
while (retries < 3)
|
|
{
|
|
try
|
|
{
|
|
var netResource = new NetResource
|
|
{
|
|
Scope = ResourceScope.GlobalNetwork,
|
|
ResourceType = ResourceType.Disk,
|
|
DisplayType = ResourceDisplayType.Share,
|
|
RemoteName = _networkPath
|
|
};
|
|
|
|
int result = WNetAddConnection2(netResource, _password, _username, 0);
|
|
|
|
if (result == 0)
|
|
{
|
|
_isConnected = true;
|
|
Console.WriteLine($"Connected to {_networkPath}");
|
|
return;
|
|
}
|
|
|
|
if (result == 1219) // Multiple connections
|
|
{
|
|
WNetCancelConnection2(_networkPath, 0, true);
|
|
Thread.Sleep(1000);
|
|
retries++;
|
|
continue;
|
|
}
|
|
|
|
throw new IOException($"Failed to connect. Error {result}: {GetNetworkErrorDescription(result)}");
|
|
}
|
|
catch
|
|
{
|
|
if (++retries >= 3) throw;
|
|
Thread.Sleep(1000);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void DisconnectFromNetworkShare()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
if (!_isConnected) return;
|
|
|
|
try
|
|
{
|
|
int result = WNetCancelConnection2(_networkPath, 0, true);
|
|
if (result != 0)
|
|
Console.WriteLine($"Warning: Disconnect failed (Error {result})");
|
|
}
|
|
finally
|
|
{
|
|
_isConnected = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Dispose() => DisconnectFromNetworkShare();
|
|
|
|
private string GetNetworkErrorDescription(int errorCode) => errorCode switch
|
|
{
|
|
5 => "Access denied",
|
|
53 => "Network path not found",
|
|
67 => "Network name not found",
|
|
85 => "Network connection already exists",
|
|
86 => "Invalid password",
|
|
1219 => "Multiple connections to a server or shared resource not allowed",
|
|
_ => new Win32Exception(errorCode).Message
|
|
};
|
|
|
|
[DllImport("mpr.dll", CharSet = CharSet.Unicode)]
|
|
private static extern int WNetAddConnection2(NetResource netResource, string password, string username, int flags);
|
|
|
|
[DllImport("mpr.dll", CharSet = CharSet.Unicode)]
|
|
private static extern int WNetCancelConnection2(string name, int flags, bool force);
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
|
private class NetResource
|
|
{
|
|
public ResourceScope Scope;
|
|
public ResourceType ResourceType;
|
|
public ResourceDisplayType DisplayType;
|
|
public int Usage;
|
|
public string LocalName;
|
|
public string RemoteName;
|
|
public string Comment;
|
|
public string Provider;
|
|
}
|
|
|
|
private enum ResourceScope { Connected = 1, GlobalNetwork, Remembered, Recent, Context }
|
|
private enum ResourceType { Any = 0, Disk = 1, Print = 2, Reserved = 8 }
|
|
private enum ResourceDisplayType { Generic = 0x0, Domain = 0x01, Server = 0x02, Share = 0x03, File = 0x04, Group = 0x05 }
|
|
} |