2011-12-25 8 views
7

私はCのdllからC#のアプリケーションにPInvokeを使用して持っているポイントのリストを返す必要があります。これらは3次元[x、y、z]の点です。ポイントの数は、どのようなモデルであるかによって異なります。 Cでは、この構造体のリンクリストを扱います。しかし、私はこれをC#にどのように渡すことができないのか分かりません。PInvokeを使用してCからC#へのポイント(x、y、z)のリストを返します。

私はそれを見て、おそらく構造体に柔軟な2次元配列を返す必要があります。

どのようにこれを行うことができますか? Cでそれを返す方法とC#でそれにアクセスする方法の両方のアイデアは非常に高く評価されています。

答えて

5

になる可能性がありますが、ポインタをループするコードを書く必要があり、ネイティブメモリからデータを読み込み、管理対象にコピーする必要がありますメモリ空間。代わりにシンプルな構造体の配列をお勧めします。

あなたは...(32ビットint型を仮定して)次...

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

のようなCの構造体を持っているなら、あなたは、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 /呼び出しの宣言は、このようになります:

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

MarshalAs属性は、配列が指定したサイズを使用してマーシャリングすることを指定します2番目のパラメータ(詳細は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

関連する問題