我需要使用PInvoke將我從C dll獲得的點列表返回給C#應用程序。這些是三維的點[x,y,z]。點數取決於它的類型。在C中我處理這個結構鏈表。但我不明白我可以如何傳遞給C#。使用PInvoke從C到C#返回列表中的點(x,y,z)
我看到它的方式,我必須返回一個靈活的二維數組,可能在一個結構中。
有關如何做到這一點的任何建議?有關如何在C中返回它以及如何在C#中訪問它的想法都非常感謝。
我需要使用PInvoke將我從C dll獲得的點列表返回給C#應用程序。這些是三維的點[x,y,z]。點數取決於它的類型。在C中我處理這個結構鏈表。但我不明白我可以如何傳遞給C#。使用PInvoke從C到C#返回列表中的點(x,y,z)
我看到它的方式,我必須返回一個靈活的二維數組,可能在一個結構中。
有關如何做到這一點的任何建議?有關如何在C中返回它以及如何在C#中訪問它的想法都非常感謝。
結構鏈接列表可能會返回,但處理起來會非常麻煩,因爲您必須編寫代碼來遍歷指針,將數據從本機內存讀取並複製到託管內存空間。我會推薦一個簡單的結構數組。
如果你有一個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);
}
}
這似乎很好。不知道CoTAskMemAlloc。謝謝 – user978281 2011-12-25 13:53:06