diff --git a/ILSpy/AssemblyList.cs b/ILSpy/AssemblyList.cs
index 8a7fc5add..caa7f8ae3 100644
--- a/ILSpy/AssemblyList.cs
+++ b/ILSpy/AssemblyList.cs
@@ -38,9 +38,10 @@ namespace ICSharpCode.ILSpy
/// Dirty flag, used to mark modifications so that the list is saved later
bool dirty;
-
+
internal readonly ConcurrentDictionary<(string assemblyName, bool isWinRT), LoadedAssembly> assemblyLookupCache = new ConcurrentDictionary<(string assemblyName, bool isWinRT), LoadedAssembly>();
-
+ internal readonly ConcurrentDictionary moduleLookupCache = new ConcurrentDictionary();
+
///
/// The assemblies in this list.
/// Needs locking for multi-threaded access!
diff --git a/ILSpy/LoadedAssembly.cs b/ILSpy/LoadedAssembly.cs
index 02503c124..2420dfa82 100644
--- a/ILSpy/LoadedAssembly.cs
+++ b/ILSpy/LoadedAssembly.cs
@@ -220,7 +220,7 @@ namespace ICSharpCode.ILSpy
}
}
- sealed class MyAssemblyResolver : Decompiler.Metadata.IAssemblyResolver
+ sealed class MyAssemblyResolver : IAssemblyResolver
{
readonly LoadedAssembly parent;
@@ -233,6 +233,11 @@ namespace ICSharpCode.ILSpy
{
return parent.LookupReferencedAssembly(reference)?.GetPEFileOrNull();
}
+
+ public PEFile ResolveModule(PEFile mainModule, string moduleName)
+ {
+ return parent.LookupReferencedModule(mainModule, moduleName)?.GetPEFileOrNull();
+ }
}
public IAssemblyResolver GetAssemblyResolver()
@@ -261,6 +266,15 @@ namespace ICSharpCode.ILSpy
}
}
+ public LoadedAssembly LookupReferencedModule(PEFile mainModule, string moduleName)
+ {
+ if (mainModule == null)
+ throw new ArgumentNullException(nameof(mainModule));
+ if (moduleName == null)
+ throw new ArgumentNullException(nameof(moduleName));
+ return assemblyList.moduleLookupCache.GetOrAdd(mainModule.FileName + ";" + moduleName, _ => LookupReferencedModuleInternal(mainModule, moduleName));
+ }
+
class MyUniversalResolver : UniversalAssemblyResolver
{
public MyUniversalResolver(LoadedAssembly assembly)
@@ -326,7 +340,58 @@ namespace ICSharpCode.ILSpy
});
return asm;
}
-
+
+ LoadedAssembly LookupReferencedModuleInternal(PEFile mainModule, string moduleName)
+ {
+ string file;
+ LoadedAssembly asm;
+ lock (loadingAssemblies) {
+ foreach (LoadedAssembly loaded in assemblyList.GetAssemblies()) {
+ var reader = loaded.GetPEFileOrNull()?.Metadata;
+ if (reader == null || reader.IsAssembly) continue;
+ var moduleDef = reader.GetModuleDefinition();
+ if (moduleName.Equals(reader.GetString(moduleDef.Name), StringComparison.OrdinalIgnoreCase)) {
+ LoadedAssemblyReferencesInfo.AddMessageOnce(moduleName, MessageKind.Info, "Success - Found in Assembly List");
+ return loaded;
+ }
+ }
+
+ file = Path.Combine(Path.GetDirectoryName(mainModule.FileName), moduleName);
+ if (!File.Exists(file))
+ return null;
+
+ foreach (LoadedAssembly loaded in assemblyList.GetAssemblies()) {
+ if (loaded.FileName.Equals(file, StringComparison.OrdinalIgnoreCase)) {
+ return loaded;
+ }
+ }
+
+ if (file != null && loadingAssemblies.TryGetValue(file, out asm))
+ return asm;
+
+ if (assemblyLoadDisableCount > 0)
+ return null;
+
+ if (file != null) {
+ LoadedAssemblyReferencesInfo.AddMessage(moduleName, MessageKind.Info, "Success - Loading from: " + file);
+ asm = new LoadedAssembly(assemblyList, file) { IsAutoLoaded = true };
+ } else {
+ LoadedAssemblyReferencesInfo.AddMessageOnce(moduleName, MessageKind.Error, "Could not find reference: " + moduleName);
+ return null;
+ }
+ loadingAssemblies.Add(file, asm);
+ }
+ App.Current.Dispatcher.BeginInvoke((Action)delegate () {
+ lock (assemblyList.assemblies) {
+ assemblyList.assemblies.Add(asm);
+ }
+ lock (loadingAssemblies) {
+ loadingAssemblies.Remove(file);
+ }
+ });
+ return asm;
+ }
+
public Task ContinueWhenLoaded(Action> onAssemblyLoaded, TaskScheduler taskScheduler)
{
return this.assemblyTask.ContinueWith(onAssemblyLoaded, default(CancellationToken), TaskContinuationOptions.RunContinuationsAsynchronously, taskScheduler);
diff --git a/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs b/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs
index f834d9fe3..2c9164184 100644
--- a/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs
+++ b/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs
@@ -27,30 +27,53 @@ namespace ICSharpCode.ILSpy.TreeNodes
///
sealed class ModuleReferenceTreeNode : ILSpyTreeNode
{
+ readonly AssemblyTreeNode parentAssembly;
readonly MetadataReader metadata;
readonly ModuleReferenceHandle handle;
readonly ModuleReference reference;
+ readonly AssemblyFileHandle fileHandle;
+ readonly AssemblyFile file;
+ readonly string moduleName;
- public ModuleReferenceTreeNode(ModuleReferenceHandle r, MetadataReader module)
+ public ModuleReferenceTreeNode(AssemblyTreeNode parentAssembly, ModuleReferenceHandle r, MetadataReader module)
{
+ this.parentAssembly = parentAssembly ?? throw new ArgumentNullException(nameof(parentAssembly));
if (r.IsNil)
throw new ArgumentNullException(nameof(r));
this.metadata = module;
this.handle = r;
this.reference = module.GetModuleReference(r);
+ this.moduleName = metadata.GetString(reference.Name);
+
+ foreach (var h in module.AssemblyFiles) {
+ var file = module.GetAssemblyFile(h);
+ if (module.StringComparer.Equals(file.Name, moduleName)) {
+ this.file = file;
+ this.fileHandle = h;
+ break;
+ }
+ }
}
public override object Text {
- get { return metadata.GetString(reference.Name) + ((EntityHandle)handle).ToSuffixString(); }
+ get { return moduleName + ((EntityHandle)handle).ToSuffixString(); }
}
-
- public override object Icon {
- get { return Images.Library; }
+
+ public override object Icon => Images.Library;
+
+ public override void ActivateItem(System.Windows.RoutedEventArgs e)
+ {
+ var assemblyListNode = parentAssembly.Parent as AssemblyListTreeNode;
+ if (assemblyListNode != null && file.ContainsMetadata) {
+ assemblyListNode.Select(assemblyListNode.FindAssemblyNode(parentAssembly.LoadedAssembly.LookupReferencedModule(parentAssembly.LoadedAssembly.GetPEFileOrNull(), metadata.GetString(reference.Name))));
+ e.Handled = true;
+ }
}
-
+
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
- language.WriteCommentLine(output, metadata.GetString(reference.Name));
+ language.WriteCommentLine(output, moduleName);
+ language.WriteCommentLine(output, file.ContainsMetadata ? "contains metadata" : "contains no metadata");
}
}
}
diff --git a/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs b/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs
index 4490cbcf8..13c0f07e7 100644
--- a/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs
+++ b/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs
@@ -58,7 +58,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
foreach (var r in module.AssemblyReferences.OrderBy(r => r.Name))
this.Children.Add(new AssemblyReferenceTreeNode(r, parentAssembly));
foreach (var r in metadata.GetModuleReferences().OrderBy(r => metadata.GetString(metadata.GetModuleReference(r).Name)))
- this.Children.Add(new ModuleReferenceTreeNode(r, metadata));
+ this.Children.Add(new ModuleReferenceTreeNode(parentAssembly, r, metadata));
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)