2

C++ API (dll) で構造体の配列を返したいと思います。既に構造体を返し、これを C# テスト アプリケーションで使用できます。

struct CharacterInformation {
  int id;
  double x;
  double y;
  CharacterInformation(int ID, double X, double Y) : id(ID), x(X), y(Y) {}
};

extern "C" EXPORT_API CharacterInformation GetCharacterPositions(void) {
  //std::vector<Character> characters = simulator->getCharacters(); 
  //CharacterInformation characterInformationArray [] = { CharacterInformation(0, 1, 2) };
  //return characterInformationArray;
  CharacterInformation characterInformation = CharacterInformation(0,1,2);
  return characterInformation;

}

この関数で配列を渡すにはどうすればよいですか。メモリ管理を行う必要がありますが、何をしなければならないかわかりません。

4

4 に答える 4

4

おそらく考えている方法で関数から配列を返すことはできませんが、配列へのポインターを返すことはできます。データを適切な C# 型に適切にマーシャリングできるように、配列の長さも返す必要があります。これには、関数に渡されたパラメーターを介して情報を返す代わりに、関数のシグネチャを少し変更する必要があります。

extern "C" EXPORT_API bool GetCharacterPositions(CharacterInformation** data, int *length)
{
    CharacterInformation *characterInformationArray = new CharacterInformation[arraysize];

    // initialize contents of array.

    // ... snip ...

    *length = arraysize;
    *data = characterInformationArray;

    return true;
}

この場合、デフォルトのコンストラクターを追加して、CharacterInformation2 フェーズの初期化 (つまり、Init()関数) を使用する必要があります。

非静的ローカル変数へのポインターまたは参照を返すべきではないことに注意してください。変数の内容は、スコープ外になると (つまり、関数が戻ると) 破棄されるためです。

データをマーシャリングするには、次のようなことを試すことができます。これはテストされていませんが、正しい方向へのプッシュを与えるはずです。

[DllImport("Dllname.dll", 
    CallingConvention = CallingConvention.Winapi, 
    CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.I1)]
public static extern bool GetCharacterPositions(out IntPtr arrayPtr, out int size);

public static List<CharacterInformation> GetCharacterPositions()
{
  var arrayValue = IntPtr.Zero;
  var size = 0;
  var list = new List<CharacterInformation>();

  if ( !GetCharacterPositions(out arrayValue, out size))
  {
    return list; 
  }

  var dataEntrySize = Marshal.SizeOf(typeof(CharacterInformation));
  for ( var i = 0; i < size; i++)
  {  
    var cur = (CharacterInformation )Marshal.PtrToStructure(arrayValue, typeof(CharacterInformation ));
    list.Add(cur);
    arrayValue = new IntPtr(arrayValue.ToInt32() + dataEntrySize);
  }

  return list;
}

C++ でデータを適切に削除するには、追加の呼び出しを追加する必要があります。そうしないと、メモリ リークが発生します。

于 2013-06-03T11:23:49.123 に答える
1

関数を呼び出す前に配列を割り当て、バッファとそのサイズを渡すこともできます。この場合、C 関数が配列を埋めます。

extern "C" EXPORT_API void GetCharacterPositions(CharacterInformation *pArr, int size)
{
    for ( int i = 0; i < size; ++ i )
    {
       //fill pArr[i]   
    }

}
于 2013-06-03T11:58:46.237 に答える