2009-09-11 23 views
6

से उल्लंघन उल्लंघन अपवाद/क्रैश एक्सेस करें इसलिए मेरे पास मूल तृतीय पक्ष सी ++ कोड बेस है (मैं .lib और .hpp फ़ाइलें) के साथ काम कर रहा हूं जिसे मैं अंतिम उपयोग के लिए सी ++/सीएलआई में एक रैपर बनाने के लिए उपयोग करता था सी # मेंसी ++ कॉलबैक से सी # फ़ंक्शन

डीबग से रिलीज मोड में स्विच करते समय मैंने एक विशेष समस्या में भाग लिया है, जिसमें मुझे कॉलबैक कोड वापस आने पर एक्सेस उल्लंघन उल्लंघन प्राप्त होता है।

कॉलबैक फ़ंक्शन प्रारूप के लिए मूल HPP फाइलों से कोड:

typedef int (*CallbackFunction) (void *inst, const void *data); 

C++/CLI आवरण के कॉलबैक समारोह प्रारूप के लिए कोड: (मैं समझाऊंगा कारण है कि मैं एक पल में दो घोषित)

public delegate int ManagedCallbackFunction (IntPtr oInst, const IntPtr oData); 
public delegate int UnManagedCallbackFunction (void* inst, const void* data); 

--Quickly, कारण मैं घोषित एक दूसरे "UnManagedCallbackFunction" है कि मैं आवरण में एक "मध्यस्थ" कॉलबैक बनाने की कोशिश की है, इसलिए श्रृंखला मूल निवासी सी ++> का एक संस्करण से मूल निवासी सी ++> सी # बदला सी ++/सीएलआई रैपर> सी # ... पूर्ण प्रकटीकरण ठीक है, समस्या अभी भी जीवित है, इसे अभी सी ++/सीएलआई रैपर को उसी पंक्ति (वापसी) पर धकेल दिया गया है।

और अंत में, सी # से क्रैश होने कोड:

public static int hReceiveLogEvent(IntPtr pInstance, IntPtr pData) 
    { 
     Console.WriteLine("in hReceiveLogEvent..."); 
     Console.WriteLine("pInstance: {0}", pInstance); 
     Console.WriteLine("pData: {0}", pData); 

     // provide object context for static member function 
     helloworld hw = (helloworld)GCHandle.FromIntPtr(pInstance).Target; 
     if (hw == null || pData == null) 
     { 
      Console.WriteLine("hReceiveLogEvent: received null instance pointer or null data\n"); 
      return 0; 
     } 

     // typecast data to DataLogger object ptr 
     IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataLoggerWrap(pData))); 
     DataLoggerWrap dlw = (DataLoggerWrap)GCHandle.FromIntPtr(ip2).Target; 

     //Do Logging Stuff 

     Console.WriteLine("exiting hReceiveLogEvent..."); 
     Console.WriteLine("pInstance: {0}", pInstance); 
     Console.WriteLine("pData: {0}", pData); 
     Console.WriteLine("Setting pData to zero..."); 
     pData = IntPtr.Zero; 
     pInstance = IntPtr.Zero; 
     Console.WriteLine("pData: {0}", pData); 
     Console.WriteLine("pInstance: {0}", pInstance); 

     return 1; 
    } 

सभी कंसोल के लिए लिखते हैं किया हैं और फिर हम खतरनाक वापसी पर दुर्घटना देखें: में 0x04d1004c पर

क्रिया के अपवाद helloworld.exe: 0xC0000005: एक्सेस उल्लंघन पढ़ने स्थान 0x04d1004c।

तो मैं यहाँ से डिबगर में कदम, सब मैं देख कॉल स्टैक पर अंतिम प्रविष्टि है:> "04d1004c()", जिनमें से दशमलव मान का मूल्यांकन: 80805964

है कौन सा केवल दिलचस्प यदि आप कंसोल है जो दिखाता है पर नज़र डालें:

entering registerDataLogger 
pointer to callback handle: 790848 
fp for callback: 2631370 
pointer to inst: 790844 
in hReceiveLogEvent... 
pInstance: 790844 
pData: 80805964 
exiting hReceiveLogEvent... 
pInstance: 790844 
pData: 80805964 
Setting pData to zero... 
pData: 0 
pInstance: 0 

अब, मुझे पता है डिबग के बीच और जारी कुछ चीजें माइक्रोसॉफ्ट दुनिया में काफी अलग हैं कि। मैं निश्चित रूप से बाइट पैडिंग और चर के प्रारंभिकरण के बारे में चिंतित हूं, इसलिए यदि कुछ ऐसा है जो मैं यहां प्रदान नहीं कर रहा हूं, तो बस मुझे बताएं और मैं (पहले से ही लंबी) पोस्ट में जोड़ दूंगा। मुझे यह भी लगता है कि प्रबंधित कोड सभी स्वामित्व को जारी नहीं कर सकता है और उसके बाद देशी सी ++ सामान (जिसके पास मेरे पास कोड नहीं है) पीडीएटी ऑब्जेक्ट को हटाने या मारने का प्रयास कर रहा है, इस प्रकार ऐप को क्रैश कर रहा है।

अधिक पूर्ण प्रकटीकरण, यह सब डीबग मोड में ठीक (प्रतीत होता है) काम करता है!

एक वास्तविक सिर स्क्रैच समस्या जो किसी भी मदद की सराहना करेगी!

उत्तर

3

मुझे लगता है कि ढेर क्योंकि बुला सम्मेलनों mismatching की कुचल गया: कॉलबैक प्रतिनिधि घोषणा पर विशेषता

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 

डाल करने के लिए बाहर की कोशिश करो।

+0

समर्थन के लिए, यह अधिकतर सही था। तीसरे पक्ष के विक्रेता से संपर्क करने के बाद, हमने पाया कि वे सीडीसीएल स्पेक का उपयोग करके संकलित किए गए हैं और प्रबंधित कोड अनुपालन के लिए आवश्यक स्टडकॉल नहीं: http://msdn.microsoft.com/en-us/library/367eeye0%28VS.80%29.aspx । मैंने StackOverflow पर एक प्रश्न पूछा कि यह क्यों होना चाहिए? उम्मीद है कि, संदर्भित एमएसडीएन लेख की तुलना में कोई बेहतर स्पष्टीकरण देगा। – TomO

+0

प्रोजेक्ट सेटिंग्स में कॉलिंग कन्वेंशन (सी/सी ++) के लिए डिफ़ॉल्ट है यदि __declspec() के साथ निर्दिष्ट नहीं है। कोड में यह कॉलिंग सम्मेलन दिखाई नहीं दे रहा था। मिस्चैचिंग सम्मेलनों के साथ क्या होता है यह स्पष्ट है: यदि स्टैक क्लीनअप की ज़िम्मेदारी मेल नहीं खाती है, तो यह स्टैक को क्रश करता है (कॉल से पहले अपने राज्य में रीसेट नहीं होता क्योंकि डबल क्लीनअप या बहुत कम)। यह ढेर पर पारित तर्कों की मात्रा पर निर्भर करता है। http://en.wikipedia.org/wiki/Calling_convention – jdehaan

0

This doesn't directly answer your question, लेकिन यह डिबग मोड को रिलीज़ मोड ठीक नहीं बनाम ठीक के रूप में जहाँ तक सही दिशा में नेतृत्व कर सकते हैं:

डिबगर के बाद से, आम तौर पर ढेर करने के लिए रिकार्ड रखने में काफी जानकारी दे कहते हैं मेमोरी में मेरे प्रोग्राम के आकार और लेआउट को पैडिंग करते हुए, मैं 9 12 बाइट्स मेमोरी को लिखकर डीबग मोड में "भाग्यशाली हो रहा था" जो बहुत महत्वपूर्ण नहीं थे। डीबगर के बिना, हालांकि, मैं अपनी महत्वपूर्ण मेमोरी स्पेस के बाहर चलने के बजाय अंततः महत्वपूर्ण चीजों के शीर्ष पर झुका रहा था, जिससे इंटरपॉप मेमोरी को हटाने के लिए इसका कारण नहीं था।

DataLoggerWrap की परिभाषा क्या है? आपके द्वारा प्राप्त किए जा रहे डेटा के लिए एक चार फ़ील्ड बहुत छोटा हो सकता है।

0

मुझे यकीन नहीं है कि आप क्या हासिल करने की कोशिश कर रहे हैं।

कुछ अंक:

1) कचरा कलेक्टर बुरा स्वामित्व के साथ इतना रिलीज़ मोड में और अधिक आक्रामक है व्यवहार आपके द्वारा बताई गई असामान्य नहीं है।

2) मुझे समझ में नहीं आता कि निम्न कोड क्या करने का प्रयास कर रहा है?

IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataLoggerWrap(pData))); 
DataLoggerWrap dlw = (DataLoggerWrap)GCHandle.FromIntPtr(ip2).Target; 

आप GCHandle.Alloc स्मृति में DataLoggerWrap का एक उदाहरण लॉक करने के लिए उपयोग करते हैं, लेकिन फिर आप इसे अप्रबंधित के पास कभी नहीं बाहर - तो क्यों आप उसे लॉक करते हैं? आप इसे कभी भी मुक्त नहीं करते?

दूसरी पंक्ति फिर संदर्भ को पकड़ लेती है - सर्कुलर पथ क्यों? संदर्भ क्यों - आप इसका कभी भी उपयोग नहीं करते?

3) आपने IntPtrs को शून्य पर सेट किया - क्यों? - इसका कार्यक्षेत्र के बाहर कोई प्रभाव नहीं पड़ेगा।

4) आपको यह जानने की जरूरत है कि कॉलबैक का अनुबंध क्या है। पीडीटा कॉलबैक या कॉलिंग फ़ंक्शन का मालिक कौन है?

0

मैं कॉलिंगकोनेटियन को छोड़कर @jdehaan के साथ हूं .tdCall जवाब हो सकता है, खासकर जब तृतीय पक्ष lib बीसी ++ में लिखा गया है, उदाहरण के लिए।

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