[英]Passing an array of structs to a function as a parameter
我知道这个问题已经在stackoverflow中出现了很多时间,当我开始研究这个问题时,我在检查了stackoverflow提出的所有问题之后发布了这个问题。
基本上,我想实现这一目标。 大图:将数组结构从c ++ dll传递到ac#应用程序。 这里要注意的是,数组的大小只能由c ++ dll确定。 现在我只知道,可以使用out参数作为函数参数来获取从c ++到c#的任何数组。 是的,我可以将ref作为out参数传递给c ++函数,该参数的大小未知,但已初始化为NULL。 但是我不确定这是对的还是行得通! 另一种方法是,将结构体数组作为返回值,对此我在c#中没有找到任何示例。
所以我做了:将这个问题简化为一个c ++问题 :
我尝试了一些示例示例,以将结构数组从函数返回到main(),从c ++ dll返回到测试c ++应用程序。 ->工作正常。 因此,作为返回值,结构数组可以正常工作。 显然,由于我不必用确切的大小初始化结构数组,因此从一开始就调用函数来填充数组!
但是要注意的是,我需要以一种可以被c#端接收的可行方式来实现它! 因此,作为函数的out参数,而不作为返回值(如果有人知道如何从c ++ dll到c#接收结构数组,请提供帮助!)。
在stackoverflow或google中,有关将结构数组传递给函数的所有问题的大小均已事先确定。 但就我而言,该功能将只能确定大小。 在调用函数之前,我不知道数组的大小。 而且,我实际上是在尝试通过一个函数调用来完成任务,因此,我不能拥有2个API,一个用于计算大小,一个用于获取数组。 这将是一个重复的任务,因为相同的功能必须执行两次,一次只能获取大小,而另一次则需要获取实际的数组,这是不可行的!
我有一个示例代码。 如果有人可以提供帮助,将不胜感激。
// structsEx.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <conio.h>
#include <vector>
#include <string>
using namespace std;
using std::vector;
using std::string;
struct example
{
char* name; // char* or const char*. But not sure if I can have an
// std::string.
int age;
char* company;
};
void passStructsRef(struct example** ex) // Again, not sure if I can have
// std::array or std::vector since
// this will be the API I expose
// to C# side.
{
vector<string> names = {"AAA", "BBB", "CCC", "DDD", "EEE"};
vector<int> ages = {25, 26, 27, 28, 29, 30};
vector<string> companies = { "AAA1", "BBB2", "CCC3", "DDD4", "EEE5" };
*ex = new example[5]; // I think this is a problem. It only initializes
// the first element and hence, I get only the
// first item.
for (int i = 0; i < 5; i++)
{
ex[i] = new example(); // Is this right? Not sure..
ex[i]->age = ages[i];
ex[i]->name = _strdup(names[i].c_str());
ex[i]->company = _strdup(companies[i].c_str());
}
cout << "2 in function" << endl;
for (int i = 0; i < 5; i++)
{
cout << ex[i]->name << "\t" << ex[i]->age << "\t" << ex[i]->company << endl;
}
}
int main()
{
example ex;
ex.age = 30;
ex.name = "AEIOU";
ex.company = "ABCDE";
cout << "1" << endl;
cout << ex.name << "\t" << ex.age << "\t" << ex.company << endl;
cout << "2" << endl;
example *ex2 = nullptr;
passStructsRef(&ex2);
for (int i = 0; i < 5; i++)
{
cout << ex2[i].name << "\t" << ex2[i].age << "\t" << ex2[i].company << endl;
}
_getch();
return 0;
}
注释之后,我想我必须对代码进行一些注释。 我不确定我是否可以在要向C#应用程序公开的代码中使用STL数组或向量或std :: string。 这就是为什么我在这里使用new运算符的原因。 下一个可能出现的问题是删除在哪里? 好吧,我必须有另一个调用delete的API才能删除为该结构分配的内存。 当我的C#应用程序成功接收到我返回的所有数据并对其进行处理后,它将被调用。 那不是问题。 但是将数据发送到C#是一个问题,导致我编写了此示例C ++测试应用程序。
无需编写任何大语法或任何特殊代码即可将数据发送到C#。 如果它在C ++中工作,则必须正确导出参数和API,才能在C#中工作。 这就是为什么我试图使我的C ++完美。
希望这可以帮助。 非常感谢。
实际上,这里有两个问题。
一种是如何返回结构数组。
经典的方式是这样的:
C ++:
int getStructsLength();
int getStructs( int bufferLength, struct example* buffer ); // Returns the count of structures actually written
C#
static extern int getStructsLength();
static extern int getStructs( int bufferLength, [Out, MarshalAs( UnmanagedType.LPArray, SizeParamIndex = 0 )] example[] buffer );
另一个是如何在这些结构中返回字符串。
如果没有太多数据或调用太多,并且无法在Windows上运行,则一种简单的方法是将const char*
更改为BSTR
,并相应地调整C ++代码。 这些是每种语言都知道如何跨DLL边界正确分配/取消分配的Unicode字符串。 唯一的缺点是它们相对较慢。
另一种更复杂的方法是在C#结构中声明以下字段:
[MarshalAs(UnmanagedType.LPStr)] public string name;
在C ++中,用CoTaskMemAlloc和strcpy调用替换strdup(分配时不要忘记终止“ \\ 0”)。 这样,互操作器将根据指针生成.NET字符串后释放这些字符串使用的内存。
最有效的另一种方法是手动编组,即在C#结构中声明以下字段:
public IntPtr name;
在C ++中,更改代码以仅在其中写入c_str()而不进行复制。
在C#中,使用Marshal.PtrToStringAnsi
将它们转换为.NET字符串。 但是请注意,如果在完成自定义编组之前C ++会更改所有这些字符串,则应用程序将崩溃。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.