internal static PortableExecutableReference CreateFromFile( Stream peStream, string path, MetadataReferenceProperties properties = default, DocumentationProvider?documentation = null ) { // prefetch image, close stream to avoid locking it: var module = ModuleMetadata.CreateFromStream( peStream, PEStreamOptions.PrefetchEntireImage ); if (properties.Kind == MetadataImageKind.Module) { return(new MetadataImageReference( module, properties, documentation, path, display: null )); } // any additional modules constituting the assembly will be read lazily: var assemblyMetadata = AssemblyMetadata.CreateFromFile(module, path); return(new MetadataImageReference( assemblyMetadata, properties, documentation, path, display: null )); }
/// <summary> /// Gets or creates metadata for specified file path. /// </summary> /// <param name="fullPath">Full path to an assembly manifest module file or a standalone module file.</param> /// <param name="kind">Metadata kind (assembly or module).</param> /// <returns>Metadata for the specified file.</returns> /// <exception cref="IOException">Error reading file <paramref name="fullPath"/>. See <see cref="Exception.InnerException"/> for details.</exception> public Metadata GetMetadata(string fullPath, MetadataImageKind kind) { if (NeedsShadowCopy(fullPath)) { return(GetMetadataShadowCopyNoCheck(fullPath, kind).Metadata); } FileKey key = FileKey.Create(fullPath); lock (Guard) { CacheEntry <Metadata> existing; if (_noShadowCopyCache.TryGetValue(key, out existing)) { return(existing.Public); } } Metadata newMetadata; if (kind == MetadataImageKind.Assembly) { newMetadata = AssemblyMetadata.CreateFromFile(fullPath); } else { newMetadata = ModuleMetadata.CreateFromFile(fullPath); } // the files are locked (memory mapped) now key = FileKey.Create(fullPath); lock (Guard) { CacheEntry <Metadata> existing; if (_noShadowCopyCache.TryGetValue(key, out existing)) { newMetadata.Dispose(); return(existing.Public); } Metadata publicMetadata = newMetadata.Copy(); _noShadowCopyCache.Add(key, new CacheEntry <Metadata>(publicMetadata, newMetadata)); return(publicMetadata); } }
/// <exception cref="IOException"/> private static AssemblyMetadata GetOrCreateAssemblyFromFile(string fullPath) { AssemblyMetadata assembly = null; // may throw: FileKey key = FileKey.Create(fullPath); CachedAssembly cachedAssembly; bool existingKey = assembliesFromFiles.TryGetValue(key, out cachedAssembly); if (existingKey && cachedAssembly.Metadata.TryGetTarget(out assembly)) { return(assembly); } // memory-map all modules of the assembly: assembly = AssemblyMetadata.CreateFromFile(fullPath); // refresh the timestamp (the file may have changed just before we memory-mapped it): bool fault = true; try { key = FileKey.Create(fullPath); fault = false; } finally { if (fault) { assembly.Dispose(); } } cachedAssembly = new CachedAssembly(assembly); assembliesFromFiles[key] = cachedAssembly; if (!existingKey) { assemblyKeys.Add(key); EnableCompactTimer(); } return(assembly); }
/// <summary> /// Creates a reference to an assembly or standalone module stored in a file. /// Reads the content of the file into memory. /// </summary> /// <param name="path">Path to the assembly file.</param> /// <param name="properties">Reference properties (extern aliases, type embedding, <see cref="MetadataImageKind"/>).</param> /// <param name="documentation">Provides XML documentation for symbol found in the reference.</param> /// <exception cref="ArgumentNullException"><paramref name="path"/> is null.</exception> /// <exception cref="ArgumentException"><paramref name="path"/> is invalid.</exception> /// <exception cref="IOException">An error occurred while reading the file.</exception> /// <remarks> /// Performance considerations: /// <para> /// It is recommended to use <see cref="AssemblyMetadata.CreateFromFile(string)"/> or <see cref="ModuleMetadata.CreateFromFile(string)"/> /// API when creating multiple references to the same file. /// Reusing <see cref="Metadata"/> object allows for sharing data across these references. /// </para> /// <para> /// The method eagerly reads the entire content of the file into native heap. The native memory block is released /// when the resulting reference becomes unreachable and GC collects it. To decrease memory footprint of the reference and/or manage /// the lifetime deterministically use <see cref="AssemblyMetadata.CreateFromFile(string)"/> /// to create an <see cref="IDisposable"/> metadata object and /// <see cref="AssemblyMetadata.GetReference(DocumentationProvider, ImmutableArray{string}, bool, string, string)"/> /// to get a reference to it. /// </para> /// </remarks> public static PortableExecutableReference CreateFromFile( string path, MetadataReferenceProperties properties = default(MetadataReferenceProperties), DocumentationProvider documentation = null) { var peStream = FileUtilities.OpenFileStream(path); // prefetch image, close stream to avoid locking it: var module = ModuleMetadata.CreateFromStream(peStream, PEStreamOptions.PrefetchEntireImage); if (properties.Kind == MetadataImageKind.Module) { return(module.GetReference(documentation, path)); } // any additional modules constituting the assembly will be read lazily: var assemblyMetadata = AssemblyMetadata.CreateFromFile(module, path); return(assemblyMetadata.GetReference(documentation, properties.Aliases, properties.EmbedInteropTypes, path)); }