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;
}
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.
Edit: 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_);
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);
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 arrays are just sequences of data with elements located in memory one after another. For example,double*
in your code points to an array ofdouble
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 ofdouble*
s, and each of them points to an array ofdouble
s.Well, I guess you already know that :)
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 anIntPtr
and useMarshal.Copy
method, as you did before in your previous question.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 callMarshal.Copy
yet again to get yourdouble
s array.The code would look some kind like this:
If you will ever have a three-dimensional array (
double***
), you will need to have one more loop, and so on.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 originalIntPtr
there:C++:
C#:
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 haveMarshal.Copy
ied your arrays, because if you will allocate the new arrays by another call tof()
, 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 :)