Refactor PowerShell Core to use the default CoreCLR loader instead (#3903)

Remove the code that spins up our own assembly load context. Keep the code that registers our `Resolve` method to the default loader's `Resolving` event, so that we can continue to do special assembly resolution as needed (such as the GAC probing logic needed for consuming FullCLR PS modules).

Essentially, the assembly `Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll` is not needed anymore, the remaining code should be moved to S.M.A.dll. However, that will break DSC and other native hosts that are hosting powershell. So this assembly is kept for now.
This commit is contained in:
Dongbo Wang 2017-06-05 20:59:30 -07:00 committed by GitHub
parent 73548532bc
commit 8ae6c5bb3b
32 changed files with 186 additions and 858 deletions

View File

@ -80,7 +80,7 @@ namespace Microsoft.PowerShell.Cim
internal void Copy(SecureString source, int offset)
{
IntPtr plainTextString = ClrFacade.SecureStringToCoTaskMemUnicode(source);
IntPtr plainTextString = Marshal.SecureStringToCoTaskMemUnicode(source);
try
{
unsafe

View File

@ -641,7 +641,7 @@ namespace Microsoft.PowerShell.Commands
{
//assigning to tempmodule to rethrow for exceptions on 64 bit machines
tempmodule = pmodule;
WriteObject(ClrFacade.GetProcessModuleFileVersionInfo(pmodule), true);
WriteObject(pmodule.FileVersionInfo, true);
}
}
catch (InvalidOperationException exception)
@ -658,7 +658,7 @@ namespace Microsoft.PowerShell.Commands
{
if (exception.HResult == 299)
{
WriteObject(ClrFacade.GetProcessModuleFileVersionInfo(tempmodule), true);
WriteObject(tempmodule.FileVersionInfo, true);
}
else
{
@ -710,7 +710,7 @@ namespace Microsoft.PowerShell.Commands
//if fileversion of each process is to be displayed
try
{
WriteObject(ClrFacade.GetProcessModuleFileVersionInfo(PsUtils.GetMainModule(process)), true);
WriteObject(PsUtils.GetMainModule(process).FileVersionInfo, true);
}
catch (InvalidOperationException exception)
{
@ -726,7 +726,7 @@ namespace Microsoft.PowerShell.Commands
{
if (exception.HResult == 299)
{
WriteObject(ClrFacade.GetProcessModuleFileVersionInfo(PsUtils.GetMainModule(process)), true);
WriteObject(PsUtils.GetMainModule(process).FileVersionInfo, true);
}
else
{
@ -1966,7 +1966,7 @@ namespace Microsoft.PowerShell.Commands
//UseNewEnvironment
if (_UseNewEnvironment)
{
ClrFacade.GetProcessEnvironment(startInfo).Clear();
startInfo.EnvironmentVariables.Clear();
LoadEnvironmentVariable(startInfo, Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine));
LoadEnvironmentVariable(startInfo, Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User));
}
@ -2173,7 +2173,7 @@ namespace Microsoft.PowerShell.Commands
private void LoadEnvironmentVariable(ProcessStartInfo startinfo, IDictionary EnvironmentVariables)
{
var processEnvironment = ClrFacade.GetProcessEnvironment(startinfo);
var processEnvironment = startinfo.EnvironmentVariables;
foreach (DictionaryEntry entry in EnvironmentVariables)
{
if (processEnvironment.ContainsKey(entry.Key.ToString()))
@ -2373,12 +2373,7 @@ namespace Microsoft.PowerShell.Commands
return builder;
}
private static byte[] ConvertEnvVarsToByteArray(
#if CORECLR
IDictionary<string, string> sd)
#else
StringDictionary sd)
#endif
private static byte[] ConvertEnvVarsToByteArray(StringDictionary sd)
{
string[] array = new string[sd.Count];
byte[] bytes = null;
@ -2497,7 +2492,7 @@ namespace Microsoft.PowerShell.Commands
creationFlags |= 0x00000004;
IntPtr AddressOfEnvironmentBlock = IntPtr.Zero;
var environmentVars = ClrFacade.GetProcessEnvironment(startinfo);
var environmentVars = startinfo.EnvironmentVariables;
if (environmentVars != null)
{
if (this.UseNewEnvironment)
@ -2647,7 +2642,7 @@ namespace Microsoft.PowerShell.Commands
internal bool AssignProcessToJobObject(Process process)
{
// Add the process to the job object
bool result = NativeMethods.AssignProcessToJobObject(_jobObjectHandle, ClrFacade.GetRawProcessHandle(process));
bool result = NativeMethods.AssignProcessToJobObject(_jobObjectHandle, process.Handle);
return result;
}

View File

@ -2054,7 +2054,7 @@ namespace Microsoft.PowerShell.Commands
if (null != Credential)
{
username = Credential.UserName;
password = ClrFacade.SecureStringToCoTaskMemUnicode(Credential.Password);
password = Marshal.SecureStringToCoTaskMemUnicode(Credential.Password);
}
// Create the service

View File

@ -964,7 +964,7 @@ namespace Microsoft.PowerShell.Commands
Assembly assembly = LoadAssemblyHelper(assemblyName);
if (assembly == null)
{
assembly = LoadFrom(ResolveAssemblyName(assemblyName, false));
assembly = Assembly.LoadFrom(ResolveAssemblyName(assemblyName, false));
}
if (passThru)
@ -1276,7 +1276,7 @@ namespace Microsoft.PowerShell.Commands
{
ms.Flush();
ms.Seek(0, SeekOrigin.Begin);
Assembly assembly = LoadFrom(ms);
Assembly assembly = Assembly.Load(ms.ToArray());
CheckTypesForDuplicates(assembly);
if (passThru)
{
@ -1292,7 +1292,7 @@ namespace Microsoft.PowerShell.Commands
{
if (passThru)
{
Assembly assembly = LoadFrom(outputAssembly);
Assembly assembly = Assembly.LoadFrom(outputAssembly);
CheckTypesForDuplicates(assembly);
WriteTypes(assembly);
}
@ -1318,16 +1318,6 @@ namespace Microsoft.PowerShell.Commands
ErrorNumber = d.Id
}).ToArray();
}
private Assembly LoadFrom(Stream assembly)
{
return ClrFacade.LoadFrom(assembly);
}
private Assembly LoadFrom(string path)
{
return ClrFacade.LoadFrom(path);
}
}
@ -1955,7 +1945,7 @@ namespace Microsoft.PowerShell.Commands
{
foreach (string path in paths)
{
generatedTypes.AddRange(ClrFacade.LoadFrom(path).GetTypes());
generatedTypes.AddRange(Assembly.LoadFrom(path).GetTypes());
}
}
// Load the assembly by name

View File

@ -285,7 +285,7 @@ namespace Microsoft.PowerShell.Commands
{
try
{
culture = ClrFacade.GetCultureInfo(_uiculture);
culture = CultureInfo.GetCultureInfo(_uiculture);
}
catch (ArgumentException)
{

View File

@ -1079,8 +1079,8 @@ namespace Microsoft.PowerShell
}
#endif
ClrFacade.SetCurrentThreadUiCulture(this.CurrentUICulture);
ClrFacade.SetCurrentThreadCulture(this.CurrentCulture);
Thread.CurrentThread.CurrentUICulture = this.CurrentUICulture;
Thread.CurrentThread.CurrentCulture = this.CurrentCulture;
// BUG: 610329. Tell PowerShell engine to apply console
// related properties while launching Pipeline Execution
// Thread.

View File

@ -9,6 +9,7 @@ using System.Management.Automation.Internal;
using System.Management.Automation.Runspaces;
using System.Management.Automation.Tracing;
using System.Globalization;
using System.Threading;
#if CORECLR
using System.Runtime.InteropServices;
@ -65,8 +66,8 @@ namespace Microsoft.PowerShell
// The currentUICulture returned NativeCultureResolver supports this non
// traditional fallback on Vista. So it is important to set currentUICulture
// in the beginning before we do anything.
ClrFacade.SetCurrentThreadUiCulture(NativeCultureResolver.UICulture);
ClrFacade.SetCurrentThreadCulture(NativeCultureResolver.Culture);
Thread.CurrentThread.CurrentUICulture = NativeCultureResolver.UICulture;
Thread.CurrentThread.CurrentCulture = NativeCultureResolver.Culture;
RunspaceConfigForSingleShell configuration = null;
PSConsoleLoadException warning = null;

View File

@ -19,7 +19,7 @@ namespace System.Management.Automation
/// <summary>
/// The powershell custom AssemblyLoadContext implementation
/// </summary>
internal partial class PowerShellAssemblyLoadContext : AssemblyLoadContext
internal partial class PowerShellAssemblyLoadContext
{
#region Resource_Strings
@ -31,11 +31,7 @@ namespace System.Management.Automation
// When the first attempt fails, we again need to retrieve the resource string to construct another exception, which ends up with an infinite loop.
private const string BaseFolderDoesNotExist = "The base directory '{0}' does not exist.";
private const string ManifestDefinitionDoesNotMatch = "Could not load file or assembly '{0}' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference.";
private const string AssemblyPathDoesNotExist = "Could not load file or assembly '{0}' or one of its dependencies. The system cannot find the file specified.";
private const string InvalidAssemblyExtensionName = "Could not load file or assembly '{0}' or one of its dependencies. The file specified is not a DLL file.";
private const string AbsolutePathRequired = "Absolute path information is required.";
private const string SingletonAlreadyInitialized = "The singleton of PowerShellAssemblyLoadContext has already been initialized.";
private const string UseResolvingEventHandlerOnly = "PowerShellAssemblyLoadContext was initialized to use its 'Resolving' event handler only.";
#endregion Resource_Strings
@ -44,14 +40,14 @@ namespace System.Management.Automation
/// <summary>
/// Initialize a singleton of PowerShellAssemblyLoadContext
/// </summary>
internal static PowerShellAssemblyLoadContext InitializeSingleton(string basePaths, bool useResolvingHandlerOnly)
internal static PowerShellAssemblyLoadContext InitializeSingleton(string basePaths)
{
lock (s_syncObj)
{
if (Instance != null)
throw new InvalidOperationException(SingletonAlreadyInitialized);
Instance = new PowerShellAssemblyLoadContext(basePaths, useResolvingHandlerOnly);
Instance = new PowerShellAssemblyLoadContext(basePaths);
return Instance;
}
}
@ -60,96 +56,52 @@ namespace System.Management.Automation
/// Constructor
/// </summary>
/// <param name="basePaths">
/// Base directory paths that are separated by semicolon ';'.
/// They will be the default paths to probe assemblies.
/// Base directory paths that are separated by semicolon ';'. They will be the default paths to probe assemblies.
/// The passed-in argument could be null or an empty string, in which case there is no default paths to probe assemblies.
/// </param>
/// <param name="useResolvingHandlerOnly">
/// Indicate whether this instance is going to be used as a
/// full fledged ALC, or only its 'Resolve' handler is going
/// to be used.
/// </param>
/// <remarks>
/// When <paramref name="useResolvingHandlerOnly"/> is true, we will register to the 'Resolving' event of the default
/// load context with our 'Resolve' method, and depend on the default load context to resolve/load assemblies for PS.
/// This mode is used when TPA list of the native host only contains .NET Core libraries.
/// In this case, TPA binder will be consulted before hitting our resolving logic. The binding order of Assembly.Load is:
/// TPA binder --> Resolving event
///
/// When <paramref name="useResolvingHandlerOnly"/> is false, we will use this instance as a full fledged load context
/// to resolve/load assemblies for PS. This mode is used when TPA list of the native host contains both .NET Core libraries
/// and PS assemblies.
/// In this case, our Load override will kick in before consulting the TPA binder. The binding order of Assembly.Load is:
/// Load override --> TPA binder --> Resolving event
/// </remarks>
private PowerShellAssemblyLoadContext(string basePaths, bool useResolvingHandlerOnly)
private PowerShellAssemblyLoadContext(string basePaths)
{
#region Validation
// FIRST: Validate and populate probing paths
if (string.IsNullOrEmpty(basePaths))
{
throw new ArgumentNullException("basePaths");
}
_basePaths = basePaths.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < _basePaths.Length; i++)
{
string basePath = _basePaths[i];
if (!Directory.Exists(basePath))
{
string message = string.Format(
CultureInfo.CurrentCulture,
BaseFolderDoesNotExist,
basePath);
throw new ArgumentException(message, "basePaths");
}
_basePaths[i] = basePath.Trim();
}
#endregion Validation
// FIRST: Add basePaths to probing paths
_probingPaths = new List<string>(_basePaths);
// NEXT: Initialize the CoreCLR type catalog dictionary [OrdinalIgnoreCase]
_coreClrTypeCatalog = InitializeTypeCatalog();
// LAST: Handle useResolvingHandlerOnly flag
_useResolvingHandlerOnly = useResolvingHandlerOnly;
_activeLoadContext = useResolvingHandlerOnly ? Default : this;
if (useResolvingHandlerOnly)
{
Default.Resolving += Resolve;
_probingPaths = Array.Empty<string>();
}
else
{
var tempSet = new HashSet<string>(_coreClrTypeCatalog.Values, StringComparer.OrdinalIgnoreCase);
_tpaSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" };
foreach (string tpa in tempSet)
_probingPaths = basePaths.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < _probingPaths.Length; i++)
{
string shortName = tpa.Substring(0, tpa.IndexOf(','));
_tpaSet.Add(shortName);
string basePath = _probingPaths[i];
if (!Directory.Exists(basePath))
{
string message = string.Format(CultureInfo.CurrentCulture, BaseFolderDoesNotExist, basePath);
throw new ArgumentException(message, "basePaths");
}
_probingPaths[i] = basePath.Trim();
}
}
// NEXT: Initialize the CoreCLR type catalog dictionary [OrdinalIgnoreCase]
_coreClrTypeCatalog = InitializeTypeCatalog();
_availableDotNetAssemblyNames = new Lazy<HashSet<string>>(
() => new HashSet<string>(_coreClrTypeCatalog.Values, StringComparer.Ordinal));
// LAST: Register 'Resolving' handler on the default load context.
AssemblyLoadContext.Default.Resolving += Resolve;
}
#endregion Constructor
#region Fields
private readonly bool _useResolvingHandlerOnly;
private readonly AssemblyLoadContext _activeLoadContext;
private readonly static object s_syncObj = new object();
private readonly string[] _basePaths;
// Initially, 'probingPaths' only contains psbase path. But every time we load an assembly through 'LoadFrom(string AssemblyPath)', we
// add its parent path to 'probingPaths', so that we are able to support implicit loading of an assembly from the same place where the
// requesting assembly is located.
// We don't need to worry about removing any paths from 'probingPaths', because once an assembly is loaded, it won't be unloaded until
// the current process exits, and thus the assembly itself and its parent folder cannot be deleted or renamed.
private readonly List<string> _probingPaths;
private readonly string[] _probingPaths;
private readonly string[] _extensions = new string[] { ".ni.dll", ".dll" };
// CoreCLR type catalog dictionary
// - Key: namespace qualified type name (FullName)
// - Value: strong name of the TPA that contains the type represented by Key.
private readonly Dictionary<string, string> _coreClrTypeCatalog;
private readonly HashSet<string> _tpaSet;
private readonly string[] _extensions = new string[] { ".ni.dll", ".dll" };
private readonly Lazy<HashSet<string>> _availableDotNetAssemblyNames;
/// <summary>
/// Assembly cache across the AppDomain
@ -180,38 +132,71 @@ namespace System.Management.Automation
get; private set;
}
/// <summary>
/// Get the namespace-qualified type names of all available .NET Core types shipped with PowerShell Core.
/// This is used for type name auto-completion in PS engine.
/// </summary>
internal IEnumerable<string> AvailableDotNetTypeNames
{
get { return _coreClrTypeCatalog.Keys; }
}
/// <summary>
/// Get the assembly names of all available .NET Core assemblies shipped with PowerShell Core.
/// This is used for type name auto-completion in PS engine.
/// </summary>
internal HashSet<string> AvailableDotNetAssemblyNames
{
get { return _availableDotNetAssemblyNames.Value; }
}
#endregion Properties
#region Events
#region Internal_Methods
/// <summary>
/// Assembly load event
/// Get the current loaded assemblies
/// </summary>
internal event Action<Assembly> AssemblyLoad;
#endregion Events
#region Protected_Internal_Methods
/// <summary>
/// Implement the AssemblyLoadContext.Load(AssemblyName). Search the requested assembly in probing paths.
/// Search the file "[assemblyName.Name][.ni].dll" in probing paths. If the file is found and it matches the requested AssemblyName, load it with LoadFromAssemblyPath.
/// </summary>
protected override Assembly Load(AssemblyName assemblyName)
internal IEnumerable<Assembly> GetAssembly(string namespaceQualifiedTypeName)
{
if (_useResolvingHandlerOnly)
throw new NotSupportedException(UseResolvingEventHandlerOnly);
// If 'namespaceQualifiedTypeName' is specified and it's a CoreCLR framework type,
// then we only return that specific TPA assembly.
if (!string.IsNullOrEmpty(namespaceQualifiedTypeName))
{
if (_coreClrTypeCatalog.TryGetValue(namespaceQualifiedTypeName, out string tpaStrongName))
{
try
{
return new Assembly[] { GetTrustedPlatformAssembly(tpaStrongName) };
}
catch (FileNotFoundException) { }
}
}
// We let the default context load the assemblies included in the type catalog as there
// appears to be a bug in .NET with method resolution with system libraries loaded by our
// context and not the default. We use the short name because some packages have inconsistent
// versions between reference and runtime assemblies.
if (_tpaSet.Contains(assemblyName.Name))
return null;
return Resolve(this, assemblyName);
// Otherwise, we return null
return null;
}
/// <summary>
/// Set the profile optimization root on the appropriate load context
/// </summary>
internal void SetProfileOptimizationRootImpl(string directoryPath)
{
AssemblyLoadContext.Default.SetProfileOptimizationRoot(directoryPath);
}
/// <summary>
/// Start the profile optimization on the appropriate load context
/// </summary>
internal void StartProfileOptimizationImpl(string profile)
{
AssemblyLoadContext.Default.StartProfileOptimization(profile);
}
#endregion Internal_Methods
#region Private_Methods
/// <summary>
/// The handler for the Resolving event
/// </summary>
@ -235,7 +220,7 @@ namespace System.Management.Automation
string asmCultureName = assemblyName.CultureName ?? string.Empty;
string asmFilePath = null;
for (int i = 0; i < _probingPaths.Count; i++)
for (int i = 0; i < _probingPaths.Length; i++)
{
string probingPath = _probingPaths[i];
string asmCulturePath = Path.Combine(probingPath, asmCultureName);
@ -247,7 +232,7 @@ namespace System.Management.Automation
if (File.Exists(asmFilePath))
{
isAssemblyFileFound = true;
AssemblyName asmNameFound = GetAssemblyName(asmFilePath);
AssemblyName asmNameFound = AssemblyLoadContext.GetAssemblyName(asmFilePath);
if (IsAssemblyMatching(assemblyName, asmNameFound))
{
isAssemblyFileMatching = true;
@ -279,303 +264,9 @@ namespace System.Management.Automation
}
}
// Raise AssemblyLoad event
OnAssemblyLoaded(asmLoaded);
return asmLoaded;
}
/// <summary>
/// Load an IL or NI assembly from its file path.
/// </summary>
internal Assembly LoadFrom(string assemblyPath)
{
ValidateAssemblyPath(assemblyPath, "assemblyPath");
Assembly asmLoaded;
AssemblyName assemblyName = GetAssemblyName(assemblyPath);
// Probe the assembly cache
if (TryGetAssemblyFromCache(assemblyName, out asmLoaded))
return asmLoaded;
// Prepare to load the assembly
lock (s_syncObj)
{
// Probe the cache again in case it's already loaded
if (TryGetAssemblyFromCache(assemblyName, out asmLoaded))
return asmLoaded;
// Load the assembly through 'LoadFromNativeImagePath' or 'LoadFromAssemblyPath'
asmLoaded = assemblyPath.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase)
? _activeLoadContext.LoadFromNativeImagePath(assemblyPath, null)
: _activeLoadContext.LoadFromAssemblyPath(assemblyPath);
if (asmLoaded != null)
{
// Add the loaded assembly to the cache
s_assemblyCache.TryAdd(assemblyName.Name, asmLoaded);
// Add its parent path to our probing paths
string parentPath = Path.GetDirectoryName(assemblyPath);
if (!_probingPaths.Contains(parentPath))
{
_probingPaths.Add(parentPath);
}
}
}
// Raise AssemblyLoad event
OnAssemblyLoaded(asmLoaded);
return asmLoaded;
}
/// <summary>
/// Load assembly from byte stream.
/// </summary>
internal Assembly LoadFrom(Stream assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly");
Assembly asmLoaded;
AssemblyName assemblyName = GetAssemblyName(assembly);
// Probe the assembly cache
if (TryGetAssemblyFromCache(assemblyName, out asmLoaded))
return asmLoaded;
// Prepare to load the assembly
lock (s_syncObj)
{
// Probe the cache again in case it's already loaded
if (TryGetAssemblyFromCache(assemblyName, out asmLoaded))
return asmLoaded;
// Load the assembly through 'LoadFromStream'
asmLoaded = _activeLoadContext.LoadFromStream(assembly);
if (asmLoaded != null)
{
// Add the loaded assembly to the cache
s_assemblyCache.TryAdd(assemblyName.Name, asmLoaded);
}
}
// Raise AssemblyLoad event
OnAssemblyLoaded(asmLoaded);
return asmLoaded;
}
/// <summary>
/// Get the current loaded assemblies
/// </summary>
internal IEnumerable<Assembly> GetAssemblies(string namespaceQualifiedTypeName)
{
// If 'namespaceQualifiedTypeName' is specified and it's a CoreCLR framework type,
// then we only return that specific TPA assembly.
if (!string.IsNullOrEmpty(namespaceQualifiedTypeName))
{
string tpaStrongName;
if (_coreClrTypeCatalog.TryGetValue(namespaceQualifiedTypeName, out tpaStrongName))
{
try
{
return new Assembly[] { GetTrustedPlatformAssembly(tpaStrongName) };
}
catch (FileNotFoundException)
{
// It's possible that the type catalog generated in OPS contains more entries than
// the one generated in windows build. This is because in OPS we have more freedom
// to control what packages to depend on, such as Json.NET.
// If we deploy the PSALC.dll generated from OPS to NanoServer, then it's possible
// that 'GetTrustedPlatformAssembly(tpaStrongName)' may fail for such entries. In
// this case, we ignore the exception and return our cached assemblies.
}
}
}
// Otherwise, we return all assemblies from the AssemblyCache
return s_assemblyCache.Values;
}
/// <summary>
/// Try adding a new assembly to the cache
/// </summary>
/// <remarks>
/// This is for adding a dynamic assembly to the cache.
/// PowerShell generates dynamic assemblies by directly emitting IL, and this API
/// is to add such assemblies to the cache so that types in them are discoverable.
/// </remarks>
internal bool TryAddAssemblyToCache(Assembly assembly)
{
AssemblyName asmName = assembly.GetName();
bool success = s_assemblyCache.TryAdd(asmName.Name, assembly);
// Raise AssemblyLoad event
if (success) { OnAssemblyLoaded(assembly); }
return success;
}
/// <summary>
/// Probe for the assembly file with the specified short name for metadata analysis purpose
/// </summary>
internal string ProbeAssemblyFileForMetadataAnalysis(string assemblyShortName, string additionalSearchPath)
{
if (string.IsNullOrEmpty(assemblyShortName))
{
throw new ArgumentNullException("assemblyShortName");
}
bool useAdditionalSearchPath = false;
if (!string.IsNullOrEmpty(additionalSearchPath))
{
if (!Path.IsPathRooted(additionalSearchPath))
{
throw new ArgumentException(AbsolutePathRequired, "additionalSearchPath");
}
useAdditionalSearchPath = Directory.Exists(additionalSearchPath);
}
// Construct the probing paths for searching the specified assembly file
string[] metadataProbingPaths = _basePaths;
if (useAdditionalSearchPath)
{
var searchPaths = new List<string>() { additionalSearchPath };
searchPaths.AddRange(_basePaths);
metadataProbingPaths = searchPaths.ToArray();
}
for (int i = 0; i < metadataProbingPaths.Length; i++)
{
string metadataProbingPath = metadataProbingPaths[i];
for (int k = 0; k < _extensions.Length; k++)
{
string asmFileName = assemblyShortName + _extensions[k];
string asmFilePath = Path.Combine(metadataProbingPath, asmFileName);
if (File.Exists(asmFilePath))
{
return asmFilePath;
}
}
}
return null;
}
/// <summary>
/// Get the namespace-qualified type names of all available CoreCLR .NET types.
/// This is used for type name auto-completion in PS engine.
/// </summary>
internal IEnumerable<string> GetAvailableDotNetTypes()
{
return _coreClrTypeCatalog.Keys;
}
/// <summary>
/// Set the profile optimization root on the appropriate load context
/// </summary>
/// <remarks>
/// When using PS ALC as a full fledged ALC in OPS, we don't enable profile optimization.
/// This is because PS assemblies will be recorded in the profile, and the next time OPS
/// starts up, the default context will load the PS assemblies pretty early to ngen them
/// in another CPU core, so our Load override won't track the loading of them, and thus
/// OPS will fail to work.
/// The root cause is that dotnet.exe put all PS assemblies in TPA list. If PS assemblies
/// are not in TPA list, then we can enable profile optimization without a problem.
/// </remarks>
internal void SetProfileOptimizationRootImpl(string directoryPath)
{
if (_useResolvingHandlerOnly)
_activeLoadContext.SetProfileOptimizationRoot(directoryPath);
}
/// <summary>
/// Start the profile optimization on the appropriate load context
/// </summary>
/// <remarks>
/// When using PS ALC as a full fledged ALC in OPS, we don't enable profile optimization.
/// This is because PS assemblies will be recorded in the profile, and the next time OPS
/// starts up, the default context will load the PS assemblies pretty early to ngen them
/// in another CPU core, so our Load override won't track the loading of them, and thus
/// OPS will fail to work.
/// The root cause is that dotnet.exe put all PS assemblies in TPA list. If PS assemblies
/// are not in TPA list, then we can enable profile optimization without a problem.
/// </remarks>
internal void StartProfileOptimizationImpl(string profile)
{
if (_useResolvingHandlerOnly)
_activeLoadContext.StartProfileOptimization(profile);
}
#endregion Protected_Internal_Methods
#region Private_Methods
/// <summary>
/// Handle the AssemblyLoad event
/// </summary>
private void OnAssemblyLoaded(Assembly assemblyLoaded)
{
Action<Assembly> assemblyLoadHandler = AssemblyLoad;
if (assemblyLoaded != null && assemblyLoadHandler != null)
{
try
{
assemblyLoadHandler(assemblyLoaded);
}
catch
{
// Catch all exceptions, same behavior as AppDomain.AssemblyLoad
}
}
}
/// <summary>
/// Validate assembly path value for the specified parameter
/// </summary>
private void ValidateAssemblyPath(string assemblyPath, string parameterName)
{
if (string.IsNullOrEmpty(assemblyPath))
{
throw new ArgumentNullException(parameterName);
}
if (!Path.IsPathRooted(assemblyPath))
{
throw new ArgumentException(AbsolutePathRequired, parameterName);
}
if (!File.Exists(assemblyPath))
{
ThrowFileNotFoundException(
AssemblyPathDoesNotExist,
assemblyPath);
}
if (!string.Equals(Path.GetExtension(assemblyPath), ".DLL", StringComparison.OrdinalIgnoreCase))
{
ThrowFileLoadException(
InvalidAssemblyExtensionName,
assemblyPath);
}
}
/// <summary>
/// Get AssemblyName of an assembly stream
/// </summary>
private AssemblyName GetAssemblyName(Stream assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly");
string strongAssemblyName = null;
using (PEReader peReader = new PEReader(assembly, PEStreamOptions.LeaveOpen | PEStreamOptions.PrefetchMetadata))
{
MetadataReader metadataReader = peReader.GetMetadataReader();
strongAssemblyName = AssemblyMetadataHelper.GetAssemblyStrongName(metadataReader);
}
assembly.Seek(0, SeekOrigin.Begin);
return new AssemblyName(strongAssemblyName);
}
/// <summary>
/// Try to get the specified assembly from cache
/// </summary>
@ -689,8 +380,6 @@ namespace System.Management.Automation
/// </summary>
public class PowerShellAssemblyLoadContextInitializer
{
private static object[] s_emptyArray = new object[0];
/// <summary>
/// Create a singleton of PowerShellAssemblyLoadContext.
/// Then register to the Resolving event of the load context that loads this assembly.
@ -708,106 +397,7 @@ namespace System.Management.Automation
if (string.IsNullOrEmpty(basePaths))
throw new ArgumentNullException("basePaths");
PowerShellAssemblyLoadContext.InitializeSingleton(basePaths, useResolvingHandlerOnly: true);
}
/// <summary>
/// Create a singleton of PowerShellAssemblyLoadContext.
/// Then load System.Management.Automation and call the WSManPluginManagedEntryWrapper delegate.
/// </summary>
/// <remarks>
/// This method is used by the native host of the PSRP plugin.
/// </remarks>
/// <param name="wkrPtrs">
/// Passed to delegate.
/// </param>
public static int WSManPluginWrapper(IntPtr wkrPtrs)
{
string basePaths = System.IO.Path.GetDirectoryName(typeof(PowerShellAssemblyLoadContextInitializer).GetTypeInfo().Assembly.Location);
string entryAssemblyName = "System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
string entryTypeName = "System.Management.Automation.Remoting.WSManPluginManagedEntryWrapper";
string entryMethodName = "InitPlugin";
object[] args = { wkrPtrs };
var psLoadContext = PowerShellAssemblyLoadContext.InitializeSingleton(basePaths, useResolvingHandlerOnly: false);
var entryAssembly = psLoadContext.LoadFromAssemblyName(new AssemblyName(entryAssemblyName));
var entryType = entryAssembly.GetType(entryTypeName, throwOnError: true, ignoreCase: true);
var methodInfo = entryType.GetMethod(entryMethodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase);
return (int)methodInfo.Invoke(null, args);
}
/// <summary>
/// Create a singleton of PowerShellAssemblyLoadContext.
/// Then load the assembly containing the actual entry point using it.
/// </summary>
/// <param name="basePaths">
/// Base directory paths that are separated by semicolon ';'.
/// They will be the default paths to probe assemblies.
/// </param>
/// <param name="entryAssemblyName">
/// Name of the assembly that contains the actual entry point.
/// </param>
/// <returns>
/// The assembly that contains the actual entry point.
/// </returns>
public static Assembly InitializeAndLoadEntryAssembly(string basePaths, AssemblyName entryAssemblyName)
{
if (string.IsNullOrEmpty(basePaths))
throw new ArgumentNullException("basePaths");
if (entryAssemblyName == null)
throw new ArgumentNullException("entryAssemblyName");
var psLoadContext = PowerShellAssemblyLoadContext.InitializeSingleton(basePaths, useResolvingHandlerOnly: false);
return psLoadContext.LoadFromAssemblyName(entryAssemblyName);
}
/// <summary>
/// Create a singleton of PowerShellAssemblyLoadContext.
/// Then call into the actual entry point based on the given assembly name, type name, method name and arguments.
/// </summary>
/// <param name="basePaths">
/// Base directory paths that are separated by semicolon ';'.
/// They will be the default paths to probe assemblies.
/// </param>
/// <param name="entryAssemblyName">
/// Name of the assembly that contains the actual entry point.
/// </param>
/// <param name="entryTypeName">
/// Name of the type that contains the actual entry point.
/// </param>
/// <param name="entryMethodName">
/// Name of the actual entry point method.
/// </param>
/// <param name="args">
/// An array of arguments passed to the entry point method.
/// </param>
/// <returns>
/// The return value of running the entry point method.
/// </returns>
public static object InitializeAndCallEntryMethod(string basePaths, AssemblyName entryAssemblyName, string entryTypeName, string entryMethodName, object[] args)
{
if (string.IsNullOrEmpty(basePaths))
throw new ArgumentNullException("basePaths");
if (entryAssemblyName == null)
throw new ArgumentNullException("entryAssemblyName");
if (string.IsNullOrEmpty(entryTypeName))
throw new ArgumentNullException("entryTypeName");
if (string.IsNullOrEmpty(entryMethodName))
throw new ArgumentNullException("entryMethodName");
args = args ?? s_emptyArray;
var psLoadContext = PowerShellAssemblyLoadContext.InitializeSingleton(basePaths, useResolvingHandlerOnly: false);
var entryAssembly = psLoadContext.LoadFromAssemblyName(entryAssemblyName);
var entryType = entryAssembly.GetType(entryTypeName, throwOnError: true, ignoreCase: true);
var methodInfo = entryType.GetMethod(entryMethodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase);
return methodInfo.Invoke(null, args);
PowerShellAssemblyLoadContext.InitializeSingleton(basePaths);
}
}
}

View File

@ -5,9 +5,8 @@ Copyright (c) Microsoft Corporation. All rights reserved.
namespace Microsoft.PowerShell.CoreCLR
{
using System.IO;
using System;
using System.Reflection;
using System.Management.Automation;
/// <summary>
/// AssemblyExtensions
@ -19,19 +18,10 @@ namespace Microsoft.PowerShell.CoreCLR
/// </summary>
/// <param name="assemblyPath">The path of the file that contains the manifest of the assembly.</param>
/// <returns>The loaded assembly.</returns>
[ObsoleteAttribute("This method is obsolete. Call Assembly.LoadFrom instead", false)]
public static Assembly LoadFrom(string assemblyPath)
{
return ClrFacade.LoadFrom(assemblyPath);
}
/// <summary>
/// Load an assembly given its byte stream
/// </summary>
/// <param name="assembly">The byte stream of assembly</param>
/// <returns>The loaded assembly</returns>
public static Assembly LoadFrom(Stream assembly)
{
return ClrFacade.LoadFrom(assembly);
return Assembly.LoadFrom(assemblyPath);
}
}
}

View File

@ -65,7 +65,7 @@ namespace Microsoft.PowerShell.Cmdletization
eb.DefineLiteral(name, integerValue);
}
ClrFacade.CreateEnumType(eb);
eb.CreateTypeInfo();
}
}
}

View File

@ -35,18 +35,10 @@ namespace System.Management.Automation
{
static CompletionCompleters()
{
#if CORECLR
ClrFacade.AddAssemblyLoadHandler(UpdateTypeCacheOnAssemblyLoad);
#else
AppDomain.CurrentDomain.AssemblyLoad += UpdateTypeCacheOnAssemblyLoad;
#endif
}
#if CORECLR
static void UpdateTypeCacheOnAssemblyLoad(Assembly loadedAssembly)
#else
private static void UpdateTypeCacheOnAssemblyLoad(object sender, AssemblyLoadEventArgs args)
#endif
{
// Just null out the cache - we'll rebuild it the next time someone tries to complete a type.
// We could rebuild it now, but we could be loading multiple assemblies (e.g. dependent assemblies)
@ -5862,34 +5854,11 @@ namespace System.Management.Automation
#endregion Process_TypeAccelerators
#region Process_LoadedAssemblies
var assembliesExcludingPSGenerated = ClrFacade.GetAssemblies();
var allPublicTypes = assembliesExcludingPSGenerated.SelectMany(assembly =>
{
try
{
return assembly.GetTypes().Where(TypeResolver.IsPublic);
}
catch (ReflectionTypeLoadException)
{
}
return Type.EmptyTypes;
});
foreach (var type in allPublicTypes)
{
HandleNamespace(entries, type.Namespace);
HandleType(entries, type.FullName, type.Name, type);
}
#endregion Process_LoadedAssemblies
#region Process_CoreCLR_TypeCatalog
#if CORECLR
// In CoreCLR, we have namespace-qualified type names of all available .NET types stored in TypeCatalog of the AssemblyLoadContext.
// In CoreCLR, we have namespace-qualified type names of all available .NET Core types stored in TypeCatalog.
// Populate the type completion cache using the namespace-qualified type names.
foreach (string fullTypeName in ClrFacade.GetAvailableCoreClrDotNetTypes())
foreach (string fullTypeName in ClrFacade.AvailableDotNetTypeNames)
{
var typeCompInString = new TypeCompletionInStringFormat { FullTypeName = fullTypeName };
HandleNamespace(entries, typeCompInString.Namespace);
@ -5898,6 +5867,32 @@ namespace System.Management.Automation
#endif
#endregion Process_CoreCLR_TypeCatalog
#region Process_LoadedAssemblies
foreach (Assembly assembly in ClrFacade.GetAssemblies())
{
#if CORECLR
// Ignore the assemblies that are already covered by the type catalog
if (ClrFacade.AvailableDotNetAssemblyNames.Contains(assembly.FullName)) { continue; }
#endif
try
{
foreach (Type type in assembly.GetTypes())
{
// Ignore non-public types
if (!TypeResolver.IsPublic(type)) { continue; }
HandleNamespace(entries, type.Namespace);
HandleType(entries, type.FullName, type.Name, type);
}
}
catch (ReflectionTypeLoadException)
{
}
}
#endregion Process_LoadedAssemblies
var grouping = entries.Values.GroupBy(t => t.Key.Count(c => c == '.')).OrderBy(g => g.Key).ToArray();
var localTypeCache = new TypeCompletionMapping[grouping.Last().Key + 1][];
foreach (var group in grouping)

View File

@ -7,6 +7,7 @@ using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Management.Automation.Language;
using System.Management.Automation.Runspaces;
using System.Reflection;
using System.Runtime.ExceptionServices;
using Microsoft.PowerShell.Commands;
@ -227,7 +228,7 @@ namespace System.Management.Automation
else if (Module.Path.EndsWith(StringLiterals.DependentWorkflowAssemblyExtension, StringComparison.OrdinalIgnoreCase))
{
// Binary module (.dll)
Module.SetVersion(ClrFacade.GetAssemblyName(Module.Path).Version);
Module.SetVersion(AssemblyName.GetAssemblyName(Module.Path).Version);
}
}

View File

@ -1375,7 +1375,7 @@ namespace System.Management.Automation
try
{
loadedAssembly = ClrFacade.LoadFrom(filename);
loadedAssembly = Assembly.LoadFrom(filename);
return loadedAssembly;
}
catch (FileNotFoundException fileNotFound)

View File

@ -4467,7 +4467,7 @@ namespace System.Management.Automation.Runspaces
{
s_PSSnapInTracer.WriteLine("Loading assembly for psSnapIn {0}", fileName);
Assembly assembly = ClrFacade.LoadFrom(fileName);
Assembly assembly = Assembly.LoadFrom(fileName);
if (assembly == null)
{
s_PSSnapInTracer.TraceError("Loading assembly for psSnapIn {0} failed", fileName);
@ -5543,7 +5543,7 @@ if($paths) {
try
{
AssemblyName assemblyName = ClrFacade.GetAssemblyName(psSnapInInfo.AbsoluteModulePath);
AssemblyName assemblyName = AssemblyName.GetAssemblyName(psSnapInInfo.AbsoluteModulePath);
if (!string.Equals(assemblyName.FullName, psSnapInInfo.AssemblyName, StringComparison.OrdinalIgnoreCase))
{
@ -5552,7 +5552,7 @@ if($paths) {
throw new PSSnapInException(psSnapInInfo.Name, message);
}
assembly = ClrFacade.LoadFrom(psSnapInInfo.AbsoluteModulePath);
assembly = Assembly.LoadFrom(psSnapInInfo.AbsoluteModulePath);
}
catch (FileLoadException e)
{

View File

@ -175,7 +175,7 @@ namespace System.Management.Automation
try
{
p = ClrFacade.SecureStringToCoTaskMemUnicode(ss);
p = Marshal.SecureStringToCoTaskMemUnicode(ss);
s = Marshal.PtrToStringUni(p);
}
finally

View File

@ -217,8 +217,8 @@ namespace System.Management.Automation.Runspaces
finally
{
NestedPipelineExecutionThread = oldNestedPipelineThread;
ClrFacade.SetCurrentThreadCulture(oldCurrentCulture);
ClrFacade.SetCurrentThreadUiCulture(oldCurrentUICulture);
Thread.CurrentThread.CurrentCulture = oldCurrentCulture;
Thread.CurrentThread.CurrentUICulture = oldCurrentUICulture;
}
break;
}

View File

@ -2370,7 +2370,7 @@ namespace System.Management.Automation.Language
#endif
if (File.Exists(assemblyFileName))
{
assembly = ClrFacade.LoadFrom(assemblyFileName);
assembly = Assembly.LoadFrom(assemblyFileName);
}
}
catch

View File

@ -700,7 +700,7 @@ namespace System.Management.Automation.Remoting
//Rooted path of dll is provided.
assemblyPath = assemblyName;
}
result = ClrFacade.LoadFrom(assemblyPath);
result = Assembly.LoadFrom(assemblyPath);
}
catch (FileLoadException e)
{

View File

@ -348,7 +348,7 @@ namespace System.Management.Automation.Remoting.Client
_cred.userName = name;
if (null != pwd)
{
_cred.password = ClrFacade.SecureStringToCoTaskMemUnicode(pwd);
_cred.password = Marshal.SecureStringToCoTaskMemUnicode(pwd);
}
_data = MarshalledObject.Create<WSManUserNameCredentialStruct>(_cred);

View File

@ -383,7 +383,7 @@ namespace System.Management.Automation.Remoting
if (Platform.IsWindows)
{
SafeWaitHandle safeWaitHandle = new SafeWaitHandle(requestDetails.shutdownNotificationHandle, false); // Owned by WinRM
ClrFacade.SetSafeWaitHandle(eventWaitHandle, safeWaitHandle);
eventWaitHandle.SafeWaitHandle = safeWaitHandle;
}
else
{
@ -1496,7 +1496,7 @@ namespace System.Management.Automation.Remoting
if (retrievingLocaleSucceeded && ((uint)WSManNativeApi.WSManDataType.WSMAN_DATA_TYPE_TEXT == localeData.Type))
{
CultureInfo uiCultureToUse = new CultureInfo(localeData.Text);
ClrFacade.SetCurrentThreadUiCulture(uiCultureToUse);
Thread.CurrentThread.CurrentUICulture = uiCultureToUse;
}
}
// ignore if there is any exception constructing the culture..
@ -1510,7 +1510,7 @@ namespace System.Management.Automation.Remoting
if (retrievingDataLocaleSucceeded && ((uint)WSManNativeApi.WSManDataType.WSMAN_DATA_TYPE_TEXT == dataLocaleData.Type))
{
CultureInfo cultureToUse = new CultureInfo(dataLocaleData.Text);
ClrFacade.SetCurrentThreadCulture(cultureToUse);
Thread.CurrentThread.CurrentCulture = cultureToUse;
}
}
// ignore if there is any exception constructing the culture..

View File

@ -266,7 +266,7 @@ namespace System.Management.Automation.Remoting
// Wrap the provided handle so it can be passed to the registration function
SafeWaitHandle safeWaitHandle = new SafeWaitHandle(creationRequestDetails.shutdownNotificationHandle, false); // Owned by WinRM
EventWaitHandle eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
ClrFacade.SetSafeWaitHandle(eventWaitHandle, safeWaitHandle);
eventWaitHandle.SafeWaitHandle = safeWaitHandle;
// Register shutdown notification handle
this.registeredShutDownWaitHandle = ThreadPool.RegisterWaitForSingleObject(

View File

@ -337,7 +337,7 @@ namespace System.Management.Automation.Remoting
// Wrap the provided handle so it can be passed to the registration function
SafeWaitHandle safeWaitHandle = new SafeWaitHandle(requestDetails.shutdownNotificationHandle, false); // Owned by WinRM
EventWaitHandle eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
ClrFacade.SetSafeWaitHandle(eventWaitHandle, safeWaitHandle);
eventWaitHandle.SafeWaitHandle = safeWaitHandle;
_registeredShutDownWaitHandle = ThreadPool.RegisterWaitForSingleObject(
eventWaitHandle,

View File

@ -379,7 +379,7 @@ namespace Microsoft.PowerShell.Commands
destPaths.Add(module.ModuleBase);
#if !CORECLR // Side-By-Side directories are not present in OneCore environments.
if (IsSystemModule(module.ModuleName) && ClrFacade.Is64BitOperatingSystem())
if (IsSystemModule(module.ModuleName) && Environment.Is64BitOperatingSystem)
{
string path = Utils.GetApplicationBase(Utils.DefaultPowerShellShellID).Replace("System32", "SysWOW64");

View File

@ -246,7 +246,7 @@ namespace System.Management.Automation.Runspaces
if (assembly == null)
throw PSTraceSource.NewArgumentNullException("assembly");
object[] attributes = ClrFacade.GetCustomAttributes<RunspaceConfigurationTypeAttribute>(assembly);
object[] attributes = assembly.GetCustomAttributes(typeof(RunspaceConfigurationTypeAttribute), false);
if (attributes == null || attributes.Length == 0)
{

View File

@ -1345,9 +1345,6 @@ ModuleVersion : Version of module to import. If used, ModuleName must represent
<data name="CantActivateDocumentInPowerShellCore" xml:space="preserve">
<value>Cannot run a document in PowerShell Core: {0}.</value>
</data>
<data name="LoadContextNotInitialized" xml:space="preserve">
<value>'PowerShellAssemblyLoadContext' is not initialized.</value>
</data>
<data name="MultipleTypeConstraintsOnMethodParam" xml:space="preserve">
<value>Multiple type constraints are not allowed on a method parameter.</value>
</data>

View File

@ -85,7 +85,7 @@ namespace Microsoft.PowerShell
if (s.Length > 0)
{
IntPtr ptr = ClrFacade.SecureStringToCoTaskMemUnicode(s);
IntPtr ptr = Marshal.SecureStringToCoTaskMemUnicode(s);
try
{

View File

@ -1565,7 +1565,7 @@ namespace System.Management.Automation
{
var processModule = PsUtils.GetMainModule(currentProcess);
hostname = string.Concat("PowerShell_", processModule.FileName, "_",
ClrFacade.GetProcessModuleFileVersionInfo(processModule).ProductVersion);
processModule.FileVersionInfo.ProductVersion);
}
catch (ComponentModel.Win32Exception)
{

View File

@ -640,7 +640,7 @@ namespace System.Management.Automation.Runspaces
try
{
AssemblyName assemblyName = ClrFacade.GetAssemblyName(mshsnapinInfo.AbsoluteModulePath);
AssemblyName assemblyName = AssemblyName.GetAssemblyName(mshsnapinInfo.AbsoluteModulePath);
if (string.Compare(assemblyName.FullName, mshsnapinInfo.AssemblyName, StringComparison.OrdinalIgnoreCase) != 0)
{
string message = StringUtil.Format(ConsoleInfoErrorStrings.PSSnapInAssemblyNameMismatch, mshsnapinInfo.AbsoluteModulePath, mshsnapinInfo.AssemblyName);
@ -648,7 +648,7 @@ namespace System.Management.Automation.Runspaces
throw new PSSnapInException(mshsnapinInfo.Name, message);
}
assembly = ClrFacade.LoadFrom(mshsnapinInfo.AbsoluteModulePath);
assembly = Assembly.LoadFrom(mshsnapinInfo.AbsoluteModulePath);
}
catch (FileLoadException e)
{

View File

@ -10,7 +10,6 @@ using System.IO;
using System.Linq;
using System.Management.Automation.Language;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
@ -37,6 +36,18 @@ namespace System.Management.Automation
/// </summary>
internal static class ClrFacade
{
/// <summary>
/// Initialize powershell AssemblyLoadContext and register the 'Resolving' event, if it's not done already.
/// If powershell is hosted by a native host such as DSC, then PS ALC might be initialized via 'SetPowerShellAssemblyLoadContext' before loading S.M.A.
/// </summary>
static ClrFacade()
{
if (PowerShellAssemblyLoadContext.Instance == null)
{
PowerShellAssemblyLoadContext.InitializeSingleton(string.Empty);
}
}
/// <summary>
/// We need it to avoid calling lookups inside dynamic assemblies with PS Types, so we exclude it from GetAssemblies().
/// We use this convention for names to archive it.
@ -45,20 +56,6 @@ namespace System.Management.Automation
#region Process
/// <summary>
/// Facade for ProcessModule FileVersionInfo
/// </summary>
/// <param name="processModule"></param>
/// <returns>FileVersionInfo</returns>
internal static FileVersionInfo GetProcessModuleFileVersionInfo(ProcessModule processModule)
{
#if CORECLR
return FileVersionInfo.GetVersionInfo(processModule.FileName);
#else
return processModule.FileVersionInfo;
#endif
}
/// <summary>
/// Facade for Process.Handle to get SafeHandle
/// </summary>
@ -73,46 +70,6 @@ namespace System.Management.Automation
#endif
}
/// <summary>
/// Facade for Process.Handle to get raw handle
/// </summary>
internal static IntPtr GetRawProcessHandle(Process process)
{
#if CORECLR
try
{
return process.SafeHandle.DangerousGetHandle();
}
catch (InvalidOperationException)
{
// It's possible that the process has already exited when we try to get its handle.
// In that case, InvalidOperationException will be thrown from Process.SafeHandle,
// and we return the invalid zero pointer.
return IntPtr.Zero;
}
#else
return process.Handle;
#endif
}
#if CORECLR
/// <summary>
/// Facade for ProcessStartInfo.Environment
/// </summary>
internal static IDictionary<string, string> GetProcessEnvironment(ProcessStartInfo startInfo)
{
return startInfo.Environment;
}
#else
/// <summary>
/// Facade for ProcessStartInfo.EnvironmentVariables
/// </summary>
internal static System.Collections.Specialized.StringDictionary GetProcessEnvironment(ProcessStartInfo startInfo)
{
return startInfo.EnvironmentVariables;
}
#endif
#endregion Process
#region Marshal
@ -171,32 +128,9 @@ namespace System.Management.Automation
#endif
}
/// <summary>
/// Facade for SecureStringToCoTaskMemUnicode
/// </summary>
internal static IntPtr SecureStringToCoTaskMemUnicode(SecureString s)
{
#if CORECLR
return SecureStringMarshal.SecureStringToCoTaskMemUnicode(s);
#else
return Marshal.SecureStringToCoTaskMemUnicode(s);
#endif
}
#endregion Marshal
#region Assembly
/// <summary>
/// Facade for AssemblyName.GetAssemblyName(string)
/// </summary>
internal static AssemblyName GetAssemblyName(string assemblyPath)
{
#if CORECLR // AssemblyName.GetAssemblyName(assemblyPath) is not in CoreCLR
return AssemblyLoadContext.GetAssemblyName(assemblyPath);
#else
return AssemblyName.GetAssemblyName(assemblyPath);
#endif
}
internal static IEnumerable<Assembly> GetAssemblies(TypeResolutionState typeResolutionState, TypeName typeName)
{
@ -217,112 +151,29 @@ namespace System.Management.Automation
/// </param>
internal static IEnumerable<Assembly> GetAssemblies(string namespaceQualifiedTypeName = null)
{
return
#if CORECLR
return PSAssemblyLoadContext.GetAssemblies(namespaceQualifiedTypeName);
#else
return AppDomain.CurrentDomain.GetAssemblies().Where(a => !(a.FullName.Length > 0 && a.FullName[0] == FIRST_CHAR_PSASSEMBLY_MARK));
#endif
}
/// <summary>
/// Facade for Assembly.LoadFrom
/// </summary>
[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")]
internal static Assembly LoadFrom(string assemblyPath)
{
#if CORECLR
return PSAssemblyLoadContext.LoadFrom(assemblyPath);
#else
return Assembly.LoadFrom(assemblyPath);
#endif
}
/// <summary>
/// Facade for EnumBuilder.CreateTypeInfo
/// </summary>
/// <remarks>
/// In Core PowerShell, we need to track the dynamic assemblies that powershell generates.
/// </remarks>
internal static void CreateEnumType(EnumBuilder enumBuilder)
{
#if CORECLR
// Create the enum type and add the dynamic assembly to assembly cache.
TypeInfo enumTypeinfo = enumBuilder.CreateTypeInfo();
PSAssemblyLoadContext.TryAddAssemblyToCache(enumTypeinfo.Assembly);
#else
enumBuilder.CreateTypeInfo();
PSAssemblyLoadContext.GetAssembly(namespaceQualifiedTypeName) ??
#endif
AppDomain.CurrentDomain.GetAssemblies().Where(a => !(a.FullName.Length > 0 && a.FullName[0] == FIRST_CHAR_PSASSEMBLY_MARK));
}
#if CORECLR
/// <summary>
/// Probe (look for) the assembly file with the specified short name.
/// </summary>
/// <remarks>
/// In Core PowerShell, we need to analyze the metadata of assembly files for binary modules. Sometimes we
/// need to find an assembly file that is referenced by the assembly file that is being processed. To find
/// the reference assembly file, we need to probe the PSBase and the additional searching path if it's specified.
/// </remarks>
internal static string ProbeAssemblyPath(string assemblyShortName, string additionalSearchPath = null)
{
if (string.IsNullOrWhiteSpace(assemblyShortName))
{
throw new ArgumentNullException("assemblyShortName");
}
return PSAssemblyLoadContext.ProbeAssemblyFileForMetadataAnalysis(assemblyShortName, additionalSearchPath);
}
/// <summary>
/// Get the namespace-qualified type names of all available CoreCLR .NET types.
/// Get the namespace-qualified type names of all available .NET Core types shipped with PowerShell Core.
/// This is used for type name auto-completion in PS engine.
/// </summary>
internal static IEnumerable<string> GetAvailableCoreClrDotNetTypes()
{
return PSAssemblyLoadContext.GetAvailableDotNetTypes();
}
internal static IEnumerable<string> AvailableDotNetTypeNames => PSAssemblyLoadContext.AvailableDotNetTypeNames;
/// <summary>
/// Load assembly from byte stream.
/// Get the assembly names of all available .NET Core assemblies shipped with PowerShell Core.
/// This is used for type name auto-completion in PS engine.
/// </summary>
internal static Assembly LoadFrom(Stream assembly)
{
return PSAssemblyLoadContext.LoadFrom(assembly);
}
internal static HashSet<string> AvailableDotNetAssemblyNames => PSAssemblyLoadContext.AvailableDotNetAssemblyNames;
/// <summary>
/// Add the AssemblyLoad handler
/// </summary>
internal static void AddAssemblyLoadHandler(Action<Assembly> handler)
{
PSAssemblyLoadContext.AssemblyLoad += handler;
}
private static PowerShellAssemblyLoadContext PSAssemblyLoadContext
{
get
{
if (PowerShellAssemblyLoadContext.Instance == null)
{
throw new InvalidOperationException(ParserStrings.LoadContextNotInitialized);
}
return PowerShellAssemblyLoadContext.Instance;
}
}
private static PowerShellAssemblyLoadContext PSAssemblyLoadContext => PowerShellAssemblyLoadContext.Instance;
#endif
/// <summary>
/// Facade for Assembly.GetCustomAttributes
/// </summary>
internal static object[] GetCustomAttributes<T>(Assembly assembly)
{
#if CORECLR // Assembly.GetCustomAttributes(Type, Boolean) is not in CORE CLR
return assembly.GetCustomAttributes(typeof(T)).ToArray();
#else
return assembly.GetCustomAttributes(typeof(T), false);
#endif
}
#endregion Assembly
#region Encoding
@ -592,48 +443,6 @@ namespace System.Management.Automation
#endregion Security
#region Culture
/// <summary>
/// Facade for CultureInfo.GetCultureInfo(string).
/// </summary>
internal static CultureInfo GetCultureInfo(string cultureName)
{
#if CORECLR
return new CultureInfo(cultureName);
#else
return CultureInfo.GetCultureInfo(cultureName);
#endif
}
/// <summary>
/// Facade for setting CurrentCulture for the CurrentThread
/// </summary>
internal static void SetCurrentThreadCulture(CultureInfo cultureInfo)
{
#if CORECLR
CultureInfo.CurrentCulture = cultureInfo;
#else
// Setters for 'CultureInfo.CurrentCulture' is introduced in .NET 4.6
Thread.CurrentThread.CurrentCulture = cultureInfo;
#endif
}
/// <summary>
/// Facade for setting CurrentUICulture for the CurrentThread
/// </summary>
internal static void SetCurrentThreadUiCulture(CultureInfo uiCultureInfo)
{
#if CORECLR
CultureInfo.CurrentUICulture = uiCultureInfo;
#else
// Setters for 'CultureInfo.CurrentUICulture' is introduced in .NET 4.6
Thread.CurrentThread.CurrentUICulture = uiCultureInfo;
#endif
}
#endregion Culture
#region Misc
/// <summary>
@ -716,19 +525,6 @@ namespace System.Management.Automation
#endif
}
/// <summary>
/// Manual implementation of the is 64bit processor check
/// </summary>
/// <returns></returns>
internal static bool Is64BitOperatingSystem()
{
#if CORECLR
return (8 == IntPtr.Size); // Pointers are 8 bytes on 64-bit machines
#else
return Environment.Is64BitOperatingSystem;
#endif
}
/// <summary>
/// Facade for FormatterServices.GetUninitializedObject.
///
@ -768,20 +564,6 @@ namespace System.Management.Automation
#endif
}
/// <summary>
/// Facade for setting WaitHandle.SafeWaitHandle.
/// </summary>
/// <param name="waitHandle"></param>
/// <param name="value"></param>
internal static void SetSafeWaitHandle(WaitHandle waitHandle, SafeWaitHandle value)
{
#if CORECLR
waitHandle.SetSafeWaitHandle(value);
#else
waitHandle.SafeWaitHandle = value;
#endif
}
/// <summary>
/// Facade for ProfileOptimization.SetProfileRoot
/// </summary>

View File

@ -995,7 +995,7 @@ namespace System.Management.Automation.Internal
if (_rsaCryptoProvider.CanEncrypt)
{
IntPtr ptr = ClrFacade.SecureStringToCoTaskMemUnicode(secureString);
IntPtr ptr = Marshal.SecureStringToCoTaskMemUnicode(secureString);
if (ptr != IntPtr.Zero)
{

View File

@ -424,7 +424,7 @@ using System.Runtime.Loader;
namespace System.Management.Automation
{{
internal partial class PowerShellAssemblyLoadContext : AssemblyLoadContext
internal partial class PowerShellAssemblyLoadContext
{{
private Dictionary<string, string> InitializeTypeCatalog()
{{

View File

@ -3,7 +3,6 @@ Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Management.Automation;
using System.Reflection;
namespace Microsoft.PowerShell
@ -21,19 +20,7 @@ namespace Microsoft.PowerShell
/// </param>
public static int Main(string[] args)
{
#if CORECLR
// PowerShell has to set the ALC here, since we don't own the native host
string appBase = System.IO.Path.GetDirectoryName(typeof(ManagedPSEntry).GetTypeInfo().Assembly.Location);
return (int)PowerShellAssemblyLoadContextInitializer.
InitializeAndCallEntryMethod(
appBase,
new AssemblyName("Microsoft.PowerShell.ConsoleHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"),
"Microsoft.PowerShell.UnmanagedPSEntry",
"Start",
new object[] { string.Empty, args, args.Length });
#else
return UnmanagedPSEntry.Start(string.Empty, args, args.Length);
#endif
}
}
}