2011-12-31 22 views
6

मैं ILSpy के साथ एक संपूर्ण .NET असेंबली को अलग करना चाहता हूं।ILSpy, निर्भरताओं को हल करने के लिए कैसे?

मैं आधार के रूप में इस कोड का प्रयोग किया:
http://skysigal.xact-solutions.com/Blog/tabid/427/entryid/2488/Default.aspx

और यह ठीक काम करता है, बस जब मैं एक विधानसभा का संदर्भ देता है Npgsql.dll (या किसी अन्य गैर गाक विधानसभा), तो मैं एक AssemblyResolutionException मिलता है।

विधानसभा को हल करने में विफल: 'Npgsql, संस्करण = 2.0.11.92, संस्कृति = तटस्थ, PublicKeyToken = 5d8b90d52f46fda7'

मुझे पता है कि मैं संदर्भित विधानसभाओं प्राप्त कर सकते हैं, लेकिन कैसे मैं उन्हें AST को जोड़ सकते हैं?

// SqlWebAdmin.Models.Decompiler.DecompileAssembly("xy.dll"); 
    public static string DecompileAssembly(string pathToAssembly) 
    { 
     //Assembly assembly = Assembly.LoadFrom(pathToAssembly); 
     System.Reflection.Assembly assembly = System.Reflection.Assembly.ReflectionOnlyLoadFrom(pathToAssembly); 
     //assembly.GetReferencedAssemblies(); 

     //assembly.GetReferencedAssemblies(assembly); 
     Mono.Cecil.AssemblyDefinition assemblyDefinition = 
      Mono.Cecil.AssemblyDefinition.ReadAssembly(pathToAssembly); 



     ICSharpCode.Decompiler.Ast.AstBuilder astBuilder = new ICSharpCode.Decompiler.Ast.AstBuilder(new ICSharpCode.Decompiler.DecompilerContext(assemblyDefinition.MainModule)); 
     astBuilder.AddAssembly(assemblyDefinition); 


     //new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit); 
     using (System.IO.StringWriter output = new System.IO.StringWriter()) 
     { 
      astBuilder.GenerateCode(new ICSharpCode.Decompiler.PlainTextOutput(output)); 
      string result = output.ToString(); 
      return result; 
     } 

     return ""; 
    } // End Function DecompileAssembly 
+0

'//assembly.GetReferencedAssemblies();' अपने लिंक से मूल कोड में था ' GetReferencedAssemblies (असेंबली); ', क्या आपने इसे छोड़ दिया क्योंकि वे इस लेख में' GetReferencedAssemblies' क्या परिभाषित नहीं करते हैं? वह कोड शायद आपकी मदद करेगा। –

+0

@ एम। बाबाकॉक: सही है लेकिन यह कोड कहीं भी नहीं है। और ऑब्जेक्ट मैनेजर में, कोई तरीका नहीं है GetReferencedAssemblies जो पैरामीटर के रूप में असेंबली लेता है ... –

उत्तर

13

आपको सीसीएल, अंतर्निहित मेटाडेटा रीडर को सूचित करने की आवश्यकता है जो आईएलएसपी उपयोग कर रहा है, जहां आपकी असेंबली हैं। आप लिख सकते हैं:

var resolver = new DefaultAssemblyResolver(); 
resolver.AddSearchDirectory("path/to/my/assemblies"); 

var parameters = new ReaderParameters 
{ 
    AssemblyResolver = resolver, 
}; 

var assembly = AssemblyDefinition.ReadAssembly(pathToAssembly, parameters); 

संदर्भित असेंबली को हल करने के लिए सेसिल को बताने का यह सबसे स्वाभाविक तरीका है। इस तरह आप उस लाइन को हटा सकते हैं जहां आप System.Reflection का उपयोग करके असेंबली लोड करते हैं, और केवल ILSpy स्टैक का उपयोग करें।

+0

इस समस्या का एक और कोण है, @ जेबी इवान। यदि मैं एक सिस्टम पर एक डीएलएल को संकुचित कर रहा हूं जहां संदर्भित असेंबली मौजूद नहीं हैं, तो विघटन विफल हो जाता है (अपवाद के साथ।) कम से कम, मैं संकुचित कोड देखना चाहता हूं, जो भी हल हो गया है। मैं एक अतिरिक्त समाधान पोस्ट कर रहा हूं, लेकिन आपका आदर्श है। – Nayan

1

Mono.Cecil स्रोत के आधार पर, मुझे लगता है कि है कि आप शायद Mono.Cecil.DefaultAssemblyResolver वर्ग का उपयोग कर इस संभाल सकता होगा।

इस कोड की बजाय

:

Mono.Cecil.AssemblyDefinition assemblyDefinition = 
    Mono.Cecil.AssemblyDefinition.ReadAssembly(pathToAssembly); 

इस प्रयास करें:

Mono.Cecil.AssemblyDefinition assemblyDefinition = 
    new Mono.Cecil.DefaultAssemblyResolver().Resolve(System.Reflection.AssemblyName.GetAssemblyName(pathToAssembly).ToString()); 

संपादित

अपने मूल सुझाव या काम नहीं कर सकता हो सकता है (मैं इसे कभी नहीं किया है, इसलिए कोई गारंटी नहीं है), आप इस प्रकार के कम करने में मदद के लिए Mono.Addins project से Mono.Addins.CecilReflector.dll असेंबली को देखना चाह सकते हैं समस्या का। यह मोनो सेसिल पर भी आधारित है (जैसा कि आईएलएसपी है), भले ही सामान्य आधार जो मोनो। एडिनस एक एक्स्टेंसिबिलिटी लाइब्रेरी है, आपकी ज़रूरतों को पूरा नहीं करती है, इसमें आपके उद्देश्यों के लिए कुछ कोड उपयोग हो सकते हैं या कम से कम सीख सकते हैं।

2

जेबी इवान ने जो सुझाव दिया है, इसके अलावा, यह कोड अपवाद से बचने में मदद करेगा। आपको बस इतना करना है कि रिज़ॉल्वर में अपवाद को संभालना है।

सबसे अच्छा तरीका नहीं है, मैं मानता हूं। लेकिन यह इस परिदृश्य के लिए काम करता है: "If I am decompiling a DLL on a system where the referred assemblies are not present, the decompilation fails (with exception.) At least, i would like to see the decompile code, for whatever has been resolved."

using System; 
using System.Collections.Generic; 
using Mono.Cecil; 

public class MyAssemblyResolver : BaseAssemblyResolver 
{ 
    private readonly IDictionary<string, AssemblyDefinition> cache; 
    public MyAssemblyResolver() 
    { 
     this.cache = new Dictionary<string, AssemblyDefinition>(StringComparer.Ordinal); 
    } 
    public override AssemblyDefinition Resolve(AssemblyNameReference name) 
    { 
     if (name == null) 
      throw new ArgumentNullException("name"); 
     AssemblyDefinition assemblyDefinition = null; 
     if (this.cache.TryGetValue(name.FullName, out assemblyDefinition)) 
      return assemblyDefinition; 
     try //< -------- My addition to the code. 
     { 
      assemblyDefinition = base.Resolve(name); 
      this.cache[name.FullName] = assemblyDefinition; 
     } 
     catch { } //< -------- My addition to the code. 
     return assemblyDefinition; 
    } 
    protected void RegisterAssembly(AssemblyDefinition assembly) 
    { 
     if (assembly == null) 
      throw new ArgumentNullException("assembly"); 
     string fullName = assembly.Name.FullName; 
     if (this.cache.ContainsKey(fullName)) 
      return; 
     this.cache[fullName] = assembly; 
    } 
} 

और इस तरह इसका इस्तेमाल:

var rp = new Mono.Cecil.ReaderParameters() { AssemblyResolver = new MyAssemblyResolver() }; 
var assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(assemblyStream, rp); 
var astBuilder = new ICSharpCode.Decompiler.Ast.AstBuilder(
    new ICSharpCode.Decompiler.DecompilerContext(assemblyDefinition.MainModule)); 
astBuilder.AddAssembly(assemblyDefinition); 




मैं वास्तव में decompiler में बढ़ा हुआ देखना चाहेंगे: यह वर्तमान में ध्यान नहीं देता ReaderParameters जो उपयोगकर्ता DefaultAssemblyResolver कक्षा में सेट करता है।

उपयोग:

var rp = new Mono.Cecil.ReaderParameters(); 
var assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(assemblyStream, rp); 

वर्तमान DefaultAssemblyResolver कोड: @Nayan जवाब

public override AssemblyDefinition Resolve(AssemblyNameReference name) 
{ 
    if (name == null) 
    { 
     throw new ArgumentNullException("name"); 
    } 
    AssemblyDefinition assemblyDefinition; 
    if (this.cache.TryGetValue(name.FullName, out assemblyDefinition)) 
    { 
     return assemblyDefinition; 
    } 
    assemblyDefinition = base.Resolve(name); // <--------- 
// Is the `ReaderParameters` object set by user, used to resolve in `base` class? 

    this.cache[name.FullName] = assemblyDefinition; 
    return assemblyDefinition; 
} 
+2

शानदार, इसने मुझे संदर्भित असेंबली के बिना स्रोत कोड प्रदर्शित करने की अनुमति दी। – TaintedLemon

+1

@ नयन: धन्यवाद, यह बहुत अच्छा है। –

+0

@ नयन: इसे बहुत आसान हासिल किया जा सकता है। मेरा जवाब देखो। आधार वर्गों का स्रोत कोड कॉपी करना उन्हें बढ़ाने का सबसे अच्छा तरीका नहीं है। –

4

यह सुधार हुआ है। आप विधानसभाओं लापता अनदेखा करना चाहते हैं, तो इस वर्ग कॉपी:

using Mono.Cecil; 

public class IgnoringExceptionsAssemblyResolver : DefaultAssemblyResolver 
{ 
    public override AssemblyDefinition Resolve(AssemblyNameReference name) 
    { 
     try 
     { 
      return base.Resolve(name); 
     } 
     catch 
     { 
      return null; 
     } 
    } 
} 

और इस तरह इसका इस्तेमाल:

var assembly = AssemblyDefinition.ReadAssembly(path, new ReaderParameters() { 
    AssemblyResolver = new IgnoringExceptionsAssemblyResolver() 
}); 
+2

हां, यह बहुत साफ है। मैं एक बकवास था, जब मैंने उस जवाब को लिखा :) – Nayan

संबंधित मुद्दे