gpt4 book ai didi

c# - 从 C# 中的 C++ dll 声明其返回值是 2 点的函数?

转载 作者:行者123 更新时间:2023-11-28 06:44:09 25 4
gpt4 key购买 nike

我在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;
}

现在,我在 C# 中声明这个函数如下:

[DllImport("exDP.dll")]
public static extern IntPtr[2] f(ref int n_);

但是这个声明的语法有错误。

我研究的课题:How to get return array from function with global variable from C++ dll in C#?

如何用这个函数正确声明?谢谢。

编辑:我修复了上面的错误,删除了“2”(数组 IntPtr 的大小),它是:

[DllImport("exDP.dll")]
public static extern IntPtr[] f(ref int n_);

现在,所有的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());
}

}
}

我编译OK。当我运行它时,错误出现在以下行:

ret = f(ref n);

即:无法编码“返回值”:无效的托管/非托管类型组合。

如何修复它并正确获得结果。谢谢。

最佳答案

您应该像处理一维数组一样执行相同的操作。

实际上,C指针(*)只是一个分配在栈上并指向的整数(32位操作系统为4字节,64位操作系统为8字节)包含您的数据的堆上的内存。 C 数组只是数据序列,其元素一个接一个地位于内存中。例如,您代码中的 double* 指向一个 double 数组。

现在,当您创建一个多维数组(例如您的 double**)时,您实际上是在创建一个指向数组的指针数组。也就是说,指针(double*)*实际上指向了一个double*数组,每一个都指向了一个double数组>s.

好吧,我猜你已经知道了:)

现在,关于与 C# 的互操作。在您的案例中,您的 C# 代码需要一个指针类型,即 IntPtr。要正确互操作此代码,您应该再次返回一个 IntPtr 并使用 Marshal.Copy 方法,就像您之前在上一个问题中所做的那样。

但是现在,在第一次调用 Marshal.Copy 之后,您将获得一个指针数组 - 即 IntPtr。对于这些指针中的每一个,您都应该再次调用 Marshal.Copy 以获取您的 double 数组。

代码看起来像这样:

[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***),您将需要再创建一个循环,依此类推。

现在,关于内存泄漏问题。正如其他人所建议的,您可以在将数组传递给 C++ 代码之前在 C# 中创建数组。但是您也可以通过简单地导出另一个函数(我们称之为 clear)并在其中传递原始 IntPtr 来释放 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#:

[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 运行时 is aware of the amount of memory它之前已经为这些指针中的每一个分配了空间,因此您无需担心 delete[] 操作的正确性。但是您必须确保在 Marshal.Copy 数组之后立即调用此函数,因为如果您将通过对 f() 的另一次调用来分配新数组,这个函数会释放新的,旧的会留在内存中。

我希望我已经清除了一些东西,这样您现在就可以开始编写您的项目了:)

关于c# - 从 C# 中的 C++ dll 声明其返回值是 2 点的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25341441/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com