我想在我的C ++ API(dll)中返回一个struct数组。我已经可以返回一个结构并在我的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;
}
如何在此函数中传递数组。我必须做一些内存管理,但我不知道我该做什么。
答案 0 :(得分: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 ++中的数据,否则最终会导致内存泄漏。
答案 1 :(得分: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);
}
答案 2 :(得分:1)
您还可以在调用函数之前分配数组,并传递缓冲区及其大小。在这种情况下,你的C函数将填充数组。
extern "C" EXPORT_API void GetCharacterPositions(CharacterInformation *pArr, int size)
{
for ( int i = 0; i < size; ++ i )
{
//fill pArr[i]
}
}
答案 3 :(得分:-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;
}