从C#中的C ++ dll声明返回的函数是2点? [英] Declare function which its return is 2-point from C++ dll in C#?
问题描述
我在C ++ dll中有一个函数,其返回值为2点,如下所示:
I have a function in C++ dll with its return is 2-point, as follows:
#include "stdafx.h"
#include <vector>
using namespace std;
double** _stdcall f(int *n)
{
vector<double> t;
vector<double> X;
int i=0, j=0;
do
{
t.push_back(3*i-4);
X.push_back(2*j);
i++;
j++;
}
while (i<15&&j<90);
*n=i;
double** ret = new double*[2];
for (i=0;i<2;i++)
ret[i]=new double[*n];
for (i=0;i<*n;i++)
{
ret[0][i]=t[i];
ret[1][i]=X[i];
}
return ret;
}
现在,我在C#中声明此函数,如下所示:
Now, I declare this function in C# as follows:
[DllImport("exDP.dll")]
public static extern IntPtr[2] f(ref int n_);
但是此声明的语法有误。
But there is an error for the syntax of this declaration.
I study as topic: How to get return array from function with global variable from C++ dll in C#?
如何使用此正确声明?功能?谢谢。
How to declare correctly with this function? Thanks.
编辑:
我修复了上面的错误,删除了 2(数组IntPtr的大小),它是:
I fixed the error above, remove "2" (the size of array IntPtr) and it's:
[DllImport("exDP.dll")]
public static extern IntPtr[] f(ref int n_);
现在,所有C#代码如下:
Now, all of C# code as follows:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
namespace pABC
{
public partial class frmABC : Form
{
[DllImport("exDP.dll")]
public static extern IntPtr[] f(ref int n_);
public frmABC()
{
InitializeComponent();
}
private void cmdOK_Click(object sender, EventArgs e)
{
int n = 0, i;
IntPtr[] ret = new IntPtr[2];
ret = f(ref n);
double[] t = new double[n];
Marshal.Copy(ret[0], t, 0, n);
double[] X = new double[n];
Marshal.Copy(ret[1], X, 0, n);
MessageBox.Show("X[0]= " + X[0].ToString());
}
}
}
我编译好。当我运行它时,在此行出现错误:
I compile OK. When I run it, an error occurs at the line:
ret = f(ref n);
即:无法编组返回值:无效的托管/非托管类型组合。 / i>
That is: Cannot marshal 'return value': Invalid managed/unmanaged type combination.
如何修复它并正确获得结果。谢谢。
How to fix it and get the results correctly. Thanks.
推荐答案
您应该执行相同的操作,就像处理一维数组一样。
You should do the same, as you did with one-dimension array.
实际上,C指针( *
)只是一个整数(在32位OS中为4字节,在64位OS中为8字节) )分配到堆栈上,并指向包含您的数据的堆上的内存。 C数组只是数据序列,其元素一个接一个地位于内存中。例如,代码中的 double *
指向一个 double
s数组。
In fact, C pointer (*
) is just an integer (4-byte in 32-bit OS and 8-byte in 64-bit OS) that is allocated on the stack and points to a memory on a heap that contains your data. C arrays are just sequences of data with elements located in memory one after another. For example, double*
in your code points to an array of double
s.
现在,当您创建多维数组(例如,您的 double **
)时,实际上是在创建指向数组的指针数组。这意味着指针(double *)*
实际上指向一个 double *
s数组,并且每个数组指向 double
s的数组。
Now, when you create a multidimensional array (your double**
, for example), you are actually creating an array of pointers to arrays. That means, the pointer (double*)*
actually points to an array of double*
s, and each of them points to an array of double
s.
嗯,我想你已经知道了:)
Well, I guess you already know that :)
现在,关于与C#的互操作。您的C#代码需要一个指针类型,即 IntPtr
。要正确地互操作此代码,您应该像以前一样再次返回 IntPtr
并使用 Marshal.Copy
方法
Now, regarding interoperation with C#. Your C# code in your case expects a pointer type, that is, IntPtr
. To correctly interop this code, you should yet again return an IntPtr
and use Marshal.Copy
method, as you did before in your previous question.
但是现在,在第一次调用 Marshal.Copy
之后,您将获得一个数组指针-即 IntPtr
。对于这些指针中的每一个,都应调用 Marshal.Copy
再次获得 double
s数组。
But now, after the first call of Marshal.Copy
, you will get an array of pointers - that is, IntPtr
. For each of these pointers you should call Marshal.Copy
yet again to get your double
s array.
代码看起来像这样:
[DllImport("exDP.dll")]
// x and y are the dimensions of the array.
public static extern IntPtr f(ref int x, ref int y);
private void cmdOK_Click(object sender, EventArgs e)
{
int x, y;
IntPtr ret = f(ref x, ref y);
IntPtr[] t = new IntPtr[x];
Marshal.Copy(ret, t, 0, x);
double[][] X = new double[x][y];
for (int i = 0; i < x; i++)
{
Marshal.Copy(t[i], X[i], 0, y);
}
//MessageBox.Show("X[0]= " + X[0].ToString());
}
如果您将拥有三维数组( double ***
),您将需要再循环一个,以此类推。
If you will ever have a three-dimensional array (double***
), you will need to have one more loop, and so on.
现在,关于内存泄漏问题。您可以按照其他建议,在将数组传递给C ++代码之前,使用C#创建数组。但是,您还可以通过简单地导出另一个函数(我们称其为 clear
)并传递原始的 IntPtr
在那里:
Now, regarding the memory leak issue. You can create your arrays in C# before passing them to the C++ code, as the others suggested. But you can also free the memory in C++ by simply exporting another function (let's call it clear
) and passing the original IntPtr
there:
C ++ :
// x is the first dimension of the array
void __stdcall clear(double** arr, int x)
{
for (int i = 0; i < x; i++)
{
// free all inner arrays
delete[] arr[i];
}
delete[] arr;
}
C#:
[DllImport("exDP.dll")]
public static extern void clear(IntPtr arr, int x);
private void cmdOK_Click(object sender, EventArgs e)
{
int x, y;
IntPtr ret = f(ref x, ref y);
...
for (int i = 0; i < x; i++)
{
Marshal.Copy(t[i], X[i], 0, y);
}
clear(ret, x); // <-- this
}
C运行时知道它先前已为每个分配的内存量这些指针,因此您不必担心 delete []
操作的正确性。但是必须确保在 Marshal.Copy
ied您的数组之后立即调用此函数,因为如果您要通过另一个调用 f()
,此函数将释放新的函数,而旧的函数将保留在内存中。
The C Runtime is aware of the amount of memory it has previously allocated for each of these pointers, so you won't need to worry about the correctness of delete[]
operation. But you must be sure to call this function right after you have Marshal.Copy
ied your arrays, because if you will allocate the new arrays by another call to f()
, this function will free the new ones, and the old ones will stay in memory.
我希望我已经清除了一些事情解决了,所以您现在就可以开始对项目进行编码了:)
I hope I have cleared some things out so you can now start coding your project :)
这篇关于从C#中的C ++ dll声明返回的函数是2点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!