namespace Tools; using System.IO; using System.Runtime.InteropServices; /// /// Wrapper for the "NET USE" functionality. /// Connect to a network resource, e.g. a network share under a different user. /// /// /// Encapsulate an instance into a using-directive like e.g.: /// ... /// using ( new NetworkConnection( @"\\myshare", true, "myUsername", "myPassword" ) ) /// { /// ... /// [code that connects to the network share under the new user context] /// ... /// } /// ... /// [PublicAPI] public sealed class NetworkConnection : IDisposable { private string? _networkName; public NetworkConnection( string networkName, bool activate, string userName, string password) { if (activate) { doNetUse(networkName, userName, password); } } private void doNetUse(string networkName, string userName, string password) { var netResource = new NetResource { Scope = ResourceScope.GlobalNetwork, ResourceType = ResourceType.Disk, DisplayType = ResourceDisplaytype.Share, RemoteName = networkName }; var result = WNetAddConnection2( netResource, password, userName, 0); if (result != 0) { throw new IOException($"Error connecting to remote share '{networkName}': {result}", result); } _networkName = networkName; } ~NetworkConnection() { doDispose(); } public void Dispose() { doDispose(); GC.SuppressFinalize(this); } private void doDispose() { if (!string.IsNullOrEmpty(_networkName)) { var nn = _networkName; _networkName = null; var result = WNetCancelConnection2(nn, 0, true); Trace.TraceInformation("Result for canceling network connection: {0}.", result); } } [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)] public class NetResource { // ReSharper disable NotAccessedField.Global // ReSharper disable NotAccessedField.Global // ReSharper disable UnusedMember.Global public ResourceScope Scope; public ResourceType ResourceType; public ResourceDisplaytype DisplayType; public int Usage; public string? LocalName; public string? RemoteName; public string? Comment; public string? Provider; // ReSharper restore UnusedMember.Global // ReSharper restore NotAccessedField.Global // ReSharper restore UnusedMember.Global } public enum ResourceScope { // ReSharper disable NotAccessedField.Global // ReSharper disable UnusedMember.Global Connected = 1, GlobalNetwork, Remembered, Recent, Context // ReSharper restore UnusedMember.Global // ReSharper restore UnusedMember.Global }; public enum ResourceType { // ReSharper disable UnusedMember.Global // ReSharper disable UnusedMember.Global Any = 0, Disk = 1, Print = 2, Reserved = 8, // ReSharper restore UnusedMember.Global // ReSharper restore UnusedMember.Global } public enum ResourceDisplaytype { // ReSharper disable UnusedMember.Global // ReSharper disable UnusedMember.Global Generic = 0x0, Domain = 0x01, Server = 0x02, Share = 0x03, File = 0x04, Group = 0x05, Network = 0x06, Root = 0x07, Shareadmin = 0x08, Directory = 0x09, Tree = 0x0a, Ndscontainer = 0x0b // ReSharper restore UnusedMember.Global // ReSharper restore UnusedMember.Global }