[英]Declare function which its return is 2-point from C++ dll in C#?
I have a function in C++ dll with its return is 2-point, as follows: 我在C ++ dll中有一个函数,其返回值为2点,如下所示:
#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;
}
Now, I declare this function in C# as follows: 现在,我在C#中声明此函数,如下所示:
[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#? 我研究的主题是: 如何从C#中的C ++ dll中获取带有全局变量的函数的返回数组?
How to declare correctly with this function? 如何使用此函数正确声明? Thanks.
谢谢。
Edit: I fixed the error above, remove "2" (the size of array IntPtr) and it's:
编辑:我修复了上面的错误,删除“ 2”(数组IntPtr的大小),它是:
[DllImport("exDP.dll")]
public static extern IntPtr[] f(ref int n_);
Now, all of C# code as follows: 现在,所有C#代码如下:
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);
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. 与一维数组一样,您应该执行相同的操作。
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指针(
*
)只是一个整数(在32位OS中为4字节,在64位OS中为8字节),它分配在堆栈上并指向包含数据的堆上的内存。 C arrays are just sequences of data with elements located in memory one after another. C数组只是数据序列,其元素一个接一个地位于内存中。 For example,
double*
in your code points to an array of double
s. 例如,代码中的
double*
指向double
数组。
Now, when you create a multidimensional array (your double**
, for example), you are actually creating an array of pointers to arrays. 现在,当您创建多维数组(例如,您的
double**
)时,实际上是在创建指向数组的指针的数组。 That means, the pointer (double*)*
actually points to an array of double*
s, and each of them points to an array of double
s. 这意味着指针
(double*)*
实际上指向double*
s的数组,并且每个指针都指向double
s的数组。
Well, I guess you already know that :) 好吧,我想你已经知道了:)
Now, regarding interoperation with C#. 现在,关于与C#的互操作。 Your C# code in your case expects a pointer type, that is,
IntPtr
. 您的C#代码需要一个指针类型,即
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. 要正确地互操作此代码,您应该再次返回
IntPtr
并使用Marshal.Copy
方法,就像之前在上一个问题中所做的那样。
But now, after the first call of Marshal.Copy
, you will get an array of pointers - that is, IntPtr
. 但是现在,在第一次调用
Marshal.Copy
,您将获得一个指针数组-即IntPtr
。 For each of these pointers you should call Marshal.Copy
yet again to get your double
s array. 对于这些指针中的每一个,都应该调用
Marshal.Copy
,再次Marshal.Copy
以获得double
数组。
The code would look some kind like this: 代码看起来像这样:
[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());
}
If you will ever have a three-dimensional array ( double***
), you will need to have one more loop, and so on. 如果您将拥有三维数组(
double***
),则将需要再创建一个循环,依此类推。
Now, regarding the memory leak issue. 现在,关于内存泄漏问题。 You can create your arrays in C# before passing them to the C++ code, as the others suggested.
您可以按照其他建议,在将数组传递给C ++代码之前,使用C#创建数组。 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: 但是,您还可以通过简单地导出另一个函数(让我们将其称为
clear
)并将原始IntPtr
传递到C ++中来释放C ++中的内存:
C++ : 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# : 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
}
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. C运行时知道它先前为每个指针分配的内存量 ,因此您不必担心
delete[]
操作的正确性。 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. 但是您必须确保在拥有
Marshal.Copy
之后立即调用此函数。复制数组,因为如果通过再次调用f()
分配新数组,则此函数将释放新数组,而旧数组将保留在记忆中。
I hope I have cleared some things out so you can now start coding your project :) 我希望我已经清除了一些东西,以便您现在就可以开始对项目进行编码了:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.