2012-04-12 7 views
6

मैं एक सी डीएल में एक रैपर बनाने की कोशिश कर रहा हूं और मैं एक फ़ंक्शन कॉल करने का प्रयास कर रहा हूं जिसमें कॉलबैक फ़ंक्शन है, प्राप्त करता है एक वस्तु जो एक सूचक के रूप में वापस पारित किया जाता है।मैं सी #+ डीएल में सी # + डीएल में एक फ़ंक्शन कैसे कॉल करूं जिसमें शून्य * कॉलबैक और ऑब्जेक्ट पैरामीटर

ज फ़ाइल delares

extern int SetErrorHandler(void (*handler) (int, const char*, void*), 
           void *data_ptr); 

हैंडलर एक कॉलबैक फ़ंक्शन एक त्रुटि होती है और data_ptr के मामले में, किसी भी वस्तु (राज्य) है कि आप करने के लिए वापस पारित हो जाता है तब होता है जब कहा जाता है वह यह है कि मेरी ऐप जो यह होगा (वर्तमान वस्तु)।

मैं एक डीएल में फ़ंक्शंस को कॉल करने में सक्षम हूं जो सरल प्रकार के तारों, इन्स इत्यादि जैसे मार्शल किए गए निरंतर प्रकारों का उपयोग करता है लेकिन मैं यह नहीं समझ सकता कि कैसे एक सी # ऑब्जेक्ट को पॉइंटर को मार्शल करना है।

सी फ़ंक्शन के ऑब्जेक्ट संदर्भ को यहां से खोजकर जो मिला है उससे प्राप्त करने के लिए और अन्यथा ऐसा लगता है कि मुझे फ़ंक्शन में मार्शल करने में सक्षम होने के लिए संरचना प्रकार की आवश्यकता है, इसलिए मैंने अपनी ऑब्जेक्ट को पकड़ने के लिए एक स्ट्रक्चर बनाया :

[StructLayout(LayoutKind.Sequential)] 
struct MyObjectState 
{ 
    public object state; 
} 

संपादित करें: मैं एक विशेषता डालने की कोशिश की: public object state संपत्ति पर [MarshalAs(UnmanagedType.Struct, SizeConst = 4)], लेकिन यह एक ही त्रुटि पैदा करता है, तो मैं इसे हटा दिया, यह does not वैसे भी काम करेगा लगता है।

संरचना में कॉलबैक फ़ंक्शन के लिए किसी ऑब्जेक्ट को रखने के लिए एक ऑब्जेक्ट प्रॉपर्टी होती है।

मैं इस प्रकार सी # में प्रतिनिधि की घोषणा की:

delegate void ErrorHandler(int errorCode, IntPtr name, IntPtr data); 

तब मैं सी # में आयात समारोह घोषित इस प्रकार है:

[DllImport("somedll.dll", CallingConvention = CallingConvention.Cdecl)] 
static extern int SetErrorHandler handler, IntPtr data); 

तब मैं अपने सी # कोड में एक कॉलबैक फ़ंक्शन बनाया:

void MyErrorHandler(int errorCode, IntPtr name, IntPtr data) 
{ 
    var strName = Marshal.PtrToStringAnsi(name); 
    var state = new MyObjectState(); 
    Marshal.PtrToStructure(data, state); 
    Console.WriteLine(strName); 
} 

मैं लाइब्रेरी फ़ंक्शन को निम्नानुसार कॉल करने में सक्षम हूं:

var state = new MyObjectState() 
{ 
    state = this 
}; 
IntPtr pStruct = Marshal.AllocHGlobal(Marshal.SizeOf(state)); 
Marshal.StructureToPtr(state, pStruct, true); 
int ret = SetErrorHandler(MyErrorHandler, pStruct); 

कॉल काम करता है और कॉलबैक फ़ंक्शन कहा जाता है, लेकिन मैं कॉलबैक फ़ंक्शन में डेटा का उपयोग करने में असमर्थ हूँ और जब मैं Marshal.PtrToStructure कोशिश मैं एक त्रुटि मिलती है:

The structure must not be a value class.

मैं खोज की एक बहुत कुछ किया यहां और मार्शल और शून्य * पर विभिन्न चीजें मिलीं लेकिन कुछ भी मुझे काम करने में मदद नहीं मिली है

धन्यवाद।

उत्तर

3

आप इसे जितना अधिक जटिल बना रहे हैं उससे कहीं अधिक जटिल बना रहे हैं। आपके सी # क्लाइंट को data_ptr पैरामीटर का उपयोग करने की आवश्यकता नहीं है क्योंकि सी # प्रतिनिधि पहले से ही this पॉइंटर को बनाए रखने के लिए तंत्र में निर्मित है।

तो आप प्रतिनिधि को IntPtr.Zero पास कर सकते हैं। आपके त्रुटि हैंडलर प्रतिनिधि के अंदर आप data_ptr के मान को अनदेखा करते हैं क्योंकि this उपलब्ध होगा।

यदि आप इस विवरण का पालन नहीं करते हैं, तो मेरा मतलब यह समझाने के लिए एक छोटा कार्यक्रम है। नोट करें कि MyErrorHandler एक उदाहरण विधि है जो त्रुटि हैंडलर के रूप में कार्य करती है, और इंस्टेंस डेटा संशोधित कर सकती है।

class Wrapper 
{ 
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
    delegate void ErrorHandler(int errorCode, string name, IntPtr data); 

    [DllImport("somedll.dll", CallingConvention = CallingConvention.Cdecl)] 
    static extern int SetErrorHandler(ErrorHandler handler, IntPtr data); 

    void MyErrorHandler(int errorCode, string name, IntPtr data) 
    { 
     lastError = errorCode; 
     lastErrorName = name; 
    } 

    public Wrapper() 
    { 
     SetErrorHandler(MyErrorHandler, IntPtr.Zero); 
    }    

    public int lastError { get; set; } 
    public string lastErrorName { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Wrapper wrapper = new Wrapper(); 
    } 
} 
+0

इस मामले में यह सच है, वास्तव में मुझे इसे डेटा पर पास करने की ज़रूरत नहीं थी क्योंकि यह मेरे ऑब्जेक्ट कॉलबैक में उपलब्ध होगा, लेकिन जब मैं उपयोगकर्ता चाहता हूं तो फ़ंक्शन को सही कॉल प्रदान करना चाहता था एक संदर्भ प्रदान करें। मुझे लगता है कि राज्य के संदर्भ को बनाए रखने के लिए डेटा के प्रबंधन को सी # ऑब्जेक्ट द्वारा नियंत्रित किया जा सकता है। तो मुझे लगता है कि यह मेरी समस्या हल करता है, लेकिन मुझे लगता है कि ऑब्जेक्ट को पास करना संभव है या नहीं, इसका मूल प्रश्न अनुत्तरित – Andre

+0

है, आप वास्तव में मेरे दृश्य में एक C# ऑब्जेक्ट का संदर्भ पास नहीं करना चाहते हैं। याद रखें कि प्रबंधित वस्तुओं को जीसी द्वारा स्थानांतरित किया जा सकता है। क्या आप ऐसी वस्तुओं को पिन करने के लिए मजबूर कर रहे हैं? और देशी कोड ऐसी चीज के साथ क्या कर सकता है? यह पूरी तरह से अपारदर्शी है। आप प्रत्येक ऑब्जेक्ट के लिए एक अद्वितीय आईडी प्राप्त करने के लिए 'ऑब्जेक्टिड जेनरेटर' का उपयोग कर सकते हैं, लेकिन व्यक्तिगत रूप से मुझे लगता है कि आपका प्रश्न सबसे अच्छा तरीके से इसका सामना कर रहा है! –

+1

जो आप कहते हैं वह समझ में आता है, और मुझे लगता है कि उत्तर ऐसा नहीं करता है/इससे बचें, यह असंभव नहीं हो सकता है लेकिन आपको नहीं चाहिए, धन्यवाद – Andre

2

ऐसा करने का एक तरीका बहुत अच्छा हो सकता है, लेकिन मैंने बहुत समय पहले छोड़ दिया था। समाधान मैं ले कर आए हैं थोड़ा hackish है, लेकिन यह बहुत प्रभावी है और सब कुछ मैं इसे फेंक दिया गया है के साथ काम करता है:

सी # -> प्रबंधित सी ++ -> मूल निवासी कॉल

यह इस तरह से आप खत्म कर प्रबंधित सी ++ में एक छोटा रैपर लिखना, जो दर्द का प्रकार है, लेकिन मुझे उस मार्शलिंग कोड की तुलना में अधिक सक्षम और कम दर्दनाक पाया गया।

ईमानदारी से हालांकि मैं उम्मीद कर रहा हूं कि कोई गैर-उत्पीड़नपूर्ण उत्तर देता है, मैंने कुछ समय से इसके साथ संघर्ष किया है।

+0

धन्यवाद क्रिस, यह उपयोगी है, लेकिन मेरे पास प्रबंधित सी ++ लाइब्रेरी लिखने के लिए इस बिंदु पर उपकरण या ज्ञान नहीं है, शायद मैं इसे भविष्य में कभी-कभी समझ सकता हूं। मुझे नहीं लगता कि आप दस्तावेज के साथ एक सामान्य एक लिंक प्रदान कर सकते हैं इसका उपयोग कैसे करें? अंत में यदि यह सब मेरे लिए काम नहीं करता है तो समाधान यह सुनिश्चित करना है कि कॉलबैक में मुझे जो भी डेटा चाहिए, उसे स्ट्रक्चर में जोड़ा जाना चाहिए और सरल मानों के रूप में मार्शल किया जाना चाहिए? धन्यवाद – Andre

+0

पीएस: मुझे अपने कॉलबैक के साथ एक अतिरिक्त समस्या भी है, यह ठीक काम करता है, लेकिन अगर मैं कॉलबैक फ़ंक्शन बॉडी में सभी कोड हटा देता हूं, तो फ़ंक्शन के अंत में मुझे एक एक्सेस उल्लंघन मिलता है (सुरक्षित स्मृति को पढ़ने या लिखने का प्रयास किया जाता है) – Andre

+0

असल में मैंने इसे अभी समझ लिया: मुझे अपने प्रतिनिधि पर विशेषता [UnmanagedFunctionPointer (CallingConvention.Cdecl)] अनुपलब्ध था: http://stackoverflow.com/questions/4906931/nullreferenceexception-during-c-callback-to-c- तेज-फ़ंक्शन – Andre

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