1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using CultureInfo = System.Globalization.CultureInfo;
10 using StringBuilder = System.Text.StringBuilder;
11 using System.Configuration.Assemblies;
12 using StackCrawlMark = System.Threading.StackCrawlMark;
13 using System.Runtime.InteropServices;
14 using System.Runtime.CompilerServices;
15 using System.Runtime.Serialization;
16 using System.Threading;
18 namespace System.Reflection
20 internal class RuntimeAssembly : Assembly
22 internal RuntimeAssembly() { throw new NotSupportedException(); }
24 #region private data members
25 private event ModuleResolveEventHandler _ModuleResolve;
26 private string m_fullname;
27 private object m_syncRoot; // Used to keep collectible types alive and as the syncroot for reflection.emit
28 private IntPtr m_assembly; // slack for ptr datum on unmanaged side
32 internal object SyncRoot
36 if (m_syncRoot == null)
38 Interlocked.CompareExchange<object>(ref m_syncRoot, new object(), null);
44 public override event ModuleResolveEventHandler ModuleResolve
48 _ModuleResolve += value;
52 _ModuleResolve -= value;
56 private const string s_localFilePrefix = "file:";
58 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
59 private static extern void GetCodeBase(RuntimeAssembly assembly,
61 StringHandleOnStack retString);
63 internal string GetCodeBase(bool copiedName)
65 string codeBase = null;
66 GetCodeBase(GetNativeHandle(), copiedName, JitHelpers.GetStringHandleOnStack(ref codeBase));
70 public override string CodeBase => GetCodeBase(false);
72 internal RuntimeAssembly GetNativeHandle() => this;
74 // If the assembly is copied before it is loaded, the codebase will be set to the
75 // actual file loaded if copiedName is true. If it is false, then the original code base
77 public override AssemblyName GetName(bool copiedName)
79 AssemblyName an = new AssemblyName();
81 string codeBase = GetCodeBase(copiedName);
83 an.Init(GetSimpleName(),
85 null, // public key token
89 AssemblyVersionCompatibility.SameMachine,
91 GetFlags() | AssemblyNameFlags.PublicKey,
92 null); // strong name key pair
94 Module manifestModule = ManifestModule;
95 if (manifestModule != null)
97 if (manifestModule.MDStreamVersion > 0x10000)
99 ManifestModule.GetPEKind(out PortableExecutableKinds pek, out ImageFileMachine ifm);
100 an.SetProcArchIndex(pek, ifm);
106 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
107 private static extern void GetFullName(RuntimeAssembly assembly, StringHandleOnStack retString);
109 public override string FullName
113 // If called by Object.ToString(), return val may be NULL.
114 if (m_fullname == null)
117 GetFullName(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref s));
118 Interlocked.CompareExchange<string>(ref m_fullname, s, null);
125 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
126 private static extern void GetEntryPoint(RuntimeAssembly assembly, ObjectHandleOnStack retMethod);
128 public override MethodInfo EntryPoint
132 IRuntimeMethodInfo methodHandle = null;
133 GetEntryPoint(GetNativeHandle(), JitHelpers.GetObjectHandleOnStack(ref methodHandle));
135 if (methodHandle == null)
138 return (MethodInfo)RuntimeType.GetMethodBase(methodHandle);
142 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
143 private static extern void GetType(RuntimeAssembly assembly,
147 ObjectHandleOnStack type,
148 ObjectHandleOnStack keepAlive);
150 public override Type GetType(string name, bool throwOnError, bool ignoreCase)
152 // throw on null strings regardless of the value of "throwOnError"
154 throw new ArgumentNullException(nameof(name));
156 RuntimeType type = null;
157 object keepAlive = null;
158 GetType(GetNativeHandle(), name, throwOnError, ignoreCase, JitHelpers.GetObjectHandleOnStack(ref type), JitHelpers.GetObjectHandleOnStack(ref keepAlive));
159 GC.KeepAlive(keepAlive);
164 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
165 private static extern void GetExportedTypes(RuntimeAssembly assembly, ObjectHandleOnStack retTypes);
167 public override Type[] GetExportedTypes()
170 GetExportedTypes(GetNativeHandle(), JitHelpers.GetObjectHandleOnStack(ref types));
174 public override IEnumerable<TypeInfo> DefinedTypes
178 RuntimeModule[] modules = GetModulesInternal(true, false);
179 if (modules.Length == 1)
181 return modules[0].GetDefinedTypes();
184 List<RuntimeType> rtTypes = new List<RuntimeType>();
186 for (int i = 0; i < modules.Length; i++)
188 rtTypes.AddRange(modules[i].GetDefinedTypes());
191 return rtTypes.ToArray();
195 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
196 [return: MarshalAs(UnmanagedType.Bool)]
197 internal static extern bool GetIsCollectible(RuntimeAssembly assembly);
199 public override bool IsCollectible => GetIsCollectible(GetNativeHandle());
201 // GetResource will return a pointer to the resources in memory.
202 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
203 private static extern unsafe byte* GetResource(RuntimeAssembly assembly,
207 // Load a resource based on the NameSpace of the type.
208 public override Stream GetManifestResourceStream(Type type, string name)
210 if (type == null && name == null)
211 throw new ArgumentNullException(nameof(type));
213 string nameSpace = type?.Namespace;
215 char c = Type.Delimiter;
216 string resourceName = nameSpace != null && name != null ?
217 string.Concat(nameSpace, new ReadOnlySpan<char>(ref c, 1), name) :
218 string.Concat(nameSpace, name);
220 return GetManifestResourceStream(resourceName);
223 public unsafe override Stream GetManifestResourceStream(string name)
226 byte* pbInMemoryResource = GetResource(GetNativeHandle(), name, out length);
228 if (pbInMemoryResource != null)
230 return new UnmanagedMemoryStream(pbInMemoryResource, length, length, FileAccess.Read);
236 // ISerializable implementation
237 public override void GetObjectData(SerializationInfo info, StreamingContext context)
239 throw new PlatformNotSupportedException();
242 public override Module ManifestModule
246 // We don't need to return the "external" ModuleBuilder because
247 // it is meant to be read-only
248 return RuntimeAssembly.GetManifestModule(GetNativeHandle());
252 public override object[] GetCustomAttributes(bool inherit)
254 return CustomAttribute.GetCustomAttributes(this, typeof(object) as RuntimeType);
257 public override object[] GetCustomAttributes(Type attributeType, bool inherit)
259 if (attributeType == null)
260 throw new ArgumentNullException(nameof(attributeType));
262 RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType;
264 if (attributeRuntimeType == null)
265 throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType));
267 return CustomAttribute.GetCustomAttributes(this, attributeRuntimeType);
270 public override bool IsDefined(Type attributeType, bool inherit)
272 if (attributeType == null)
273 throw new ArgumentNullException(nameof(attributeType));
275 RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType;
277 if (attributeRuntimeType == null)
278 throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType));
280 return CustomAttribute.IsDefined(this, attributeRuntimeType);
283 public override IList<CustomAttributeData> GetCustomAttributesData()
285 return CustomAttributeData.GetCustomAttributesInternal(this);
288 internal static RuntimeAssembly InternalLoad(string assemblyString, ref StackCrawlMark stackMark)
290 RuntimeAssembly assembly;
291 AssemblyName an = CreateAssemblyName(assemblyString, out assembly);
293 if (assembly != null)
295 // The assembly was returned from ResolveAssemblyEvent
299 return InternalLoadAssemblyName(an, ref stackMark);
302 // Creates AssemblyName. Fills assembly if AssemblyResolve event has been raised.
303 internal static AssemblyName CreateAssemblyName(
304 string assemblyString,
305 out RuntimeAssembly assemblyFromResolveEvent)
307 if (assemblyString == null)
308 throw new ArgumentNullException(nameof(assemblyString));
310 if ((assemblyString.Length == 0) ||
311 (assemblyString[0] == '\0'))
312 throw new ArgumentException(SR.Format_StringZeroLength);
314 AssemblyName an = new AssemblyName();
316 an.Name = assemblyString;
317 an.nInit(out assemblyFromResolveEvent, true);
322 internal static RuntimeAssembly InternalLoadAssemblyName(AssemblyName assemblyRef, ref StackCrawlMark stackMark, IntPtr ptrLoadContextBinder = default)
325 if (ApplicationModel.IsUap)
327 if (assemblyRef.CodeBase != null)
329 throw new NotSupportedException(SR.Format(SR.NotSupported_AppX, "Assembly.LoadFrom"));
334 assemblyRef = (AssemblyName)assemblyRef.Clone();
335 if (assemblyRef.ProcessorArchitecture != ProcessorArchitecture.None)
337 // PA does not have a semantics for by-name binds for execution
338 assemblyRef.ProcessorArchitecture = ProcessorArchitecture.None;
341 string codeBase = VerifyCodeBase(assemblyRef.CodeBase);
343 return nLoad(assemblyRef, codeBase, null, ref stackMark, true, ptrLoadContextBinder);
346 [MethodImplAttribute(MethodImplOptions.InternalCall)]
347 private static extern RuntimeAssembly nLoad(AssemblyName fileName,
349 RuntimeAssembly assemblyContext,
350 ref StackCrawlMark stackMark,
351 bool throwOnFileNotFound,
352 IntPtr ptrLoadContextBinder);
354 public override bool ReflectionOnly
362 // Returns the module in this assembly with name 'name'
364 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
365 private static extern void GetModule(RuntimeAssembly assembly, string name, ObjectHandleOnStack retModule);
367 public override Module GetModule(string name)
369 Module retModule = null;
370 GetModule(GetNativeHandle(), name, JitHelpers.GetObjectHandleOnStack(ref retModule));
374 // Returns the file in the File table of the manifest that matches the
375 // given name. (Name should not include path.)
376 public override FileStream GetFile(string name)
378 RuntimeModule m = (RuntimeModule)GetModule(name);
382 return new FileStream(m.GetFullyQualifiedName(),
384 FileAccess.Read, FileShare.Read, FileStream.DefaultBufferSize, false);
387 public override FileStream[] GetFiles(bool getResourceModules)
389 Module[] m = GetModules(getResourceModules);
390 FileStream[] fs = new FileStream[m.Length];
392 for (int i = 0; i < fs.Length; i++)
394 fs[i] = new FileStream(((RuntimeModule)m[i]).GetFullyQualifiedName(),
396 FileAccess.Read, FileShare.Read, FileStream.DefaultBufferSize, false);
402 // Returns the names of all the resources
403 [MethodImplAttribute(MethodImplOptions.InternalCall)]
404 private static extern string[] GetManifestResourceNames(RuntimeAssembly assembly);
406 // Returns the names of all the resources
407 public override string[] GetManifestResourceNames()
409 return GetManifestResourceNames(GetNativeHandle());
412 // Returns the names of all the resources
413 [MethodImplAttribute(MethodImplOptions.InternalCall)]
414 private static extern AssemblyName[] GetReferencedAssemblies(RuntimeAssembly assembly);
416 public override AssemblyName[] GetReferencedAssemblies()
418 return GetReferencedAssemblies(GetNativeHandle());
421 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
422 private static extern int GetManifestResourceInfo(RuntimeAssembly assembly,
424 ObjectHandleOnStack assemblyRef,
425 StringHandleOnStack retFileName);
427 public override ManifestResourceInfo GetManifestResourceInfo(string resourceName)
429 RuntimeAssembly retAssembly = null;
430 string fileName = null;
431 int location = GetManifestResourceInfo(GetNativeHandle(), resourceName,
432 JitHelpers.GetObjectHandleOnStack(ref retAssembly),
433 JitHelpers.GetStringHandleOnStack(ref fileName));
438 return new ManifestResourceInfo(retAssembly, fileName,
439 (ResourceLocation)location);
442 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
443 private static extern void GetLocation(RuntimeAssembly assembly, StringHandleOnStack retString);
445 public override string Location
449 string location = null;
451 GetLocation(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref location));
457 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
458 private static extern void GetImageRuntimeVersion(RuntimeAssembly assembly, StringHandleOnStack retString);
460 public override string ImageRuntimeVersion
465 GetImageRuntimeVersion(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref s));
470 public override bool GlobalAssemblyCache
478 public override long HostContext
486 private static string VerifyCodeBase(string codebase)
488 if (codebase == null)
491 int len = codebase.Length;
496 int j = codebase.IndexOf(':');
497 // Check to see if the url has a prefix
500 ((codebase[j + 1] == '/') || (codebase[j + 1] == '\\')) &&
501 ((codebase[j + 2] == '/') || (codebase[j + 2] == '\\')))
504 else if ((len > 2) && (codebase[0] == '\\') && (codebase[1] == '\\'))
505 return "file://" + codebase;
507 return "file:///" + Path.GetFullPath(codebase);
510 return "file://" + Path.GetFullPath(codebase);
511 #endif // PLATFORM_WINDOWS
514 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
515 private static extern void GetVersion(RuntimeAssembly assembly,
521 internal Version GetVersion()
523 int majorVer, minorVer, build, revision;
524 GetVersion(GetNativeHandle(), out majorVer, out minorVer, out build, out revision);
525 return new Version(majorVer, minorVer, build, revision);
528 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
529 private static extern void GetLocale(RuntimeAssembly assembly, StringHandleOnStack retString);
531 internal CultureInfo GetLocale()
533 string locale = null;
535 GetLocale(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref locale));
538 return CultureInfo.InvariantCulture;
540 return new CultureInfo(locale);
543 [MethodImplAttribute(MethodImplOptions.InternalCall)]
544 private static extern bool FCallIsDynamic(RuntimeAssembly assembly);
546 public override bool IsDynamic
550 return FCallIsDynamic(GetNativeHandle());
554 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
555 private static extern void GetSimpleName(RuntimeAssembly assembly, StringHandleOnStack retSimpleName);
557 internal string GetSimpleName()
560 GetSimpleName(GetNativeHandle(), JitHelpers.GetStringHandleOnStack(ref name));
564 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
565 private static extern AssemblyHashAlgorithm GetHashAlgorithm(RuntimeAssembly assembly);
567 private AssemblyHashAlgorithm GetHashAlgorithm()
569 return GetHashAlgorithm(GetNativeHandle());
572 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
573 private static extern AssemblyNameFlags GetFlags(RuntimeAssembly assembly);
575 private AssemblyNameFlags GetFlags()
577 return GetFlags(GetNativeHandle());
580 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
581 private static extern void GetPublicKey(RuntimeAssembly assembly, ObjectHandleOnStack retPublicKey);
583 internal byte[] GetPublicKey()
585 byte[] publicKey = null;
586 GetPublicKey(GetNativeHandle(), JitHelpers.GetObjectHandleOnStack(ref publicKey));
590 // This method is called by the VM.
591 private RuntimeModule OnModuleResolveEvent(string moduleName)
593 ModuleResolveEventHandler moduleResolve = _ModuleResolve;
594 if (moduleResolve == null)
597 foreach (ModuleResolveEventHandler handler in moduleResolve.GetInvocationList())
599 RuntimeModule ret = (RuntimeModule)handler(this, new ResolveEventArgs(moduleName, this));
607 public override Assembly GetSatelliteAssembly(CultureInfo culture)
609 return GetSatelliteAssembly(culture, null);
612 // Useful for binding to a very specific version of a satellite assembly
613 public override Assembly GetSatelliteAssembly(CultureInfo culture, Version version)
616 throw new ArgumentNullException(nameof(culture));
618 return InternalGetSatelliteAssembly(culture, version, true);
621 [System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
622 internal Assembly InternalGetSatelliteAssembly(CultureInfo culture,
624 bool throwOnFileNotFound)
626 AssemblyName an = new AssemblyName();
628 an.SetPublicKey(GetPublicKey());
629 an.Flags = GetFlags() | AssemblyNameFlags.PublicKey;
632 an.Version = GetVersion();
634 an.Version = version;
636 an.CultureInfo = culture;
637 an.Name = GetSimpleName() + ".resources";
639 // This stack crawl mark is never used because the requesting assembly is explicitly specified,
640 // so the value could be anything.
641 StackCrawlMark unused = default;
642 RuntimeAssembly retAssembly = nLoad(an, null, this, ref unused, throwOnFileNotFound, IntPtr.Zero);
644 if (retAssembly == this)
649 if (retAssembly == null && throwOnFileNotFound)
651 throw new FileNotFoundException(string.Format(culture, SR.IO_FileNotFound_FileName, an.Name));
657 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
658 private static extern void GetModules(RuntimeAssembly assembly,
660 bool getResourceModules,
661 ObjectHandleOnStack retModuleHandles);
663 private RuntimeModule[] GetModulesInternal(bool loadIfNotFound,
664 bool getResourceModules)
666 RuntimeModule[] modules = null;
667 GetModules(GetNativeHandle(), loadIfNotFound, getResourceModules, JitHelpers.GetObjectHandleOnStack(ref modules));
671 public override Module[] GetModules(bool getResourceModules)
673 return GetModulesInternal(true, getResourceModules);
676 public override Module[] GetLoadedModules(bool getResourceModules)
678 return GetModulesInternal(false, getResourceModules);
681 [MethodImplAttribute(MethodImplOptions.InternalCall)]
682 internal static extern RuntimeModule GetManifestModule(RuntimeAssembly assembly);
684 [MethodImplAttribute(MethodImplOptions.InternalCall)]
685 internal static extern int GetToken(RuntimeAssembly assembly);
687 public sealed override Type[] GetForwardedTypes()
689 List<Type> types = new List<Type>();
690 List<Exception> exceptions = new List<Exception>();
692 MetadataImport scope = GetManifestModule(GetNativeHandle()).MetadataImport;
693 scope.Enum(MetadataTokenType.ExportedType, 0, out MetadataEnumResult enumResult);
694 for (int i = 0; i < enumResult.Length; i++)
696 MetadataToken mdtExternalType = enumResult[i];
698 Exception exception = null;
699 ObjectHandleOnStack pType = JitHelpers.GetObjectHandleOnStack(ref type);
702 GetForwardedType(this, mdtExternalType, pType);
704 continue; // mdtExternalType was not a forwarder entry.
712 Debug.Assert((type != null) != (exception != null)); // Exactly one of these must be non-null.
717 AddPublicNestedTypes(type, types, exceptions);
721 exceptions.Add(exception);
725 if (exceptions.Count != 0)
727 int numTypes = types.Count;
728 int numExceptions = exceptions.Count;
729 types.AddRange(new Type[numExceptions]); // add one null Type for each exception.
730 exceptions.InsertRange(0, new Exception[numTypes]); // align the Exceptions with the null Types.
731 throw new ReflectionTypeLoadException(types.ToArray(), exceptions.ToArray());
734 return types.ToArray();
737 private static void AddPublicNestedTypes(Type type, List<Type> types, List<Exception> exceptions)
742 nestedTypes = type.GetNestedTypes(BindingFlags.Public);
749 foreach (Type nestedType in nestedTypes)
751 types.Add(nestedType);
752 AddPublicNestedTypes(nestedType, types, exceptions);
756 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
757 private static extern void GetForwardedType(RuntimeAssembly assembly, MetadataToken mdtExternalType, ObjectHandleOnStack type);