// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Diagnostics; using System.Globalization; using System.Reflection; namespace Roslyn.Utilities { /// /// This type contains the light up scenarios for various platform and runtimes. Any function /// in this type can, and is expected to, fail on various platforms. These are light up scenarios /// only. /// internal static class CorLightup { internal static class Desktop { private static class _CultureInfo { internal static readonly Type Type = typeof(CultureInfo); internal static readonly PropertyInfo CultureTypes = Type .GetTypeInfo() .GetDeclaredProperty(nameof(CultureTypes)); } private static class CultureTypes { internal const int UserCustomCulture = 8; } internal static bool? IsUserCustomCulture(CultureInfo cultureInfo) { if (_CultureInfo.CultureTypes == null) { return null; } try { var value = (int)_CultureInfo.CultureTypes.GetValue(cultureInfo); return (value & CultureTypes.UserCustomCulture) != 0; } catch (Exception ex) { Debug.Assert(false, ex.Message); return null; } } private static class _Assembly { internal static readonly Type Type = typeof(Assembly); internal static readonly Func Load_bytes = Type .GetTypeInfo() .GetDeclaredMethod("Load", typeof(byte[])) .CreateDelegate>(); internal static readonly Func LoadFile = Type .GetTypeInfo() .GetDeclaredMethod("LoadFile", typeof(string)) .CreateDelegate>(); internal static readonly Func get_Location = Type .GetTypeInfo() .GetDeclaredMethod("get_Location") .CreateDelegate>(); internal static readonly Func get_GlobalAssemblyCache = Type .GetTypeInfo() .GetDeclaredMethod("get_GlobalAssemblyCache") .CreateDelegate>(); } private static class _Module { internal static readonly Type Type = typeof(Module); internal static readonly Func get_ModuleVersionId = Type .GetTypeInfo() .GetDeclaredMethod("get_ModuleVersionId") .CreateDelegate>(); } private static class _ResolveEventArgs { internal static readonly Type Type = ReflectionUtilities.TryGetType("System.ResolveEventArgs"); internal static readonly MethodInfo get_Name = Type .GetTypeInfo() .GetDeclaredMethod("get_Name"); internal static readonly MethodInfo get_RequestingAssembly = Type .GetTypeInfo() .GetDeclaredMethod("get_RequestingAssembly"); } private static class _AppDomain { internal static readonly Type Type = ReflectionUtilities.TryGetType("System.AppDomain"); internal static readonly Type ResolveEventHandlerType = ReflectionUtilities.TryGetType("System.ResolveEventHandler"); internal static readonly MethodInfo get_CurrentDomain = Type .GetTypeInfo() .GetDeclaredMethod("get_CurrentDomain"); internal static readonly MethodInfo add_AssemblyResolve = Type .GetTypeInfo() .GetDeclaredMethod("add_AssemblyResolve", ResolveEventHandlerType); internal static readonly MethodInfo remove_AssemblyResolve = Type .GetTypeInfo() .GetDeclaredMethod("remove_AssemblyResolve", ResolveEventHandlerType); } internal static Assembly LoadAssembly(byte[] peImage) { if (_Assembly.Load_bytes == null) { throw new PlatformNotSupportedException(); } return _Assembly.Load_bytes(peImage); } internal static Assembly LoadAssembly(string path) { if (_Assembly.LoadFile == null) { throw new PlatformNotSupportedException(); } return _Assembly.LoadFile(path); } internal static string GetAssemblyLocation(Assembly assembly) { if (_Assembly.get_Location == null) { throw new PlatformNotSupportedException(); } return _Assembly.get_Location(assembly); } internal static Guid GetModuleVersionId(Module module) { return _Module.get_ModuleVersionId(module); } internal static bool IsAssemblyFromGlobalAssemblyCache(Assembly assembly) { if (_Assembly.get_GlobalAssemblyCache == null) { throw new PlatformNotSupportedException(); } return _Assembly.get_GlobalAssemblyCache(assembly); } private sealed class AssemblyResolveWrapper { private readonly Func _handler; private static readonly MethodInfo s_stubInfo = typeof(AssemblyResolveWrapper).GetTypeInfo().GetDeclaredMethod("Stub"); public AssemblyResolveWrapper(Func handler) { _handler = handler; } private Assembly Stub(object sender, object resolveEventArgs) { var name = (string)_ResolveEventArgs.get_Name.Invoke(resolveEventArgs, Array.Empty()); var requestingAssembly = (Assembly)_ResolveEventArgs.get_RequestingAssembly.Invoke(resolveEventArgs, Array.Empty()); return _handler(name, requestingAssembly); } public object GetHandler() { return s_stubInfo.CreateDelegate(_AppDomain.ResolveEventHandlerType, this); } } internal static object GetCurrentAppDomain() { if (_AppDomain.get_CurrentDomain == null || _AppDomain.add_AssemblyResolve == null || _ResolveEventArgs.get_Name == null || _ResolveEventArgs.get_RequestingAssembly == null) { throw new PlatformNotSupportedException(); } return _AppDomain.get_CurrentDomain.Invoke(null, Array.Empty()); } internal static void GetOrRemoveAssemblyResolveHandler(Func handler, MethodInfo handlerOperation) { if (_AppDomain.add_AssemblyResolve == null) { throw new PlatformNotSupportedException(); } object currentAppDomain = GetCurrentAppDomain(); object resolveEventHandler = new AssemblyResolveWrapper(handler).GetHandler(); handlerOperation.Invoke(currentAppDomain, new[] { resolveEventHandler }); } internal static void AddAssemblyResolveHandler(Func handler) { GetOrRemoveAssemblyResolveHandler(handler, _AppDomain.add_AssemblyResolve); } internal static void RemoveAssemblyResolveHandler(Func handler) { GetOrRemoveAssemblyResolveHandler(handler, _AppDomain.remove_AssemblyResolve); } } } }