mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Replace DllImport with LibraryImport for WNetAddConnection2 (#18721)
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user