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;
}

在这种情况下,您需要添加一个默认构造函数CharacterInformation并使用两阶段初始化(即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 回答
3

我得到了这个简单的解决方案:

C++

extern "C" EXPORT_API CharacterInformation* GetCharacterPositions(void) {
  std::vector<Character> characters = simulator->getCharacters();   
  CharacterInformation characterInformation;
  CharacterInformation *characterInformationArray = new CharacterInformation[GetCharactersCount()];
  for(int i = 0; i < GetCharactersCount(); i++) {
    characterInformation.id = characters[i].getID();
    characterInformation.x = characters[i].getPosition().x;
    characterInformation.y = characters[i].getPosition().y;
    characterInformationArray[i] = characterInformation;
  } 
  return characterInformationArray;
}

C#

[DllImport("API.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr GetCharacterPositions();

IntPtr characterPositions = GetCharacterPositions();
for (int i = 0; i < GetCharactersCount(); ++i)
{
  var data = new IntPtr(characterPositions.ToInt64() + structSize * i);
  var characterInformation = (CharacterInformation)Marshal.PtrToStructure(data, typeof(CharacterInformation));
  Console.WriteLine("Character with ID: " + characterInformation.id + " X: " + characterInformation.x + " Y: " + characterInformation.y);
}
于 2013-06-06T13:59:34.623 回答
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 回答
-1

你可以考虑我的代码。我使用参考

#include<iostream>

using namespace std;

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 void GetCharacterPositions(CharacterInformation &ci) {
  CharacterInformation ciTmp(0,1,2);
  ci.id = ciTmp.id;
  ci.x = ciTmp.x;
  ci.y = ciTmp.y;
}

int main()
{
    CharacterInformation ci(0,0,0);
    GetCharacterPositions(ci);
    cout<<ci.id<<ci.x<<ci.y<<endl;
    return 0;
}
于 2013-06-03T13:16:27.727 回答