I have a function in C++ dll with its return is 2-point, as follows:
#include \"stdafx.h\"
#include
using namespace std;
double** _stdcall f(int
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 of 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 :)
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.
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.
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.
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
}
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 :)