使用CLI将c#双精度数组传递给c++函数

Passing a C# double array to a C++ function using CLI

本文关键字:c++ 函数 数组 CLI 双精度 使用      更新时间:2023-10-16

是的,需要做的事情听起来很简单,但事实证明这是一个真正的痛苦。

我在 c# 中有一些GUI代码(注意我以前从未使用过c#,但熟悉语法),我有 c++ 代码,使用CLI与之交互。

在c#中,我想创建一个双精度数组,并将其发送到我的c++代码中。我使用下面的代码作为传递数组的方法,并且这是单独执行的。

所以在c#中,我将一个double[]数组传递给这个函数。

public ref class KernelWrapper
{
public: 
    static void ImageNoiseFilter(System::IntPtr imageData, int imageWidth, int imageHeight, array<double>^ values); 

我应该使用什么参数类型来从c++端检索这个数组?

我试过:

 MyFunction(double values[]){}
 MyFunction(double* values){}
 MyFunction(array<double>^ values){} 

但是没有编译,通常最后一个会显示"array is not a template"的信息,而

Error   1   error C2664: 'RunImageNoiseFilterKernel' : cannot convert parameter 4 from 'cli::array<Type> ^' to 'double *'

如果有任何关于如何做到这一点的建议,我将不胜感激。


为了可读性,我在这里更新了代码

<标题> . cpp文件:
void Bangor::KernelWrapper::ImageNoiseFilter(System::IntPtr imageData, int imageWidth,    int imageHeight, pin_ptr<double> pval){
    RunImageNoiseFilterKernel((Format24bppRgb*)((int)imageData), imageWidth, imageHeight); //If parameter would work, 4th argument would also be passed into this.
}
<标题> c#代码:
    double[] randomValues = new double[ARRAY_LENGTH]; //Array of random numbers
    KernelWrapper.ImageNoiseFilter(ptr, image.Width, image.Height, randomValues);

错误包括:

Error   1   error C3824: 'cli::pin_ptr<Type>': this type cannot appear in this context (function parameter, return type, or a static member)
Error   3   The best overloaded method match for 'Bangor.KernelWrapper.ImageNoiseFilter(System.IntPtr, int, int, double*)' has some invalid arguments   
Error   4   Argument 4: cannot convert from 'double[]' to 'double*' 

您应该使用pin_ptr<>类将托管数组转换为双精度*。它固定数组,所以垃圾收集器不能在本机函数执行和访问数组数据时移动它。

#include <vcclr.h>                 // Declares cli::pin_ptr<>
using namespace cli;
#pragma managed(push, off)
#  include "unmanagedstuff.h"      // Declaration of MyFunction here
#pragma managed(pop)
...
        pin_ptr<double> pvalues = &values[0];
        MyFunction(pvalues, values->Length);

假设MyFunction()也需要知道数组的大小,所以我添加了一个额外的参数来传递数组的大小。不这样做是致命的,您的本机代码可能会破坏托管堆的完整性。请注意,只有当pvalues在作用域中时,数组才会保持固定,因此MyFunction()不存储传入的指针是很重要的。如果是这种情况,那么必须复制数组。

好吧,所以我的大多数尝试都失败了;可能是因为我做错了:P,但这里有一个解决方案确实有效。

进口

:

using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Linq;
在c#文件中,我创建了一个数组:
    float[] randomValues = new float[ARRAY_LENGTH]; //Array of random numbers
    GCHandle handle = GCHandle.Alloc(randomValues, GCHandleType.Pinned);
    var randPtr = handle.AddrOfPinnedObject();
    KernelWrapper.ImageNoiseFilter(ptr, image.Width, image.Height, randPtr);

ImageNoiseFilter的定义为:

static void ImageNoiseFilter(System::IntPtr imageData, int imageWidth, int imageHeight, System::IntPtr randValPtr);

要在我的c++函数中获得一个浮点指针,我这样做:

void KernelWrapper::ImageNoiseFilter(System::IntPtr imageData, int imageWidth, int imageHeight, System::IntPtr randValues){
    RunImageNoiseFilterKernel((Format24bppRgb*)((int)imageData), imageWidth, imageHeight, (float*) ((int) randValues));
}

所有这些似乎都很好:),这种方法有多好或安全我不知道,所以任何读到这篇文章的人都不应该认为这是"正确"的方法,它只是有效的。