2013-03-08 4 views
8

मैं सी में लिखा एक डीएल से एक समारोह कॉल करने के लिए सी # इंटरऑप का उपयोग करना चाहता हूँ। मेरे पास हेडर फाइलें हैं I इस पर एक नज़र डालें:मैं इस सी फ़ंक्शन को C# (unmarshalling रिटर्न स्ट्रक्चर) में कैसे कॉल करूं?

enum CTMBeginTransactionError { 
    CTM_BEGIN_TRX_SUCCESS = 0, 
    CTM_BEGIN_TRX_ERROR_ALREADY_IN_PROGRESS, 
    CTM_BEGIN_TRX_ERROR_NOT_CONNECTED 
}; 

#pragma pack(push) 
#pragma pack(1) 
struct CTMBeginTransactionResult { 
    char *      szTransactionID; 
    enum CTMBeginTransactionError error; 
}; 

struct CTMBeginTransactionResult ctm_begin_customer_transaction(const char * szTransactionID); 

मैं कैसे ग # से ctm_begin_customer_transaction कहते हैं। कॉन्स char * mapps को स्ट्रिंग करने के लिए अच्छी तरह से है, लेकिन विभिन्न प्रयासों के बावजूद (स्टैक ओवरफ्लो और अन्य साइटों को देखते हुए), मैं वापसी संरचना को मार्शल करने में विफल रहता हूं। CTMBeginTransactionResult संरचना = (CTMBeginTransactionResult) Marshal.PtrToStructure (PTR, typeof (CTMBeginTransactionResult)): यदि मैं समारोह IntPtr यह ठीक काम करता है वापस जाने के लिए ...

परिभाषित संपादित मैं IntPtr और प्रयोग करने में वापसी प्रकार बदल ; लेकिन यह AccessViolationException

फेंकता मैं भी करने की कोशिश की:

IntPtr ptr = Transactions.ctm_begin_customer_transaction(""); 
int size = 50; 
byte[] byteArray = new byte[size]; 
Marshal.Copy(ptr, byteArray, 0, size); 
string stringData = Encoding.ASCII.GetString(byteArray); 

stringData == "70e3589b-2de0-4d1e-978d-55e22225be95 \ 0 \" \ 0 \ 0 \ एक \ 0 \ 0 \ b \ बी? "इस बिंदु पर।" 70e3589b-2de0-4d1e-978d-55e22225be95 "संरचना से szTransactionID है। एनम कहां है? क्या यह अगला बाइट है?

उत्तर

1

मुझे अपने स्वयं के प्रश्न का उत्तर देने से नफरत है, लेकिन मुझे परिणामस्वरूप संरचना के मार्शल का समाधान मिला। संरचना 8 बाइट लंबी है (चार * के लिए बाइट्स और enum के लिए 4 बाइट्स)। स्ट्रिंग मार्शलिंग स्वचालित रूप से काम नहीं करता है, लेकिन निम्न काम करता है:

// Native (unmanaged) 
public enum CTMBeginTransactionError 
{ 
    CTM_BEGIN_TRX_SUCCESS = 0, 
    CTM_BEGIN_TRX_ERROR_ALREADY_IN_PROGRESS, 
    CTM_BEGIN_TRX_ERROR_NOT_CONNECTED 
}; 

// Native (unmanaged) 
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] 
internal struct CTMBeginTransactionResult 
{ 
    public IntPtr szTransactionID; 
    public CTMBeginTransactionError error; 
}; 

// Managed wrapper around native struct 
public class BeginTransactionResult 
{ 
    public string TransactionID; 
    public CTMBeginTransactionError Error; 

    internal BeginTransactionResult(CTMBeginTransactionResult nativeStruct) 
    { 
     // Manually marshal the string 
     if (nativeStruct.szTransactionID == IntPtr.Zero) this.TransactionID = ""; 
     else this.TransactionID = Marshal.PtrToStringAnsi(nativeStruct.szTransactionID); 

     this.Error = nativeStruct.error; 
    } 
} 

[DllImport("libctmclient-0.dll")] 
internal static extern CTMBeginTransactionResult ctm_begin_customer_transaction(string ptr); 

public static BeginTransactionResult BeginCustomerTransaction(string transactionId) 
{ 
    CTMBeginTransactionResult nativeResult = Transactions.ctm_begin_customer_transaction(transactionId); 
    return new BeginTransactionResult(nativeResult); 
} 

कोड काम करता है, लेकिन मैं अभी भी अगर मेमोरी लीक में अप्रबंधित कोड परिणाम बुला, जांच करने के लिए की जरूरत है।

5

इस संरचना में एक स्मृति प्रबंधन समस्या छिपी हुई है सी स्ट्रिंग पॉइंटर का मालिक कौन है? पिनवोक मार्शलर हमेशा यह मान लेगा कि कॉलर का मालिक है, इसलिए यह स्ट्रिंग को रिलीज़ करने का प्रयास करेगा। और पॉइंटर को CoTaskMemFree() में पास करता है, टी के समान कार्य वह मार्शल द्वारा बुलाया जाता है। फ्रीको टास्कम()। ये फ़ंक्शंस COM मेमोरी आवंटक, विंडोज़ में सार्वभौमिक इंटरऑप मेमोरी मैनेजर का उपयोग करते हैं।

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

तो आप मार्शलर को अपना सामान्य कर्तव्य नहीं दे सकते हैं। आपको वापसी मान प्रकार को IntPtr के रूप में घोषित करना होगा ताकि यह स्ट्रिंग को रिलीज़ करने का प्रयास न करे। और आपको इसे मार्शल के साथ मार्शल करना होगा। PtrToStructure()।

हालांकि अभी भी सवाल अनुत्तरित छोड़ दिया गया है, जो स्ट्रिंग का मालिक है? स्ट्रिंग बफर को रिलीज़ करने के लिए आप कुछ भी नहीं कर सकते हैं, आपके पास सी कोड में उपयोग किए गए आवंटक तक पहुंच नहीं है। आपके पास एकमात्र आशा है कि स्ट्रिंग वास्तव में ढेर पर आवंटित नहीं की गई थी। यह संभव है, सी प्रोग्राम स्ट्रिंग अक्षर का उपयोग कर सकता है। आपको उस अनुमान को सत्यापित करने की आवश्यकता है। एक परीक्षण कार्यक्रम में एक अरब बार समारोह को बुलाओ। यदि वह प्रोग्राम को विस्फोट नहीं करता है तो आप अच्छे हैं। यदि नहीं तो केवल सी ++/सीएलआई आपकी समस्या का समाधान कर सकता है। स्ट्रिंग की प्रकृति को देखते हुए, "लेनदेन आईडी" को बहुत कुछ बदलना चाहिए, मैं कहूंगा कि आपको कोई समस्या है।

+0

आपके उत्तर के लिए धन्यवाद। टिप्पणी मेरे उत्तर देने के लिए एक बुरी जगह है, इसलिए इसके बजाय प्रश्न संपादित किया। संभावित स्मृति रिसाव मुद्दे को खोजने के लिए – Eiver

+0

+1 – Eiver

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