简体   繁体   English

将结构体数组作为参数传递给函数

[英]Passing an array of structs to a function as a parameter

I know this question has come up a lot of time in stackoverflow and I am posting this question after checking all the questions suggested by stackoverflow when I started this question. 我知道这个问题已经在stackoverflow中出现了很多时间,当我开始研究这个问题时,我在检查了stackoverflow提出的所有问题之后发布了这个问题。

Basically, I want to achieve this. 基本上,我想实现这一目标。 Big picture: Pass an array of structs from c++ dll to ac# application. 大图:将数组结构从c ++ dll传递到ac#应用程序。 The catch here is that, the size of the array can only be determined by the c++ dll. 这里要注意的是,数组的大小只能由c ++ dll确定。 Now I only know that getting an array of anything from c++ to c# is possible with the out parameter as a function argument. 现在我只知道,可以使用out参数作为函数参数来获取从c ++到c#的任何数组。 And yes, I can pass a ref to a c++ function as an out parameter whose size is not known but is initialized to NULL. 是的,我可以将ref作为out参数传递给c ++函数,该参数的大小未知,但已初始化为NULL。 But I am not sure if this is right or if it will work! 但是我不确定这是对的还是行得通! And another way is, to get the array of structs as a return value, for which I didn't find any example in c#. 另一种方法是,将结构体数组作为返回值,对此我在c#中没有找到任何示例。

So what I did: Simplified this problem into a c++ problem : 所以我做了:将这个问题简化为一个c ++问题

I tried some sample examples to return an array of structs from a function to my main(), from a c++ dll to a test c++ application. 我尝试了一些示例示例,以将结构数组从函数返回到main(),从c ++ dll返回到测试c ++应用程序。 --> Works fine. ->工作正常。 So as a return value, an array of structs works fine. 因此,作为返回值,结构数组可以正常工作。 Obviously, because I do not have to initialize my array of structs with the exact size, in the beginning before calling my function to populate the array! 显然,由于我不必用确切的大小初始化结构数组,因此从一开始就调用函数来填充数组!

But the catch is, I need to implement it in a way which will be feasible to be received by the c# end! 但是要注意的是,我需要以一种可以被c#端接收的可行方式来实现它! So, as an out parameter to the function, and not as a return value (if anybody knows how to receive an array of structs from c++ dll to c#, please help!). 因此,作为函数的out参数,而不作为返回值(如果有人知道如何从c ++ dll到c#接收结构数组,请提供帮助!)。

All the questions in stackoverflow or in google about passing an array of structs to a function have their size determined previously. 在stackoverflow或google中,有关将结构数组传递给函数的所有问题的大小均已事先确定。 But in my case, the function will only be able to decide the size. 但就我而言,该功能将只能确定大小。 I do not know the size of the array prior to calling the function. 在调用函数之前,我不知道数组的大小。 And, I am really trying to complete the tasks in a single function call and hence, I cannot have 2 APIs, one for computing the size and one for getting the array. 而且,我实际上是在尝试通过一个函数调用来完成任务,因此,我不能拥有2个API,一个用于计算大小,一个用于获取数组。 It would be a repetitive task since the same functionality has to be executed twice, once to only get the size and another time to get the actual array, which is not feasible! 这将是一个重复的任务,因为相同的功能必须执行两次,一次只能获取大小,而另一次则需要获取实际的数组,这是不可行的!

I have a sample code. 我有一个示例代码。 If anyone can help, it would be really appreciated. 如果有人可以提供帮助,将不胜感激。

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

Following the comment, I think I have to give a bit of comments on my code. 注释之后,我想我必须对代码进行一些注释。 I am not sure if I can use STL arrays or vectors or std::string in my code which I am going to expose to C# application. 我不确定我是否可以在要向C#应用程序公开的代码中使用STL数组或向量或std :: string。 Which is why I am using new operator here. 这就是为什么我在这里使用new运算符的原因。 Next question which might arise is where is delete? 下一个可能出现的问题是删除在哪里? Well, I have to have another API calling delete to delete the memory allocated for the structure. 好吧,我必须有另一个调用delete的API才能删除为该结构分配的内存。 Which will be called by my C# application when it has successfully received all the data I have returned and processed them. 当我的C#应用​​程序成功接收到我返回的所有数据并对其进行处理后,它将被调用。 That is not a problem. 那不是问题。 But sending data to C# is a problem which has led me to write this sample C++ test application. 但是将数据发送到C#是一个问题,导致我编写了此示例C ++测试应用程序。

There is no big syntax or any special code to write to send data to C#. 无需编写任何大语法或任何特殊代码即可将数据发送到C#。 If it works in C++, it has to work in C#, if the parameters and APIs are exported properly. 如果它在C ++中工作,则必须正确导出参数和API,才能在C#中工作。 Which is why I am trying to get my C++ side perfect. 这就是为什么我试图使我的C ++完美。

Hope this helps. 希望这可以帮助。 Thanks a lot in advance. 非常感谢。

There're actually two questions here. 实际上,这里有两个问题。

One is how to return array of structures. 一种是如何返回结构数组。

The classical way is this: 经典的方式是这样的:

C++: C ++:

int getStructsLength();
int getStructs( int bufferLength, struct example* buffer ); // Returns the count of structures actually written

C# C#

static extern int getStructsLength();
static extern int getStructs( int bufferLength, [Out, MarshalAs( UnmanagedType.LPArray, SizeParamIndex = 0 )] example[] buffer );

Another one is how to return strings in these structures. 另一个是如何在这些结构中返回字符串。

If you don't have too much data or too many calls and running on Windows, one simple way is change const char* into BSTR , and adjust C++ code accordingly. 如果没有太多数据或调用太多,并且无法在Windows上运行,则一种简单的方法是将const char*更改为BSTR ,并相应地调整C ++代码。 These are Unicode strings every language knows how to properly allocate/deallocate across DLL boundaries; 这些是每种语言都知道如何跨DLL边界正确分配/取消分配的Unicode字符串。 the only downside is they're relatively slow. 唯一的缺点是它们相对较慢。

Another method, more complex, declare the following field in your C# structure: 另一种更复杂的方法是在C#结构中声明以下字段:

 [MarshalAs(UnmanagedType.LPStr)] public string name;

In C++, replace strdup with CoTaskMemAlloc and strcpy calls (don't forget about terminating '\\0' when allocating). 在C ++中,用CoTaskMemAlloc和strcpy调用替换strdup(分配时不要忘记终止“ \\ 0”)。 This way the interop will free memory used by these strings after making .NET strings from the pointers. 这样,互操作器将根据指针生成.NET字符串后释放这些字符串使用的内存。

Another way, most performant, is do manual marshalling, ie declare the following fields in your C# structure: 最有效的另一种方法是手动编组,即在C#结构中声明以下字段:

 public IntPtr name;

In C++, change the code to just write c_str() there without making copies. 在C ++中,更改代码以仅在其中写入c_str()而不进行复制。

In C#, use Marshal.PtrToStringAnsi to convert them to .NET strings. 在C#中,使用Marshal.PtrToStringAnsi将它们转换为.NET字符串。 But beware if your C++ will change any of these strings before you're done with your custom marshalling, your app will crash. 但是请注意,如果在完成自定义编组之前C ++会更改所有这些字符串,则应用程序将崩溃。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM