2011-12-25 7 views
7

का उपयोग कर सी से सी # तक बिंदुओं (x, y, z) की वापसी सूची I PLvoke का उपयोग करते हुए मुझे सी डीएल से सी # एप्लिकेशन में पॉइंट्स की एक सूची वापस करने की आवश्यकता है। ये 3 आयामों में अंक हैं [एक्स, वाई, जेड]। अंक की संख्या भिन्न होती है कि यह किस प्रकार का मॉडल है। सी में मैं इसे structs की एक लिंक की सूची संभालता हूं। लेकिन मुझे नहीं लगता कि मैं इसे सी # पर कैसे पास कर सकता हूं।PInvoke

जिस तरह से मैं इसे देखता हूं, मुझे एक लचीली दो आयामी सरणी, शायद एक संरचना में वापस करना होगा।

यह कैसे किया जा सकता है इसके बारे में कोई सुझाव? सी में इसे वापस करने के तरीके और सी # में इसका उपयोग करने के तरीके पर दोनों विचारों की अत्यधिक सराहना की जाती है।

उत्तर

5

एक structs वापस भेजी जा सकती है की सूची से जुड़ा हुआ है, लेकिन यह काफी एक परेशानी से निपटने के लिए किया जाएगा के रूप में आप कामयाब में पढ़ रहे हैं और देशी स्मृति से डेटा की प्रतिलिपि, संकेत लूप करने के लिए कोड लिखने के लिए होता है मेमोरी स्पेस मैं इसके बजाय structs की एक सरल सरणी की सिफारिश करेंगे।

आप निम्नलिखित की तरह एक सी struct है, तो (32-बिट ints कल्पना करते हुए) ...

struct Point 
{ 
    int x; 
    int y; 
    int z; 
} 

... तो आप यह लगभग सी # में एक ही तरह से प्रतिनिधित्व करते हैं चाहते हैं:

[StructLayout(LayoutKind.Sequential] 
struct Point 
{ 
    public int x; 
    public int y; 
    public int z; 
} 

अब एक सरणी वापस पास करने के लिए, अपने मूल कोड को सरणी आवंटित करना और तत्वों में आकार निर्दिष्ट करने वाले अन्य सूचक के साथ इसे पॉइंटर के रूप में वापस पास करना सबसे आसान होगा।

आपका सी प्रोटोटाइप इस प्रकार दिखाई देंगे:

// Return value would represent an error code 
// (in case something goes wrong or the caller 
// passes some invalid pointer, e.g. a NULL). 
// Caller must pass in a valid pointer-to-pointer to 
// capture the array and a pointer to capture the size 
// in elements. 
int GetPoints(Point ** array, int * arraySizeInElements); 

पी/आह्वान घोषणा तो यह होगा:

[DllImport("YourLib.dll")] 
static extern int GetPoints(
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out Point[] array, 
    out int arraySizeInElements); 

MarshalAs विशेषता निर्दिष्ट है कि सरणी आकार निर्दिष्ट का उपयोग कर मार्शल किया जाना चाहिए दूसरे पैरामीटर में (आप एमएसडीएन, "Default Marshaling for Arrays" पर इसके बारे में अधिक पढ़ सकते हैं)।

यदि आप इस दृष्टिकोण का उपयोग करते हैं, तो ध्यान दें कि देशी बफर आवंटित करने के लिए CoTaskMemAlloc का उपयोग करें क्योंकि यह .NET marshaler अपेक्षा करता है। अन्यथा, आपको अपने आवेदन में मेमोरी लीक और/या अन्य त्रुटियां मिलेंगी।

यहाँ एक टुकड़ा सरल उदाहरण से, जबकि मेरा उत्तर की पुष्टि करने संकलित मैं है:

struct Point 
{ 
    int x; 
    int y; 
    int z; 
}; 

extern "C" 
int GetPoints(Point ** array, int * arraySizeInElements) 
{ 
    // Always return 3 items for this simple example. 
    *arraySizeInElements = 3; 

    // MUST use CoTaskMemAlloc to allocate (from ole32.dll) 
    int bytesToAlloc = sizeof(Point) * (*arraySizeInElements); 
    Point * a = static_cast<Point *>(CoTaskMemAlloc(bytesToAlloc)); 
    *array = a; 

    Point p1 = { 1, 2, 3 }; 
    a[0] = p1; 

    Point p2 = { 4, 5, 6 }; 
    a[1] = p2; 

    Point p3 = { 7, 8, 9 }; 
    a[2] = p3; 

    return 0; 
} 

कामयाब फोन करने वाले तो डेटा के साथ सौदा कर सकते हैं बहुत बस (इस उदाहरण में, मैं सभी इंटरॉप कोड एक के अंदर डाल NativeMethods नामक स्थैतिक वर्ग):

NativeMethods.Point[] points; 
int size; 
int result = NativeMethods.GetPoints(out points, out size); 
if (result == 0) 
{ 
    Console.WriteLine("{0} points returned.", size); 
    foreach (NativeMethods.Point point in points) 
    { 
     Console.WriteLine("({0}, {1}, {2})", point.x, point.y, point.z); 
    } 
} 
+0

यह उत्कृष्ट काम करता है। CoTAskMemAlloc के बारे में नहीं पता था। धन्यवाद – user978281

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