Replace DllImport with LibraryImport for WNetAddConnection2 (#18721)

This commit is contained in:
Ilya
2022-12-05 23:50:22 +05:00
committed by GitHub
parent 5d9835f46e
commit 07175ae0ff
4 changed files with 118 additions and 138 deletions
@@ -0,0 +1,73 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#nullable enable
using System.Runtime.InteropServices;
internal static partial class Interop
{
internal static partial class Windows
{
internal const int CONNECT_NOPERSIST = 0x00000000;
internal const int CONNECT_UPDATE_PROFILE = 0x00000001;
internal const int RESOURCE_GLOBALNET = 0x00000002;
internal const int RESOURCETYPE_ANY = 0x00000000;
internal const int RESOURCEDISPLAYTYPE_GENERIC = 0x00000000;
internal const int RESOURCEUSAGE_CONNECTABLE = 0x00000001;
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct NETRESOURCEW
{
public int Scope;
public int Type;
public int DisplayType;
public int Usage;
public char* LocalName;
public char* RemoteName;
public char* Comment;
public char* Provider;
}
[LibraryImport("mpr.dll", EntryPoint = "WNetAddConnection2W", StringMarshalling = StringMarshalling.Utf16)]
internal static partial int WNetAddConnection2(ref NETRESOURCEW netResource, byte[] password, string userName, int flags);
internal static unsafe int WNetAddConnection2(string localName, string remoteName, byte[] password, string userName, int connectType)
{
if (s_WNetApiNotAvailable)
{
return ERROR_NOT_SUPPORTED;
}
int errorCode = ERROR_NO_NETWORK;
fixed (char* pinnedLocalName = localName)
fixed (char* pinnedRemoteName = remoteName)
{
NETRESOURCEW resource = new NETRESOURCEW()
{
Comment = null,
DisplayType = RESOURCEDISPLAYTYPE_GENERIC,
LocalName = pinnedLocalName,
Provider = null,
RemoteName = pinnedRemoteName,
Scope = RESOURCE_GLOBALNET,
Type = RESOURCETYPE_ANY,
Usage = RESOURCEUSAGE_CONNECTABLE
};
try
{
errorCode = WNetAddConnection2(ref resource, password, userName, connectType);
}
catch (System.DllNotFoundException)
{
s_WNetApiNotAvailable = true;
return ERROR_NOT_SUPPORTED;
}
}
return errorCode;
}
}
}
@@ -10,6 +10,28 @@ internal static partial class Interop
internal static unsafe partial class Windows
{
[LibraryImport("mpr.dll", EntryPoint = "WNetCancelConnection2W", StringMarshalling = StringMarshalling.Utf16)]
internal static partial int WNetCancelConnection2(string driveName, int flags, [MarshalAs(UnmanagedType.Bool)] bool force);
internal static partial int WNetCancelConnection2W(string driveName, int flags, [MarshalAs(UnmanagedType.Bool)] bool force);
internal static int WNetCancelConnection2(string driveName, int flags, bool force)
{
if (s_WNetApiNotAvailable)
{
return ERROR_NOT_SUPPORTED;
}
int errorCode = ERROR_NO_NETWORK;
try
{
errorCode = WNetCancelConnection2W(driveName, flags, force: true);
}
catch (System.DllNotFoundException)
{
s_WNetApiNotAvailable = true;
return ERROR_NOT_SUPPORTED;
}
return errorCode;
}
}
}
@@ -38,7 +38,7 @@ internal static partial class Interop
// to the assembly.
ReadOnlySpan<ushort> driveName = stackalloc ushort[] { drive, ':', '\0' };
Span<ushort> uncBuffer = stackalloc ushort[(int)bufferSize];
int errorCode;
int errorCode = ERROR_NO_NETWORK;
try
{
@@ -528,7 +528,7 @@ namespace Microsoft.PowerShell.Commands
{
// MapNetworkDrive facilitates to map the newly
// created PS Drive to a network share.
this.MapNetworkDrive(drive);
MapNetworkDrive(drive);
}
// The drive is valid if the item exists or the
@@ -587,35 +587,18 @@ namespace Microsoft.PowerShell.Commands
/// MapNetworkDrive facilitates to map the newly created PS Drive to a network share.
/// </summary>
/// <param name="drive">The PSDrive info that would be used to create a new PS drive.</param>
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Can be static on Unix but not on Windows.")]
private void MapNetworkDrive(PSDriveInfo drive)
{
#if UNIX
throw new PlatformNotSupportedException();
#else
// Porting note: mapped network drives are only supported on Windows
if (Platform.IsWindows)
{
WinMapNetworkDrive(drive);
}
else
{
throw new PlatformNotSupportedException();
}
}
private static bool _WNetApiAvailable = true;
private void WinMapNetworkDrive(PSDriveInfo drive)
{
if (drive != null && !string.IsNullOrEmpty(drive.Root))
{
const int CONNECT_UPDATE_PROFILE = 0x00000001;
const int CONNECT_NOPERSIST = 0x00000000;
const int RESOURCE_GLOBALNET = 0x00000002;
const int RESOURCETYPE_ANY = 0x00000000;
const int RESOURCEDISPLAYTYPE_GENERIC = 0x00000000;
const int RESOURCEUSAGE_CONNECTABLE = 0x00000001;
const int ERROR_NO_NETWORK = 1222;
// By default the connection is not persisted.
int CONNECT_TYPE = CONNECT_NOPERSIST;
int connectType = Interop.Windows.CONNECT_NOPERSIST;
string driveName = null;
byte[] passwd = null;
@@ -625,13 +608,12 @@ namespace Microsoft.PowerShell.Commands
{
if (IsSupportedDriveForPersistence(drive))
{
CONNECT_TYPE = CONNECT_UPDATE_PROFILE;
connectType = Interop.Windows.CONNECT_UPDATE_PROFILE;
driveName = drive.Name + ":";
drive.DisplayRoot = drive.Root;
}
else
{
// error.
ErrorRecord er = new ErrorRecord(new InvalidOperationException(FileSystemProviderStrings.InvalidDriveName), "DriveNameNotSupportedForPersistence", ErrorCategory.InvalidOperation, drive);
ThrowTerminatingError(er);
}
@@ -647,37 +629,15 @@ namespace Microsoft.PowerShell.Commands
try
{
NetResource resource = new NetResource();
resource.Comment = null;
resource.DisplayType = RESOURCEDISPLAYTYPE_GENERIC;
resource.LocalName = driveName;
resource.Provider = null;
resource.RemoteName = drive.Root;
resource.Scope = RESOURCE_GLOBALNET;
resource.Type = RESOURCETYPE_ANY;
resource.Usage = RESOURCEUSAGE_CONNECTABLE;
int errorCode = Interop.Windows.WNetAddConnection2(driveName, drive.Root, passwd, userName, connectType);
int code = ERROR_NO_NETWORK;
if (_WNetApiAvailable)
if (errorCode != Interop.Windows.ERROR_SUCCESS)
{
try
{
code = NativeMethods.WNetAddConnection2(ref resource, passwd, userName, CONNECT_TYPE);
}
catch (System.DllNotFoundException)
{
_WNetApiAvailable = false;
}
}
if (code != 0)
{
ErrorRecord er = new ErrorRecord(new System.ComponentModel.Win32Exception(code), "CouldNotMapNetworkDrive", ErrorCategory.InvalidOperation, drive);
ErrorRecord er = new ErrorRecord(new System.ComponentModel.Win32Exception(errorCode), "CouldNotMapNetworkDrive", ErrorCategory.InvalidOperation, drive);
ThrowTerminatingError(er);
}
if (CONNECT_TYPE == CONNECT_UPDATE_PROFILE)
if (connectType == Interop.Windows.CONNECT_UPDATE_PROFILE)
{
// Update the current PSDrive to be a persisted drive.
drive.IsNetworkDrive = true;
@@ -692,10 +652,11 @@ namespace Microsoft.PowerShell.Commands
// Clear the password in the memory.
if (passwd != null)
{
Array.Clear(passwd, 0, passwd.Length - 1);
Array.Clear(passwd);
}
}
}
#endif
}
/// <summary>
@@ -727,15 +688,12 @@ namespace Microsoft.PowerShell.Commands
#else
if (IsNetworkMappedDrive(drive))
{
const int CONNECT_UPDATE_PROFILE = 0x00000001;
const int ERROR_NO_NETWORK = 1222;
int flags = 0;
int flags = Interop.Windows.CONNECT_NOPERSIST;
string driveName;
if (drive.IsNetworkDrive)
{
// Here we are removing only persisted network drives.
flags = CONNECT_UPDATE_PROFILE;
flags = Interop.Windows.CONNECT_UPDATE_PROFILE;
driveName = drive.Name + ":";
}
else
@@ -746,23 +704,11 @@ namespace Microsoft.PowerShell.Commands
}
// You need to actually remove the drive.
int code = ERROR_NO_NETWORK;
int errorCode = Interop.Windows.WNetCancelConnection2(driveName, flags, force: true);
if (_WNetApiAvailable)
if (errorCode != Interop.Windows.ERROR_SUCCESS)
{
try
{
code = Interop.Windows.WNetCancelConnection2(driveName, flags, true);
}
catch (System.DllNotFoundException)
{
_WNetApiAvailable = false;
}
}
if (code != 0)
{
ErrorRecord er = new ErrorRecord(new System.ComponentModel.Win32Exception(code), "CouldRemoveNetworkDrive", ErrorCategory.InvalidOperation, drive);
ErrorRecord er = new ErrorRecord(new System.ComponentModel.Win32Exception(errorCode), "CouldRemoveNetworkDrive", ErrorCategory.InvalidOperation, drive);
ThrowTerminatingError(er);
}
}
@@ -806,13 +752,6 @@ namespace Microsoft.PowerShell.Commands
#if UNIX
return driveName;
#else
return WinGetUNCForNetworkDrive(driveName);
#endif
}
#if !UNIX
private static string WinGetUNCForNetworkDrive(string driveName)
{
string uncPath = null;
if (!string.IsNullOrEmpty(driveName) && driveName.Length == 1)
{
@@ -825,8 +764,8 @@ namespace Microsoft.PowerShell.Commands
}
return uncPath;
}
#endif
}
/// <summary>
/// Get the substituted path of a NetWork type MS-DOS device that is created by 'subst' command.
@@ -7041,35 +6980,6 @@ namespace Microsoft.PowerShell.Commands
#endif
}
private static partial class NativeMethods
{
/// <summary>
/// WNetAddConnection2 API makes a connection to a network resource
/// and can redirect a local device to the network resource.
/// This API simulates the "new Use" functionality used to connect to
/// network resource.
/// </summary>
/// <param name="netResource">
/// The netResource structure contains information
/// about a network resource.</param>
/// <param name="password">
/// The password used to get connected to network resource.
/// </param>
/// <param name="username">
/// The username used to get connected to network resource.
/// </param>
/// <param name="flags">
/// The flags parameter is used to indicate if the created network
/// resource has to be persisted or not.
/// </param>
/// <returns>If connection is established to the network resource
/// then success is returned or else the error code describing the
/// type of failure that occurred while establishing
/// the connection is returned.</returns>
[DllImport("mpr.dll", CharSet = CharSet.Unicode)]
internal static extern int WNetAddConnection2(ref NetResource netResource, byte[] password, string username, int flags);
}
#if !UNIX
/// <summary>
/// The API 'PathIsNetworkPath' is not available in CoreSystem.
@@ -7092,8 +7002,7 @@ namespace Microsoft.PowerShell.Commands
if (path.Length > 1 && path[1] == ':' && char.IsAsciiLetter(path[0]))
{
// path[0] is ASCII letter, e.g. is in 'A'-'Z' or 'a'-'z'.
int errorCode = -1;
errorCode = Interop.Windows.GetUNCForNetworkDrive(path[0], out string _);
int errorCode = Interop.Windows.GetUNCForNetworkDrive(path[0], out string _);
// From the 'IsNetDrive' API.
// 0: success; 1201: connection closed; 31: device error
@@ -7109,30 +7018,6 @@ namespace Microsoft.PowerShell.Commands
}
#endif
/// <summary>
/// Managed equivalent of NETRESOURCE structure of WNet API.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct NetResource
{
public int Scope;
public int Type;
public int DisplayType;
public int Usage;
[MarshalAs(UnmanagedType.LPWStr)]
public string LocalName;
[MarshalAs(UnmanagedType.LPWStr)]
public string RemoteName;
[MarshalAs(UnmanagedType.LPWStr)]
public string Comment;
[MarshalAs(UnmanagedType.LPWStr)]
public string Provider;
}
#region InodeTracker
/// <summary>
/// Tracks visited files/directories by caching their device IDs and inodes.