using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Text;
using Vanara.Extensions;
using Vanara.Security;
using static Vanara.PInvoke.Mpr;
namespace Vanara
{
/// Information about a remote resource, usually in reference to a connection to that resource.
public class NetworkDeviceConnection : IEquatable
{
internal readonly NETRESOURCE netRes = default;
internal WindowsIdentity identity;
private NetworkDeviceConnectionCollection children;
internal NetworkDeviceConnection(NETRESOURCE r, WindowsIdentity user)
{
if (r is null) throw new ArgumentNullException(nameof(r));
netRes = r;
identity = user;
}
internal NetworkDeviceConnection(string remoteName, string localName = null, string provider = null, NETRESOURCEType type = NETRESOURCEType.RESOURCETYPE_ANY)
{
if (string.IsNullOrEmpty(remoteName)) throw new ArgumentNullException(nameof(remoteName));
netRes = new NETRESOURCE(remoteName, localName, provider) { dwType = type };
}
/// Gets the children of this resource if it is a container.
/// The children resources.
public NetworkDeviceConnectionCollection Children => children ??= new NetworkDeviceConnectionCollection(identity, netRes);
/// A string that contains a comment supplied by the network provider.
public string Comment => netRes.lpComment;
///
/// A string that contains the name of the provider that owns the resource. This member can be if the
/// provider name is unknown.
///
public string Provider => netRes.lpProvider;
/// The display options for the network object in a network browsing user interface.
public NETRESOURCEDisplayType ResourceDisplayType => netRes.dwDisplayType;
/// The type of resource.
public NETRESOURCEType ResourceType => netRes.dwType;
/// A set of flags describing how the resource can be used.
public NETRESOURCEUsage Use => netRes.dwUsage;
/// The name of a local device. This member is if the connection does not use a device.
public string LocalName => netRes.lpLocalName;
///
/// If the entry is a network resource, this member is a string that specifies the remote network name.
/// If the entry is a current or persistent connection, this member is the network name associated with .
///
public string RemoteName => netRes.lpRemoteName;
/// Makes a connection to a network resource and can redirect a local device to the network resource.
///
/// A string that specifies the network resource to connect to. The string must follow the network provider's naming conventions.
///
///
/// A string that specifies the name of a local device to redirect, such as "F:" or "LPT1". The string is treated in a
/// case-insensitive manner. If the string is empty or , the function makes a connection to the network
/// resource without redirecting a local device.
///
///
/// A pointer to a constant null-terminated string that specifies a user name for making the connection.
///
/// If lpUserName is NULL, the function uses the default user name. (The user context for the process provides the default
/// user name.)
///
///
/// The lpUserName parameter is specified when users want to connect to a network resource for which they have been assigned a user
/// name or account other than the default user name or account.
///
/// The user-name string represents a security context. It may be specific to a network provider.
/// Windows Me/98/95: This parameter must be NULL or an empty string.
///
///
/// A pointer to a constant null-terminated string that specifies a password to be used in making the network connection.
///
/// If lpPassword is NULL, the function uses the current default password associated with the user specified by the
/// lpUserName parameter.
///
/// If lpPassword points to an empty string, the function does not use a password.
///
/// If the connection fails because of an invalid password and the CONNECT_INTERACTIVE value is set in the dwFlags parameter, the
/// function displays a dialog box asking the user to type the password.
///
/// Windows Me/98/95: This parameter must be NULL or an empty string.
///
/// if set to , the resource specified in is a printer.
/// A set of connection options.
///
/// A string that specifies the network provider to connect to. If , or an empty string, the operating system
/// attempts to determine the correct provider by parsing the string provided in . If this member is
/// not , the operating system attempts to make a connection only to the named network provider. You should
/// set this member only if you know the network provider you want to use. Otherwise, let the operating system determine which
/// provider the network name maps to.
///
/// An instance of for the created connection.
public static NetworkDeviceConnection Create(string remoteName, string localName = null, string userName = null, string password = null, bool isPrinter = false, CONNECT flags = 0, string provider = null)
{
if (localName == "*")
{
var sbSz = 261U;
var sb = new StringBuilder((int)sbSz);
var nr = new NETRESOURCE(remoteName, null, provider) { dwType = NETRESOURCEType.RESOURCETYPE_DISK };
WNetUseConnection(default, nr, password, userName, flags | CONNECT.CONNECT_REDIRECT, sb, ref sbSz, out _).WNetThrowIfFailed();
nr.lpLocalName = sb.ToString();
return new NetworkDeviceConnection(nr, WindowsIdentity.GetCurrent());
}
else
{
var nr = new NETRESOURCE(remoteName, localName, provider) { dwType = isPrinter ? NETRESOURCEType.RESOURCETYPE_PRINT : (localName is null ? NETRESOURCEType.RESOURCETYPE_ANY : NETRESOURCEType.RESOURCETYPE_DISK) };
WNetAddConnection2(nr, password, userName, flags).WNetThrowIfFailed();
return new NetworkDeviceConnection(nr, WindowsIdentity.GetCurrent());
}
}
/// Implements the operator !=.
/// The left.
/// The right.
/// The result of the operator.
public static bool operator !=(NetworkDeviceConnection left, NetworkDeviceConnection right) => !(left == right);
/// Implements the operator ==.
/// The left.
/// The right.
/// The result of the operator.
public static bool operator ==(NetworkDeviceConnection left, NetworkDeviceConnection right) => EqualityComparer.Default.Equals(left, right);
/// Determines whether the specified , is equal to this instance.
/// The to compare with this instance.
/// if the specified is equal to this instance; otherwise, .
public override bool Equals(object obj) => Equals(obj as NetworkDeviceConnection);
/// Indicates whether the current object is equal to another object of the same type.
/// An object to compare with this object.
/// true if the current object is equal to the parameter; otherwise, false.
public bool Equals(NetworkDeviceConnection other) => other != null && LocalName == other.LocalName && RemoteName == other.RemoteName;
/// Returns a hash code for this instance.
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
public override int GetHashCode() => netRes.GetHashCode();
}
/// Provides access to the local machine's remote connections.
///
public class NetworkDeviceConnectionCollection : ICollection
{
internal WindowsIdentity identity;
private NETRESOURCE root;
/// Initializes a new instance of the class.
public NetworkDeviceConnectionCollection() { }
internal NetworkDeviceConnectionCollection(WindowsIdentity user, NETRESOURCE root)
{
identity = user;
this.root = root;
}
/// Gets a value indicating whether the is read-only.
public bool IsReadOnly => false;
/// Gets the number of elements contained in the .
public int Count => Enumerate().Count();
///
/// Removes an existing network connection. You can also call the function to remove remembered network connections that are not
/// currently connected.
///
///
/// A string that specifies the name of either the redirected local device or the remote network resource to disconnect from.
///
/// If this parameter specifies a redirected local device, the function cancels only the specified device redirection. If the
/// parameter specifies a remote network resource, all connections without devices are canceled.
///
///
///
///
/// If , the system updates the user profile with the information that the connection is no longer a
/// persistent one. The system will not restore this connection during subsequent logon operations. (Disconnecting resources using
/// remote names has no effect on persistent connections.)
///
///
/// If , the system does not update information about the connection. If the connection was marked as
/// persistent in the registry, the system continues to restore the connection at the next logon.
///
///
///
/// Specifies whether the disconnection should occur if there are open files or jobs on the connection. If this parameter is , the function fails if there are open files or jobs.
///
public static void RemoveConnection(string name, bool force = false, bool removePersistence = true) =>
WNetCancelConnection2(name, removePersistence ? CONNECT.CONNECT_UPDATE_PROFILE : 0, force).WNetThrowIfFailed();
/// Makes a connection to a network resource and can redirect a local device to the network resource.
///
/// A string that specifies the network resource to connect to. The string must follow the network provider's naming conventions.
///
///
/// A string that specifies the name of a local device to redirect, such as "F:" or "LPT1". The string is treated in a
/// case-insensitive manner. If the string is empty or , the function makes a connection to the network
/// resource without redirecting a local device.
///
/// if set to , the resource specified in is a printer.
///
/// A pointer to a constant null-terminated string that specifies a password to be used in making the network connection.
///
/// If lpPassword is NULL, the function uses the current default password associated with the user specified by the
/// lpUserName parameter.
///
/// If lpPassword points to an empty string, the function does not use a password.
///
/// If the connection fails because of an invalid password and the CONNECT_INTERACTIVE value is set in the dwFlags parameter, the
/// function displays a dialog box asking the user to type the password.
///
/// Windows Me/98/95: This parameter must be NULL or an empty string.
///
///
/// A pointer to a constant null-terminated string that specifies a user name for making the connection.
///
/// If lpUserName is NULL, the function uses the default user name. (The user context for the process provides the default
/// user name.)
///
///
/// The lpUserName parameter is specified when users want to connect to a network resource for which they have been assigned a user
/// name or account other than the default user name or account.
///
/// The user-name string represents a security context. It may be specific to a network provider.
/// Windows Me/98/95: This parameter must be NULL or an empty string.
///
/// A set of connection options.
///
/// A string that specifies the network provider to connect to. If , or an empty string, the operating system
/// attempts to determine the correct provider by parsing the string provided in . If this member is
/// not , the operating system attempts to make a connection only to the named network provider. You should
/// set this member only if you know the network provider you want to use. Otherwise, let the operating system determine which
/// provider the network name maps to.
///
public string Add(string remoteName, string localName = null, string userName = null, string password = null, bool isPrinter = false, CONNECT flags = 0, string provider = null)
{
var nr = identity.Run(() => NetworkDeviceConnection.Create(remoteName, localName, userName, password, isPrinter, flags, provider));
nr.identity = identity;
return nr.LocalName;
}
/// Removes all items from the .
public void Clear()
{
foreach (var r in Enumerate().ToList())
Remove(r);
}
///
/// Copies the elements of the to an , starting
/// at a particular index.
///
///
/// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing.
///
/// The zero-based index in at which copying begins.
public void CopyTo(NetworkDeviceConnection[] array, int arrayIndex)
{
var arr = Enumerate().ToArray();
Array.Copy(arr, 0, array, arrayIndex, arr.Length);
}
/// Returns an enumerator that iterates through the collection.
/// A that can be used to iterate through the collection.
public IEnumerator GetEnumerator() => Enumerate().GetEnumerator();
/// Removes the first occurrence of a specific object from the .
/// The object to remove from the .
///
/// true if was successfully removed from the ;
/// otherwise, false. This method also returns false if is not found in the original .
///
public bool Remove(NetworkDeviceConnection item) { try { Remove(item.RemoteName, false, true); return true; } catch { return false; } }
///
/// Removes an existing network connection. You can also call the function to remove remembered network connections that are not
/// currently connected.
///
///
/// A string that specifies the name of either the redirected local device or the remote network resource to disconnect from.
///
/// If this parameter specifies a redirected local device, the function cancels only the specified device redirection. If the
/// parameter specifies a remote network resource, all connections without devices are canceled.
///
///
///
///
/// If , the system updates the user profile with the information that the connection is no longer a
/// persistent one. The system will not restore this connection during subsequent logon operations. (Disconnecting resources using
/// remote names has no effect on persistent connections.)
///
///
/// If , the system does not update information about the connection. If the connection was marked as
/// persistent in the registry, the system continues to restore the connection at the next logon.
///
///
///
/// Specifies whether the disconnection should occur if there are open files or jobs on the connection. If this parameter is , the function fails if there are open files or jobs.
///
public void Remove(string name, bool force = false, bool removePersistence = true) => identity.Run(() => RemoveConnection(name, force, removePersistence));
/// Adds an item to the .
/// The object to add to the .
void ICollection.Add(NetworkDeviceConnection item) => WNetAddConnection2(item.netRes, null, null, 0);
/// Determines whether this instance contains the object.
/// The object to locate in the .
///
/// true if is found in the ; otherwise, false.
///
bool ICollection.Contains(NetworkDeviceConnection item) => Enumerate().Contains(item);
/// Returns an enumerator that iterates through a collection.
/// An object that can be used to iterate through the collection.
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
private IEnumerable Enumerate()
{
return identity.Run(() =>
root is null || root.dwUsage.IsFlagSet(NETRESOURCEUsage.RESOURCEUSAGE_CONTAINER) ?
WNetEnumResources(root, NETRESOURCEScope.RESOURCE_CONNECTED).Select(r => new NetworkDeviceConnection(r, identity)) :
new NetworkDeviceConnection[0]);
}
}
}