2013-04-23 8 views
6

मैं जो निम्नलिखित कोड का उपयोग कर देशी डेल्फी dll कॉल एक सी # अनुप्रयोग है में सी # फोन करने वाले के लिए डेल्फी dll से एक स्ट्रिंग रिटर्निंग:64 बिट

सी #

[DllImport("NativeDLL.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] 
public static extern int GetString(string out str); 

डेल्फी

function GetString(out a: PChar): Integer; stdcall; 
begin 
    a := PChar('abc'); 
    Result := 1; 
end; 

जो 32 बिट एप्लिकेशन में ठीक काम करता है। लेकिन जब मैं 64 बिट के लिए सी # एक्सई और डेल्फी डीएल दोनों संकलित करता हूं तो मुझे एक अजीब समस्या मिलती है। डेल्फी डीबगर में गेटस्ट्रिंग को कॉल करने के बाद मैं देख सकता हूं कि .NET कोड में कहीं भी अपवाद उठाया गया है और निम्न स्ट्रिंग डीबगर आउटपुट विंडो में दिखाई देती है: "गंभीर त्रुटि का पता चला c0000374"। Google कहता है कि यह त्रुटि ढेर भ्रष्टाचार से संबंधित है। मैंने बाहर/बाहर की बजाय रेफ/var पैरामीटर संशोधक का उपयोग करने का प्रयास किया। अभी भी कोई भाग्य नहीं है। मुझे यह त्रुटि क्यों मिलती है? क्या मुझे 64 बिट के लिए एक अलग कॉलिंग सम्मेलन का उपयोग करना चाहिए?

बीटीडब्ल्यू। निम्नलिखित संयोजन ठीक काम करता है:

सी #

[DllImport("NativeDLL.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] 
public static extern string GetString(string a); 

डेल्फी

function GetString(a: PChar): PChar; stdcall; 
var 
    inp: string; 
begin 
    inp := a; 
    Result := PChar('test ' + inp); 
end; 

ठीक काम करता है। लेकिन मुझे एक स्ट्रिंग को आउट पैरामीटर के रूप में वापस करने की आवश्यकता है।

उत्तर

17

आप इस तरह से प्रबंधित देशी से एक स्ट्रिंग पास नहीं कर सकते हैं। आपका कोड 32 बिट में भी गलत है, आप बस इससे दूर हो जाते हैं। कोड का दूसरा संस्करण भी गलत है। यह केवल काम करने लगता है। ताकि कि प्रबंधित कोड है कि ढेर बंद पुनःआवंटन कर सकते हैं

  1. एक साझा ढेर से आवंटित:

    आप या तो की जरूरत है। पी/invoke के लिए साझा ढेर COM ढेर है।

  2. प्रबंधित पक्ष पर स्मृति आवंटित करें, और सामग्री को उस बफर में मूल पक्ष पर कॉपी करें।

विकल्प 2 हमेशा बेहतर होता है।यह इस तरह दिखता है:

[DllImport("NativeDLL.dll", CharSet = CharSet.Unicode)] 
public static extern int GetString(StringBuilder str, int len); 

देशी तरफ आप के लिए होता है

function GetString(str: PChar; len: Integer): Integer; stdcall; 
begin 
    StrLCopy(str, 'abc', len); 
    Result := 1; // real code would have real error handling 
end; 

फिर तो जैसे इस फोन:

StringBuilder str = new StringBuilder(256); 
int retval = GetString(str, str.Capacity); 

आप विकल्प 1 की कोशिश करना चाहते हैं, तो यह की तरह लग रहा यह प्रबंधित पक्ष पर:

[DllImport("NativeDLL.dll", CharSet = CharSet.Unicode)] 
public static extern int GetString(out string str); 

और इस देशी की तरह:

function GetString(out str: PChar): Integer; stdcall; 
begin 
    str = CoTaskMemAlloc(SizeOf(Char)*(Length('abc')+1)); 
    StrCopy(str, 'abc'); 
    Result := 1; // real code would have real error handling 
end; 

प्रबंधित कोड प्रतियां str की सामग्री स्ट्रिंग मान के लिए, यह तो फोन करता है CoTaskMemFree सूचक है कि आप वापस आ पर।

और तुच्छता से कॉल करने के लिए आसान है:

string str; 
int retval = GetString(out str); 
+0

आपको बहुत बहुत धन्यवाद! आपने मुझे इस समस्या से लड़ने के कई घंटे बचाए। – Max

+0

'पीसीहर'? मौका का खेल यह 'पंसिहर' या 'पीवाइडकर' था? (हाँ, हम इसे 64-बिट XE2 को घटा सकते हैं, लेकिन हम यह सुनिश्चित नहीं कर सकते कि यह कोड 64-बिट एफपीसी के साथ संकलित नहीं किया जाएगा या 32-बिट प्रोजेक्ट आदि में कॉपी-पेस्ट नहीं किया जाएगा) –

+0

@ एरियोच 'फिर' PWideChar 'का उपयोग करें आप चाहें तो। –