将 C++ int* 编组为 C#

Posted

技术标签:

【中文标题】将 C++ int* 编组为 C#【英文标题】:Marshaling C++ int* to C# 【发布时间】:2010-12-06 04:15:40 【问题描述】:

我正在尝试让 dll 工作。

DLL 是用 C++ 编写的,它需要将 int* 传递给 C#。我花了几天的时间来让它工作,但它失败了。我开始拔头发,因为我不知道出了什么问题。我已经尝试了一切。我对 C++ 不像对 C# 那样熟悉,所以问题可能来自那里......

从 dll 中读取正常,但返回的值不正确。我删除了输入,我只是想通过一个测试数组。我在 C++ 中使用的函数是:

extern "C" EAGLE128DLL_API int* encryptFunc()

    //return encrypt(x, Q);

    int t[128];

    for(int i = 0; i < 128; i++)
    
        t[i] = 5;
    

    return t;
;

我用来调用这个函数的C#代码如下:

[DllImport("C:\\Users\\Leon\\Documents\\Visual Studio 2010\\Projects\\Eagle128DLL\\Release\\Eagle128DLL.dll")]
            public static extern IntPtr encryptFunc();
    ...

IntPtr outputPtr = encryptFunc();
int[] output = new int[128];

Marshal.Copy(outputPtr, output, 0, 128);

输出数组中的值应该全是 5。但我得到的是: 16187392、16190224..etc(不是 5 的)

【问题讨论】:

您还应该能够使用 [return: MarshalAs] 属性返回 int[] 而不是 IntPtr 并让编组器为您完成工作: [return: MarshalAs(UnmanagedType.LPArray , SizeConst = 128)] public static extern int[] encryptFunc(); 【参考方案1】:

C++ 代码包含一个错误:您正在返回一个指向存储在堆栈中的变量的指针(t[128] 只是一个临时变量),这将不起作用。只要您的 encryptFunc 返回,call stack will be unwound 和变量 t[128] 就会被丢弃。

如果您的代码不需要可重入或线程安全,您可以简单地将t[128] 设为静态:

static int t[128];
...
return t;

静态变量将不再存储在堆栈中,并将在函数结束后继续存在。

【讨论】:

哈哈简直不敢相信这么简单。最大的拔毛器总是如此简单,以至于一个人都不会想到它......非常感谢! 我猜我应该在静态数组上使用 delete[] 来将它们从内存中删除? 不,不要那样做。仅在已在堆上分配的内存上使用 delete[](使用 new)。您应该不需要删除静态变量。【参考方案2】:

我认为您的问题是您试图返回一个已在 C 函数的堆栈上本地声明的值。

最好的办法是将一个预先分配的数组传递给您的 C 函数,该函数将接收该函数创建的数据并将其返回给调用者。

【讨论】:

以上是关于将 C++ int* 编组为 C#的主要内容,如果未能解决你的问题,请参考以下文章

C# 中的 C++ int & long 编组

将 C++ 类编组为结构

在 C# 中使用“const char*”和“const int”编组我的 C++ .dll

如何通过 IntPtr 将 c++ 数组编组为 c#

将字符串从 c# 编组到 c++

在本机 C++ 中将变量从 C# 编组为 void*,并在本机程序内更改 Managed/C# 中的变量值