2012-08-13 10 views
14

संभव डुप्लिकेट:
preprocessor directive…C#सी बदलें # DllImport लक्ष्य कोड 64 के आधार पर/86

मैं एक बाहरी C++ dll DllImport का उपयोग करके आयात करना पड़ता है। यदि मेरा आवेदन x64 में संकलित है, तो मुझे इस डीएलएल के x64 संस्करण को आयात करने की आवश्यकता है, यदि यह x86 बिल्ड है, तो मुझे x86 dll की आवश्यकता है।

इसे प्राप्त करने का सबसे अच्छा तरीका क्या है?

आदर्श रूप से, मुझे कुछ प्रीप्रोसेसर निर्देश चाहिए, लेकिन मुझे लगता है कि यह सी # में काम नहीं करता है?

अधिक जानकारी: डीएलएल किसी परियोजना द्वारा आयात किया जा रहा है जो किसी भी सीसीपीयू पर सेट है। एक मूल परियोजना वह है जो यह निर्धारित करती है कि एप्लिकेशन x64 या x86 के रूप में संकलित है या नहीं। हम अलग-अलग ग्राहकों के लिए दोनों संस्करणों को संकलित करते हैं - और मैं दोनों संस्करणों में बाल प्रोजेक्ट को साझा करना चाहता हूं।

+0

दोनों संस्करणों (निजी विधियों) को आयात करने के बारे में क्या है लेकिन क्लाइंट कोड को पर्यावरण के आधार पर सही तरीके से बेनकाब करने के लिए? .NET 4 के साथ बस [Environment.Is64BitOperatingSystem] (http://msdn.microsoft) की जांच करें।com/en-us/पुस्तकालय/system.environment.is64bitoperatingsystem.aspx)। नोट मैं निर्भर देशी डीएलएल की वजह से सी # अनुप्रयोग के दो अलग-अलग संस्करण नहीं रखूंगा (इसलिए मैं इसके लिए प्रीप्रोसेसर का उपयोग नहीं करता)। –

+0

माइकल - यह लगभग मेरा प्रश्न है, लेकिन मेरे पास एक अतिरिक्त जटिलता है जिसका अर्थ है कि उनका समाधान काम नहीं करेगा। मेरा डीएल एक परियोजना द्वारा आयात किया जाता है जो कि एसीसीपीयू है, और एक मूल परियोजना यह तय करती है कि एप्लिकेशन x64 या x86 – Sugrue

+0

@ सुग्रे है तो आपको रनटाइम समाधान का उपयोग करने की आवश्यकता होगी, अर्थात् दोनों को आयात करें और 'पर्यावरण। आईएस 64 बिटप्रोसेस' या 'आकार' का उपयोग करें (शून्य *) ', या' IntPtr.Size'। –

उत्तर

22

यह मुख्य रूप से एक तैनाती समस्या है, बस अपने इंस्टॉलर को लक्ष्य मशीन पर विंडोज संस्करण के आधार पर सही DLL कॉपी करें।

लेकिन कोई भी ऐसा कभी नहीं करना पसंद करता है। सही DLL के फ़ंक्शन को गतिशील रूप से पिनवोक करना बेहद दर्दनाक है, आपको प्रत्येक निर्यात किए गए फ़ंक्शन के लिए प्रतिनिधि प्रकार लिखना होगा और प्रतिनिधि ऑब्जेक्ट बनाने के लिए लोड लाइब्रेरी + GetProcAddress + Marshal.GetDelegateForFunctionPointer का उपयोग करना होगा।

लेकिन कोई भी ऐसा कभी नहीं करना पसंद करता है। कम दर्दनाक प्रयास दो बार फ़ंक्शन घोषित करना है, इसे अलग-अलग नाम देना और वास्तविक नाम निर्दिष्ट करने के लिए [DllImport] विशेषता में EntryPoint प्रॉपर्टी का उपयोग करना है। फिर उस रनटाइम पर परीक्षण करें जिसे आप कॉल करना चाहते हैं।

लेकिन कोई भी ऐसा कभी नहीं करना पसंद करता है। सबसे प्रभावी चाल आपके लिए सही डीएलएल लोड करने में विंडोज़ को चलाती है। सबसे पहले आपको जो करना है वह डीएलएल को उस निर्देशिका में कॉपी करें जहां विंडोज इसकी तलाश नहीं करेगा। सबसे अच्छा तरीका है अपनी बिल्ड निर्देशिका में "x86" और "x64" उपनिर्देशिका बनाना और उचित DLL को प्रत्येक में कॉपी करना है। ऐसा पोस्ट-बिल्ड ईवेंट लिखकर ऐसा करें जो निर्देशिका बनाता है और DLL को प्रतिलिपि बनाता है।

फिर इसके बारे में विंडोज़ को SetDllDirectory() को पिनवोक करके बताएं। आपके द्वारा निर्दिष्ट पथ निर्देशिकाओं में जोड़ा जाएगा जो विंडोज एक डीएलएल की खोज करता है। इस तरह:

using System; 
using System.Runtime.InteropServices; 
using System.Reflection; 
using System.IO; 

class Program { 
    static void Main(string[] args) { 
     var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); 
     path = Path.Combine(path, IntPtr.Size == 8 ? "x64" : "x86"); 
     bool ok = SetDllDirectory(path); 
     if (!ok) throw new System.ComponentModel.Win32Exception(); 
     //etc.. 
    } 
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern bool SetDllDirectory(string path); 
} 

मान लें कि 64-बिट मोड में कोड चलाने के लिए वास्तव में आपके लिए उपयोगी है या नहीं। आपके द्वारा प्राप्त होने वाली विशाल वर्चुअल मेमोरी एड्रेस स्पेस की आवश्यकता के लिए यह बहुत दुर्लभ है, केवल वास्तविक लाभ। आपको अभी भी 32-बिट संस्करण का समर्थन करने की आवश्यकता है जिसे 2 गीगाबाइट मामले में सही ढंग से संचालित करने की आवश्यकता है।

+0

अच्छा समाधान। PhonicUK और माइकल Graczyk भी अच्छे समाधान है, लेकिन इस में कोई दोहराव कोड शामिल है, जो मुझे पसंद है। – Sugrue

+1

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

+0

लोड लाइब्रेरी दूसरे अनुच्छेद द्वारा कवर किया गया है। बुरा विचार। –

5

दोनों x86 और अलग-अलग नामों के साथ x86_64 DLL आयात जोड़ें, तो आप सशर्त उन्हें कार्यावधि में वास्तुकला के आधार पर Environment.Is64BitProcess (या IntPtr.size का मूल्य की जाँच करके आह्वान अगर आप < नेट का उपयोग कर रहे सकते हैं 4)। यह इस पर ध्यान दिए बिना कि परियोजना x86, x86_64 या AnyCPU

वैकल्पिक रूप से, 2 अलग-अलग बिल्ड कॉन्फ़िगरेशन सेट करें - एक जो केवल x86 करता है और केवल x86_64 करता है, प्रत्येक को एक सशर्त संकलन प्रतीक और उपयोग दें आपके कस्टम प्रतीक पर #ifdef।

+0

मुझे लगता है कि ओपी को पता नहीं है कि '# ifdef' का उपयोग कैसे करें, क्या आप उसके लिए एक त्वरित कोड उदाहरण प्रदान कर सकते हैं, और शायद पुस्तकालयों को लोड करने का एक कोड उदाहरण भी? हालांकि उदाहरण के बिना अभी भी एक +1 दिया। –

+0

'पर्यावरण। आईएस 64 बिटप्रोसेस 'ने वास्तव में मेरी मदद की – LuckyLikey

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