2008-09-18 12 views
53

मैं एक स्थिति है जहाँ मुझे DLL मुझे लगता है कि एक और तीसरी पार्टी DLL का उपयोग करता बना रहा हूं राशि मिल गया है से यह बुला, लेकिन मैं का निर्माण करने में सक्षम होना पसंद करेंगे यदि संभव हो तो दोनों को एक साथ रखने के बजाय मेरी डीएलएल में तीसरी पार्टी डीएलएल।एक एम्बेडेड संसाधन के रूप में एक और अंदर एक dll एम्बेड और फिर मेरी कोड

यह सी # और .NET 3.5 है।

तरह से मैं यह करने के लिए चाहते हैं एक एम्बेडेड संसाधन जो मैं तो पहले DLL के निष्पादन के दौरान उपयुक्त जगह में जगह के रूप में तीसरे पक्ष DLL भंडारण के द्वारा है।

जिस तरह से मैंने मूल रूप से ऐसा करने की योजना बनाई थी, वह सिस्टम द्वारा लिखे गए स्थान में तीसरे पक्ष के डीएलएल को रखने के लिए कोड लिखकर है। Reflection.Assembly.GetExecutingAssembly()। स्थान.ToString() अंतिम/nameOfMyAssembly.dll को घटाएं। मैं सफलतापूर्वक इस स्थान में तीसरे पक्ष के .DLL (जो (सी जा रहा समाप्त होता है बचा सकते हैं: \ दस्तावेज़ और सेटिंग्स \ myUserName \ Local Settings \ Application Data \ विधानसभा \ DL3 \ KXPPAX6Y.ZCY \ A1MZ1499.1TR \ e0115d44 \ 91bb86eb_fe18c901), लेकिन जब मैं अपने कोड इस DLL की आवश्यकता होती है के भाग के लिए मिलता है यह यह नहीं मिल रहा।

किसी को भी यह है कि मुझे क्या चाहिए के बारे में कोई विचार है अलग ढंग से कर रही हैं?

उत्तर

41

एक बार जब आप संसाधन के रूप में तीसरे पक्ष की असेंबली को एम्बेड कर लेते हैं, तो एप्लिकेशन स्टार्ट-अप के दौरान वर्तमान डोमेन की AppDomain.AssemblyResolve ईवेंट की सदस्यता लेने के लिए कोड जोड़ें। जब भी सीएलआर की फ़्यूज़न उप-प्रणाली असफलता (नीतियों) के अनुसार असेंबली का पता लगाने में विफल रहता है तो यह घटना आग लगती है। AppDomain.AssemblyResolve के लिए ईवेंट हैंडलर में, Assembly.GetManifestResourceStream का उपयोग करके संसाधन लोड करें और अपनी सामग्री को बाइट सरणी के रूप में संबंधित Assembly.Load अधिभार में फ़ीड करें।नीचे ऐसे ही एक कार्यान्वयन सी # में दिखाई दे सकता है कि कैसे:

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => 
{ 
    var resName = args.Name + ".dll";  
    var thisAssembly = Assembly.GetExecutingAssembly();  
    using (var input = thisAssembly.GetManifestResourceStream(resName)) 
    { 
     return input != null 
      ? Assembly.Load(StreamToBytes(input)) 
      : null; 
    } 
}; 

जहां StreamToBytes के रूप में परिभाषित किया जा सकता है: के रूप में कुछ पहले ही उल्लेख किया है,

static byte[] StreamToBytes(Stream input) 
{ 
    var capacity = input.CanSeek ? (int) input.Length : 0; 
    using (var output = new MemoryStream(capacity)) 
    { 
     int readLength; 
     var buffer = new byte[4096]; 

     do 
     { 
      readLength = input.Read(buffer, 0, buffer.Length); 
      output.Write(buffer, 0, readLength); 
     } 
     while (readLength != 0); 

     return output.ToArray(); 
    } 
} 

अंत में, ILMerge विचार करने के लिए एक और विकल्प हो सकता है, यद्यपि कुछ हद तक अधिक शामिल है।

+0

पोस्ट करने के बाद यह महसूस किया कि @dgvid ने प्रतिक्रिया समय में मुझे हराया। : पी –

+0

मैंने इस कोड का उपयोग वास्तव में वही करने के लिए किया जो मैं चाहता था। मेरे द्वारा तय किए गए कुछ मामूली वाक्यविन्यास चूक के लिए मेरी पोस्ट देखें (इसे संपादित करने के लिए पर्याप्त प्रतिनिधि नहीं है))। –

+0

वह चिकना है, अच्छी तरह से किया गया है। – jcollum

11

वहाँ एक उपकरण IlMerge कहा जाता है कि यह कर सकते हैं यह पूरा: http://research.microsoft.com/~mbarnett/ILMerge.aspx

तो फिर तुम सिर्फ एक का निर्माण घटना निम्नलिखित के समान बना सकते हैं

। सेट पथ = "सी: \ प्रोग्राम फ़ाइलें \ माइक्रोसॉफ्ट \ ILMerge"

ilmerge /out:$(ProjectDir)\Deploy\LevelEditor.exe $ (ProjectDir) \ bin \ release \ release.exe $ (ProjectDir) \ bin \ रिलीज \ InteractLib.dll $ (ProjectDir) \ bin \ Release \ SpriteLib.dll $ (ProjectDir) \ bin \ Release \ LevelLibrary.dll

2

डिस्क पर असेंबली लिखने के बजाय आप असेंबली करने की कोशिश कर सकते हैं। लोड (बाइट [] rawAssembly) जहां आप एम्बेडेड संसाधन से rawAssembly बनाते हैं।

9

आप Netz, एक .NET नेट एक्जिक्यूटिव कंप्रेसर & पैकर का उपयोग करके यह उल्लेखनीय आसानी से प्राप्त कर सकते हैं।

8

मैं सफलता कर आप क्या कर रहे हैं का वर्णन किया है, लेकिन क्योंकि तीसरे पक्ष के DLL भी एक .NET विधानसभा है, मैं इसे डिस्क पर लिखने कभी नहीं, मैं सिर्फ स्मृति से इसे लोड।()

 Assembly resAssembly = Assembly.LoadFile(assemblyPathName); 

     byte[] assemblyData; 
     using (Stream stream = resAssembly.GetManifestResourceStream(resourceName)) 
     { 
      assemblyData = ReadBytesFromStream(stream); 
      stream.Close(); 
     } 

तब मैं Assembly.Load साथ डेटा लोड:

मैं बहुत की तरह एक बाइट सरणी के रूप में एम्बेडेड संसाधन विधानसभा मिलता है।

अंत में, मैं अपने लोड विधानसभा वापस जाने के लिए जब प्रकार लोडर यह लग रहा है AppDomain.CurrentDomain.AssemblyResolve करने के लिए एक हैंडलर जोड़ने।

अतिरिक्त जानकारी के लिए .NET Fusion Workshop देखें।

17

अंत में मैंने लगभग कुछ ही मामूली परिवर्तनों और कुछ चूक को छोड़कर, रबूफ सुझाव दिया (और डीजीवीआईडी ​​सुझाव के समान) जैसा ही किया था। मैंने इस विधि को चुना क्योंकि यह पहली जगह के लिए सबसे नज़दीक था और किसी तीसरे पक्ष के निष्पादन योग्य और इस तरह के उपयोग की आवश्यकता नहीं थी। यह बहुत अच्छा काम करता है!

संपादित करें:

यह वही मेरी कोड की तरह लग रही समाप्त हो गया है मैं एक और विधानसभा को यह समारोह स्थानांतरित करने के लिए तो मैं एक से अधिक फ़ाइलों में यह पुन: उपयोग कर सकता है फैसला किया (मैं सिर्फ Assembly.GetExecutingAssembly में पारित())।

यह अद्यतन संस्करण है जो आपको एम्बेडेड डीएलएस के साथ असेंबली में पास करने की अनुमति देता है।

एम्बेडेड रिसोर्सप्रैक्स एम्बेडेड संसाधन के लिए स्ट्रिंग पथ है, यह आमतौर पर असेंबली का नाम होगा जिसके बाद संसाधन युक्त किसी भी फ़ोल्डर संरचना (जैसे "MyComapny.MyProduct.MyAssembly.Resources" है यदि डीएलएल फ़ोल्डर में है परियोजना में संसाधन)। यह भी मानता है कि डीएलएल में .dll.resource एक्सटेंशन है।

public static void EnableDynamicLoadingForDlls(Assembly assemblyToLoadFrom, string embeddedResourcePrefix) { 
     AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { // had to add => 
      try { 
       string resName = embeddedResourcePrefix + "." + args.Name.Split(',')[0] + ".dll.resource"; 
       using (Stream input = assemblyToLoadFrom.GetManifestResourceStream(resName)) { 
        return input != null 
         ? Assembly.Load(StreamToBytes(input)) 
         : null; 
       } 
      } catch (Exception ex) { 
       _log.Error("Error dynamically loading dll: " + args.Name, ex); 
       return null; 
      } 
     }; // Had to add colon 
    } 

    private static byte[] StreamToBytes(Stream input) { 
     int capacity = input.CanSeek ? (int)input.Length : 0; 
     using (MemoryStream output = new MemoryStream(capacity)) { 
      int readLength; 
      byte[] buffer = new byte[4096]; 

      do { 
       readLength = input.Read(buffer, 0, buffer.Length); // had to change to buffer.Length 
       output.Write(buffer, 0, readLength); 
      } 
      while (readLength != 0); 

      return output.ToArray(); 
     } 
    } 
+0

अपना अंतिम कोड पोस्ट करने के लिए धन्यवाद, मैं उस जगह का उपयोग कर समाप्त कर सकता हूं! –

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