2010-11-14 15 views
9

मुझे अपने सी # एप्लिकेशन, में अप्रबंधित डीएल आयात करना है, मैं जानना चाहता हूं कि इंटिप्ट और रेफरी के बीच अलग-अलग क्या है, और आपने मुझे क्या उपयोग करने की सिफारिश की और क्यों? ध्यान दें कि दोनों तरीके मेरे लिए काम कर रहे हैं। उदाहरण के लिए:इंटप्राट बनाम रेफरी सी #

[DllImport("mydll.dll", CallingConvention=CallingConvention.Cdecl)] 
static extern Result Init(IntPtr versionInfo); 

[DllImport("mydll.dll", CallingConvention=CallingConvention.Cdecl)] 
public static extern Result Init(ref Version versionInfo); 

उत्तर

3

संपादित करें: कुछ आलोचना मुझे मजबूर कर इस पर पुनर्विचार और इसे आगे अनुसंधान करने के लिए के आधार पर। मैं स्वतंत्र रूप से स्वीकार करता हूं कि IntPtr त्रुटि प्रवण है, मुझे लगता है कि "कठिन" अर्थों पर कुछ बहस हो सकती है, लेकिन यदि ढांचा स्वचालित रूप से इसे मार्शल कर सकता है और आपको चीजों को पिन करने से रोक सकता है, तो यदि आप IntPtr का उपयोग नहीं करते हैं तो मुझे लगता है मैं इस समझौते में हूं कि IntPtr "कठिन" होगा। यह आगे के शोध के बाद मुझे दिखाई देता है और सोचा कि यह आसान होगा (जब आपको पी/Invoke करने के लिए मजबूर किया जाता है और सी ++/सीएलआई रैपर नहीं बना सकता) अपनी संरचना घोषित करने के लिए (प्रबंधित कोड में और उसके बाद अपने मामले संस्करण) में यह रेफरी पैरामीटर के माध्यम से गुजरती हैं।

[StructLayout(LayoutKind.Sequential)] 
struct Version 
{ 
    // Data members 
} 

[DllImport("mydll.dll", CallingConvention=CallingConvention.Cdecl)] 
public static extern Result Init(ref Version versionInfo); 

मेरा अनुमान होगा आप IntPtr संस्करण चाहते हैं। अंतर यह है कि IntPtr एक वर्ग है कि करने के लिए एक सूचक का प्रबंधन करता है स्मृति, जबकि एक तर्क सूची में संदर्भ (रेफरी कीवर्ड) के रूप में पैरामीटर घोषित करने का अर्थ है कि आप गुजर रहे हैं संदर्भ से। आम तौर पर एक पी/इनवॉक कॉल के माध्यम से एक अप्रबंधित डीएल से डेटा पास करते समय, जब तक कि डेटा पास नहीं किया जाता है, एक वैनिला प्रकार (int, डबल, स्ट्रिंग - उचित मार्शल सजावट के साथ) मैं डेटा को इंटिप्टर के रूप में पास करता हूं। फिर आप अप्रबंधित संरचना की अपनी प्रबंधित घोषणा के लिए मार्शल IntPtr कर सकते हैं।

आप पी के बारे में अधिक जानकारी के लिए इस लिंक को आज़माना चाहिए/आह्वान कॉल: http://msdn.microsoft.com/en-us/magazine/cc164123.aspx

+0

यह दुर्भाग्यपूर्ण है कि आप चीजें कठिन, त्रुटि-प्रवण तरीके से कर रहे हैं। यह और भी दुर्भाग्यपूर्ण है कि आप अन्य लोगों को भी ऐसा करने के लिए सिखा रहे हैं। –

+0

@ बेन मैं इसे करने के लिए एक आसान/कम त्रुटि प्रवण तरीका सीखने में प्रसन्न हूं। क्या आपके पास कोई लिंक है या पढ़ने की सामग्री है।मैं पी/Invoking चीजों में बहुत समय बिताता हूं, ज्यादातर बार मैं एक सी ++/सीएलआई रैपर लिखता हूं, लेकिन जब मैं पी/इनवोक करने के लिए नीचे आ गया हूं तो मैंने केवल int, स्ट्रिंग जैसी चीजों के लिए रेफ पैरामीटर का उपयोग किया है (आने वाले मामलों में स्ट्रिंगबिल्डर), आदि, और फिर अन्य चीजों के लिए IntPtr का उपयोग किया। जीत के लिए – pstrjds

+1

सी ++/सीएलआई :) उन अवसरों के लिए जब आप इसका उपयोग नहीं कर सकते (विंडोज सीई, या यह सुनिश्चित नहीं हो सकता कि दृश्य सी ++ रनटाइम स्थापित हो जाएगा), तो http://pinvoke.net में एक भयानक है बहुत सारे उदाहरण आम तौर पर, न केवल आदिम प्रकारों जैसे 'int' और' double' को सुरक्षित रूप से पी/आवेषण हस्ताक्षर में उपयोग किया जा सकता है, बल्कि उपयोगकर्ता-परिभाषित प्रकार भी प्राचीन प्रकार से बने होते हैं। उदाहरण 'POINT',' POINTF', 'RECT',' FONTMETRIC', 'BITMAPFILEHEADER', आदि –

5

तो Version एक struct कि struct कि निर्वासन Init समारोह की उम्मीद के साथ संगत है है, वहाँ के बीच कोई महत्वपूर्ण अंतर है दो, सिवाय इसके कि ref संस्करण बहुत सी # से उपयोग करना आसान होगा क्योंकि रनटाइम आपके लिए सभी मार्शलिंग और पिनिंग का प्रबंधन करेगा। जब तक आप वास्तव में वह काम नहीं करना चाहते हैं, तो मैं ref विकल्प के साथ रहूंगा।

बेशक, सी फ़ंक्शन प्रोटोटाइप को देखे बिना, सी # में Version संरचना, और उस पैरामीटर के लिए सी में प्रयुक्त संरचना, मैं वास्तव में केवल अनुमान लगा सकता हूं।

+2

एक संभावित रूप से महत्वपूर्ण अंतर है: IntPtr का उपयोग करके IntPtr.Zero को मान के रूप में पास करने की अनुमति मिलती है, जबकि 'रेफ संस्करण' नहीं होता है। इस प्रकार, देशी कोड की आवश्यकता के आधार पर, IntPtr अधिभार की आवश्यकता नहीं है। – jonp

+2

@jonp: उस स्थिति में, आप ** ** ** दोनों संस्करण (एक अधिभारित फ़ंक्शन) चाहते हैं, ताकि जब आप एक हों, तो संदर्भ द्वारा 'संस्करण' पास कर सकें, और जब आप पास करना चाहते हैं तो 'IntPtr.Zero' शून्य। या संरचना के बजाए 'संस्करण' को कक्षा बनाएं, फिर आप शून्य को पास कर सकते हैं (और अब 'रेफरी' कीवर्ड की आवश्यकता नहीं है, लेकिन पी/कक्षा में एनोटेशन विशेषताओं की आवश्यकता है)। –

-1

IntPtr का उपयोग करने के लिए बेहतर है क्योंकि यह कोड को 6464 में संकलित करने के लिए आपके कोड को और अधिक लचीला बना देगा। IntPtr स्वचालित रूप से अपने आकार का विस्तार करेगा।

IntPtr = 4 bytes on x86 
IntPtr = 8 bytes on x64 

मामले हैं जब सी में कुछ विशेष प्रकार वे दोगुना आकार जब x64 लेकिन सी # समकक्षों (कि PInvoke के लिए घोषित किया गया है) के लिए संकलित कर रहे हैं नहीं है। फिर फ़ंक्शन कॉल विफल हो जाएगी। यदि Version कक्षा में कुछ फ़ील्ड शामिल है तो आप IntPtr का बेहतर उपयोग करते हैं।

+0

'ref' एक सूचक आकार के पैरामीटर को भी पास करेगा। आपका बाकी उत्तर लगता है जैसे आप 'संस्करण' संरचना के अंदरूनी हिस्सों के बारे में बात कर रहे हैं, न कि पैरामीटर स्वयं। हालांकि यह संभव है कि 'संस्करण' के कुछ फ़ील्ड में 'IntPtr' टाइप होना चाहिए, इसलिए पी/इनवॉक घोषणा में' रेफ संस्करण 'का उपयोग न करने का कोई कारण नहीं है। –

+0

@ बेन आपको यह विचार नहीं मिला कि मुझे लगता है कि मैंने खुद को बहुत अच्छा व्यक्त किया है। मैंने यह नहीं कहा कि रेफरी का उपयोग काम नहीं करेगा, लेकिन मेरी राय में मैं इंटिप्ट का इस्तेमाल करता। लेकिन जब आप उत्तर नहीं देते तो नीचे वोट के लिए धन्यवाद। –

+0

@ लिविउ: मैंने डाउनवॉट किया (और जाहिर है कि मैं अकेला नहीं हूं) क्योंकि आपका जवाब गलत है। आपने कहा था कि "IntPtr' आपके कोड को अधिक लचीला बना देगा" wrt सूचक आकार, और यह केवल झूठा है। प्रत्येक रेफ्रिजरेटर पर 'रेफरी' और 'इंटिप्टर' समान आकार हैं। –

2

IntPtr आपको कॉल में उपयोग की जाने वाली संरचनाओं पर निर्भरताओं के बिना, अपने सभी बाहरीों को एक कक्षा में स्थानांतरित करने देगा, जिसे कहीं और परिभाषित किया जा सकता है। मैं एपी एडाप्टर को डेटा स्ट्रक्चर/क्लास डीफ़ से पृथक रखना चाहता हूं जो अगली परत में डालने के लिए अधिक प्राकृतिक लगती है।

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