Declare function which its return is 2-point from C++ dll in C#?

后端 未结 1 911
忘了有多久
忘了有多久 2021-01-27 15:05

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          


        
相关标签:
1条回答
  • 2021-01-27 15:51

    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 doubles.

    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 doubles.

    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 doubles 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.Copyied 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 :)

    0 讨论(0)
提交回复
热议问题