1 // 2 // Copyright (c) ZeroC, Inc. All rights reserved. 3 // 4 5 namespace IceInternal 6 { 7 using System; 8 using System.Runtime.InteropServices; 9 using System.Collections; 10 using System.Collections.Generic; 11 using System.Reflection; 12 13 public sealed class AssemblyUtil 14 { 15 #if NETSTANDARD2_0 16 public static readonly bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); 17 public static readonly bool isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); 18 public static readonly bool isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); 19 public static readonly bool isMono = RuntimeInformation.FrameworkDescription.Contains("Mono"); 20 #else 21 public static readonly bool isWindows = true; 22 public static readonly bool isMacOS = false; 23 public static readonly bool isLinux = false; 24 public static readonly bool isMono = false; 25 #endif findType(Instance instance, string csharpId)26 public static Type findType(Instance instance, string csharpId) 27 { 28 lock(_mutex) 29 { 30 Type t; 31 if (_typeTable.TryGetValue(csharpId, out t)) 32 { 33 return t; 34 } 35 36 loadAssemblies(); // Lazy initialization 37 foreach (Assembly a in _loadedAssemblies.Values) 38 { 39 if((t = a.GetType(csharpId)) != null) 40 { 41 _typeTable[csharpId] = t; 42 return t; 43 } 44 } 45 } 46 return null; 47 } 48 findTypesWithPrefix(string prefix)49 public static Type[] findTypesWithPrefix(string prefix) 50 { 51 LinkedList<Type> l = new LinkedList<Type>(); 52 53 lock(_mutex) 54 { 55 loadAssemblies(); // Lazy initialization 56 foreach(Assembly a in _loadedAssemblies.Values) 57 { 58 try 59 { 60 Type[] types = a.GetTypes(); 61 foreach(Type t in types) 62 { 63 if(t.AssemblyQualifiedName.IndexOf(prefix, StringComparison.Ordinal) == 0) 64 { 65 l.AddLast(t); 66 } 67 } 68 } 69 catch(ReflectionTypeLoadException) 70 { 71 // Failed to load types from the assembly, ignore and continue 72 } 73 } 74 } 75 76 Type[] result = new Type[l.Count]; 77 if(l.Count > 0) 78 { 79 l.CopyTo(result, 0); 80 } 81 return result; 82 } 83 createInstance(Type t)84 public static object createInstance(Type t) 85 { 86 try 87 { 88 return Activator.CreateInstance(t); 89 } 90 catch(MemberAccessException) 91 { 92 return null; 93 } 94 } 95 preloadAssemblies()96 public static void preloadAssemblies() 97 { 98 lock(_mutex) 99 { 100 loadAssemblies(); // Lazy initialization 101 } 102 } 103 104 // 105 // Make sure that all assemblies that are referenced by this process 106 // are actually loaded. This is necessary so we can use reflection 107 // on any type in any assembly because the type we are after will 108 // most likely not be in the current assembly and, worse, may be 109 // in an assembly that has not been loaded yet. (Type.GetType() 110 // is no good because it looks only in the calling object's assembly 111 // and mscorlib.dll.) 112 // loadAssemblies()113 private static void loadAssemblies() 114 { 115 Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); 116 List<Assembly> newAssemblies = null; 117 foreach(Assembly a in assemblies) 118 { 119 if(!_loadedAssemblies.Contains(a.FullName)) 120 { 121 if(newAssemblies == null) 122 { 123 newAssemblies = new List<Assembly>(); 124 } 125 newAssemblies.Add(a); 126 _loadedAssemblies[a.FullName] = a; 127 } 128 } 129 if(newAssemblies != null) 130 { 131 foreach(Assembly a in newAssemblies) 132 { 133 loadReferencedAssemblies(a); 134 } 135 } 136 } 137 loadReferencedAssemblies(Assembly a)138 private static void loadReferencedAssemblies(Assembly a) 139 { 140 try 141 { 142 AssemblyName[] names = a.GetReferencedAssemblies(); 143 foreach(AssemblyName name in names) 144 { 145 if(!_loadedAssemblies.ContainsKey(name.FullName)) 146 { 147 try 148 { 149 Assembly ra = Assembly.Load(name); 150 // 151 // The value of name.FullName may not match that of ra.FullName, so 152 // we record the assembly using both keys. 153 // 154 _loadedAssemblies[name.FullName] = ra; 155 _loadedAssemblies[ra.FullName] = ra; 156 loadReferencedAssemblies(ra); 157 } 158 catch(Exception) 159 { 160 // Ignore assemblies that cannot be loaded. 161 } 162 } 163 } 164 } 165 catch(PlatformNotSupportedException) 166 { 167 // Some platforms like UWP do not support using GetReferencedAssemblies 168 } 169 } 170 171 private static Hashtable _loadedAssemblies = new Hashtable(); // <string, Assembly> pairs. 172 private static Dictionary<string, Type> _typeTable = new Dictionary<string, Type>(); // <type name, Type> pairs. 173 private static object _mutex = new object(); 174 } 175 } 176