2008-09-16 12 views
31

मेरे पास एक विंडोज सी # प्रोग्राम है जो डेटा I/o के लिए C++ dll का उपयोग करता है। मेरा लक्ष्य एक EXE के रूप में एप्लिकेशन को तैनात करना है।सी ++ विंडोज़ डीएल को सी # एप्लिकेशन एक्सई में कैसे विलय किया जा सकता है?

ऐसे निष्पादन योग्य बनाने के लिए क्या कदम हैं?

+0

आप BoxedAppPacker या BoxedApp एसडीके का उपयोग करना चाहिए। यह मदद करनी चाहिए। – MastAvalons

+1

http://stackoverflow.com/questions/666799/embedding-unmanaged-dll-into-a-managed-c-sharp-dll/11038376#11038376 –

उत्तर

14

एकल विधानसभा प्रबंधित और अप्रबंधित कोड रविवार, 4 फरवरी, 2007

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

तो here's क्या मैं एक समाधान के लिए के साथ आया था:

मैं शामिल जो कुछ DLLs मैं अपने component's साथ एम्बेड किए गए संसाधन के रूप में मुख्य विधानसभा को तैनात करना चाहते हैं। फिर मैंने नीचे दिए गए डीएलएल को निकालने के लिए एक क्लास कन्स्ट्रक्टर स्थापित किया। क्लास सीटीओ को प्रत्येक ऐपडोमेन के भीतर सिर्फ एक बार बुलाया जाता है, इसलिए यह एक लापरवाह ओवरहेड है, मुझे लगता है।

namespace MyLib 
{ 
    public class MyClass 
    { 
     static MyClass() 
     { 
      ResourceExtractor.ExtractResourceToFile("MyLib.ManagedService.dll", "managedservice.dll"); 
      ResourceExtractor.ExtractResourceToFile("MyLib.UnmanagedService.dll", "unmanagedservice.dll"); 
     } 

     ... 

इस उदाहरण में मैं संसाधनों के रूप में दो DLLs, एक होने के एक अप्रबंधित कोड DLL, और एक एक प्रबंधित कोड DLL (सिर्फ प्रदर्शन के उद्देश्य से) किया जा रहा है, दिखाने के लिए, कैसे इस तकनीक कोड दोनों प्रकार के लिए काम करता है शामिल ।

अपनी खुद की फाइलों में DLLs निकालने के लिए कोड सरल है:

public static class ResourceExtractor 
{ 
    public static void ExtractResourceToFile(string resourceName, string filename) 
    { 
     if (!System.IO.File.Exists(filename)) 
      using (System.IO.Stream s = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) 
       using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Create)) 
       { 
        byte[] b = new byte[s.Length]; 
        s.Read(b, 0, b.Length); 
        fs.Write(b, 0, b.Length); 
       } 
    } 
} 

इस तरह एक प्रबंधित कोड विधानसभा के साथ कार्य करना हमेशा की तरह एक ही है - लगभग। आप इसे अपने घटक की मुख्य परियोजना (यहां: MyLib) में संदर्भित करते हैं (यहां: प्रबंधित Service.dll), लेकिन प्रतिलिपि स्थानीय संपत्ति को गलत पर सेट करें। इसके अतिरिक्त आप असेंबली में मौजूदा आइटम के रूप में लिंक करते हैं और एंबेडेड संसाधन में बिल्ड एक्शन सेट करते हैं।

अप्रबंधित कोड (यहां: UnmanagedService.dll) के लिए आप बस मौजूदा आइटम के रूप में डीएलएल में लिंक करते हैं और एंबेडेड संसाधन में बिल्ड एक्शन सेट करते हैं। अपने कार्यों तक पहुंचने के लिए सामान्य रूप से DllImport विशेषता का उपयोग करें, उदा।

[DllImport("unmanagedservice.dll")] public extern static int Add(int a, int b); 

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

का आनंद लें!

http://weblogs.asp.net/ralfw/archive/2007/02/04/single-assembly-deployment-of-managed-and-unmanaged-code.aspx

+1

का डुप्लिकेट लिंक मर चुका है। यही कारण है कि आपको हमेशा एक लिंक-केवल उत्तर पोस्ट करने के बजाय ** हमेशा ** [लिंक किए गए पृष्ठ के सबसे प्रासंगिक भागों को उद्धृत करना चाहिए] (http://stackoverflow.com/help/how-to-answer) चाहिए। – BackSlash

0

Thinstall एक समाधान है। एक मूल विंडोज़ अनुप्रयोग के लिए मैं डीएलएल को द्विआधारी संसाधन ऑब्जेक्ट के रूप में एम्बेड करने का सुझाव दूंगा, फिर इसे चलाने से पहले रनटाइम पर निकालना होगा।

+2

थिंस्टॉल हास्यास्पद रूप से महंगा है और कुछ विंडोज इंस्टॉलेशन और तृतीय पक्ष शैल एक्सटेंशन के साथ समस्याओं में चलता है। हमने गैर-नेट कोड के लिए सीमित सफलता के साथ इसका इस्तेमाल किया, लेकिन क्लिकऑन और एमएसआई ने नेट के लिए सर्वश्रेष्ठ इंस्टॉल किया। – user7116

+2

यदि आप मुख्य रूप से इंस्टॉलेशन की तलाश में हैं, तो मैं इनो सेटअप की अनुशंसा करता हूं, हमने कुछ साल पहले इसके लिए इंस्टॉलशील्ड गिरा दिया और कभी पीछे नहीं देखा। http://www.innosetup.com/isinfo.php – titanae

1

क्या आपने ILMerge की कोशिश की है?http://research.microsoft.com/~mbarnett/ILMerge.aspx

आईएलएमर्ज एक उपयोगिता है जिसका उपयोग एकाधिक .NET असेंबली को एक असेंबली में विलय करने के लिए किया जा सकता है। यह माइक्रोसॉफ्ट .NET Framework डेवलपर सेंटर पर उपकरण & उपयोगिता पृष्ठ से उपयोग के लिए स्वतंत्र रूप से उपलब्ध है।

आप /clr ध्वज के साथ सी ++ DLL का निर्माण कर रहे हैं (सभी या आंशिक रूप से C++/CLI), तो यह काम करना चाहिए:

ilmerge /out:Composite.exe MyMainApp.exe Utility.dll 

यह एक साधारण (देशी) विंडोज के साथ काम नहीं करेगा डीएलएल हालांकि।

+1

बहुत यकीन है कि इसे डीएलएल पर '/ clr: pure' या उच्चतम की आवश्यकता है। –

3

boxedapp आज़माएं; यह स्मृति से सभी डीएलएल लोड करने की अनुमति देता है। साथ ही, ऐसा लगता है कि आप .NET रनटाइम को भी एम्बेड कर सकते हैं। वास्तव में एक स्टैंडअलोन अनुप्रयोग बनाने के लिए अच्छा ...

+0

महान एसडीके। मैं इसका भी उपयोग करता हूं। –

-2

Xenocode से पोस्टबिल्ड दोनों एक ही एक्सई में प्रबंधित और असम्बद्ध दोनों पैकेज कर सकते हैं।

1

विजुअल स्टूडियो में बस अपनी परियोजना पर राइट-क्लिक करें, परियोजना गुण -> संसाधन -> संसाधन जोड़ें -> मौजूदा फ़ाइल जोड़ें ... और नीचे दिए गए कोड को अपने App.xaml.cs या समकक्ष में शामिल करें।

public App() 
{ 
    AppDomain.CurrentDomain.AssemblyResolve +=new ResolveEventHandler(CurrentDomain_AssemblyResolve); 
} 

System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
{ 
    string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll",""); 

    dllName = dllName.Replace(".", "_"); 

    if (dllName.EndsWith("_resources")) return null; 

    System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly()); 

    byte[] bytes = (byte[])rm.GetObject(dllName); 

    return System.Reflection.Assembly.Load(bytes); 
} 

यहाँ मेरी मूल ब्लॉग पोस्ट है: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly/

+2

कृपया एक ही पोस्ट को कई बार पोस्ट न करें, खासकर यदि आप इसे बहुत पुराने प्रश्नों पर पोस्ट करने जा रहे हैं। यदि पिछली पोस्ट के समान सटीक उत्तर उचित है, तो प्रश्न को डुप्लिकेट के रूप में चिह्नित करें। यदि आप उसी ब्लॉग के साथ उस ब्लॉग लिंक को पोस्ट करना जारी रखते हैं, तो आप कुछ स्पैम झंडे आकर्षित कर सकते हैं। – Mat

+0

ठीक है .. धन्यवाद। –

0

Smart Assembly इस और अधिक कर सकते हैं। यदि आपके डीएलएल में अप्रबंधित कोड है, तो यह आपको डीएलएस को एक असेंबली में विलय नहीं करने देगा, बल्कि यह आवश्यक निर्भरताओं को आपके मुख्य एक्सई में संसाधनों के रूप में एम्बेड कर सकता है। इसकी फ्लिप-साइड, यह मुफ़्त नहीं है।

आप अपने संसाधनों में डीएल एम्बेड करके मैन्युअल रूप से ऐसा कर सकते हैं और फिर ऐपडोमेन की असेंबली ResolveHandler पर भरोसा कर सकते हैं। जब मिश्रित मोड डीएलएस की बात आती है, तो मुझे ResolveHandler दृष्टिकोण के कई प्रकार और स्वाद मिलते हैं जो मेरे लिए काम नहीं करते हैं (जो सभी स्मृति को डीएल बाइट पढ़ते हैं और इससे पढ़ते हैं)। वे सभी प्रबंधित डीएलएस के लिए काम किया। यहां मेरे लिए क्या काम किया गया है:

static void Main() 
{ 
    AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => 
    { 
     string assemblyName = new AssemblyName(args.Name).Name; 
     if (assemblyName.EndsWith(".resources")) 
      return null; 

     string dllName = assemblyName + ".dll"; 
     string dllFullPath = Path.Combine(GetMyApplicationSpecificPath(), dllName); 

     using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName)) 
     { 
      byte[] data = new byte[stream.Length]; 
      s.Read(data, 0, data.Length); 

      //or just byte[] data = new BinaryReader(s).ReadBytes((int)s.Length); 

      File.WriteAllBytes(dllFullPath, data); 
     } 

     return Assembly.LoadFrom(dllFullPath); 
    }; 
} 

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

यदि असेंबली पूरी तरह से अप्रबंधित है, तो आप इस link या this को इस तरह के डीएलएस लोड करने के तरीके के रूप में देख सकते हैं।

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