从C#中的C ++ dll声明返回的函数是2点? [英] Declare function which its return is 2-point from C++ dll in C#?

查看:57
本文介绍了从C#中的C ++ dll声明返回的函数是2点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

现在,当您创建多维数组(例如,您的 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 doubles.

嗯,我想你已经知道了:)

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

这篇关于从C#中的C ++ dll声明返回的函数是2点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆