2011-12-25 50 views
7

我需要使用PInvoke將我從C dll獲得的點列表返回給C#應用程序。這些是三維的點[x,y,z]。點數取決於它的類型。在C中我處理這個結構鏈表。但我不明白我可以如何傳遞給C#。使用PInvoke從C到C#返回列表中的點(x,y,z)

我看到它的方式,我必須返回一個靈活的二維數組,可能在一個結構中。

有關如何做到這一點的任何建議?有關如何在C中返回它以及如何在C#中訪問它的想法都非常感謝。

回答

5

結構鏈接列表可能會返回,但處理起來會非常麻煩,因爲您必須編寫代碼來遍歷指針,將數據從本機內存讀取並複製到託管內存空間。我會推薦一個簡單的結構數組。

如果你有一個C結構類似如下(假設32位整數)...

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

...然後你會代表它幾乎在C#中以同樣的方式:

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

現在要傳回數組,最簡單的方法是讓您的本機代碼分配數組並將其作爲指針傳回,另一個指針指定元素中的大小。

您的C原型可能是這樣的:

// 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); 

的的P/Invoke聲明隨後將是這樣的:

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

MarshalAs屬性指定數組應該使用指定的大小來封在第二個參數中(你可以在MSDN上閱讀更多關於此的信息,"Default Marshaling for Arrays")。

如果您使用這種方法,請注意您需要使用CoTaskMemAlloc來分配本地緩衝區,因爲這是.NET封送處理器所期望的。否則,您的應用程序中將出現內存泄漏和/或其他錯誤。

下面是簡單的例子,我在驗證我的答案編譯的代碼段:

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 2011-12-25 13:53:06

相關問題