简体   繁体   English

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

[英]Passing a C# double array to a C++ function using CLI

Right, what is needed sounds simple, but it is proving to be a real pain. 是的,所需的听起来很简单,但事实证明这是一个真正的痛苦。

I have some GUI code in C# (note i've never used C# before but familiar with the syntax) and I have C++ code which interacts with it using CLI . 我在C#中有一些GUI代码(请注意,我以前从未使用过C#,但是熟悉语法),并且我有C ++代码,可以使用CLI与之交互。

In C#, I want to create an array of doubles, and send it to my C++ code. 在C#中,我想创建一个双精度数组,并将其发送到我的C ++代码。 I'm using the code below as the means of passing an array, and this complies in isolation. 我使用下面的代码作为传递数组的方法,并且这是隔离的。

So from C# im passing in a double[] array into that function. 因此,从C#im中将double []数组传递给该函数。

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

What parameter type should I use to retrieve this array from the C++ side? 我应该使用哪种参数类型从C ++端检索此数组?

I've tried: 我试过了:

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

but none compile, usually with the message of "array is not a template" for the last one, and 但没有一个可以编译,通常最后一个消息是“数组不是模板”,并且

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

Any tips on how this achieve this will be greatly appreciated. 任何有关如何实现此目的的技巧将不胜感激。


For readability, I'm updating with code up here 为了提高可读性,我在这里更新代码

.cpp file: .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# code: C#代码:

    double[] randomValues = new double[ARRAY_LENGTH]; //Array of random numbers
    KernelWrapper.ImageNoiseFilter(ptr, image.Width, image.Height, randomValues);

The errors are: 错误是:

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*' 

Hope this clarifies a little. 希望这可以澄清一点。

You should use the pin_ptr<> class to convert the managed array to a double*. 您应该使用pin_ptr <>类将托管数组转换为double *。 It pins the array so the garbage collector cannot move it while your native function is executing and accessing the array data. 它固定了数组,因此当您的本机函数正在执行和访问数组数据时,垃圾收集器无法移动它。

#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);

With the assumption that surely MyFunction() also needs to know the size of the array so I added an extra argument that passes the size of the array. 假设MyFunction()当然也需要知道数组的大小,因此我添加了一个额外的参数来传递数组的大小。 Not doing this is lethal, your native code is liable to destroy the managed heap integrity. 不这样做会致命,您的本机代码可能会破坏托管堆的完整性。 Note that the array will only stay pinned while pvalues is in scope so it is important that MyFunction() does not store the passed pointer. 请注意,只有在pvalues在作用域内时,数组才会保持固定状态,因此MyFunction() 不要存储传递的指针很重要。 If that's the case then you must copy the array. 如果是这种情况,则必须复制该阵列。

Okay, so most attempts have failed for me; 好吧,所以大多数尝试对我来说都失败了; likely because I'm doing it wrong :P, but here is a solution which does work. 可能是因为我做错了:P,但这是一个有效的解决方案。

Imports: 进口:

using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Linq;

In the C# file, I create an array as so: 在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);

The definition of ImageNoiseFilter is: ImageNoiseFilter的定义是:

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

To obtain in my C++ function which expects a float pointer, I do this: 要在需要浮动指针的C ++函数中获取代码,请执行以下操作:

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

All this seems to work fine :), how good or safe this approach is I do not know, so anyone reading this should not assume its the "correct" approach, it just works. 所有这些似乎都可以正常工作:),我不知道这种方法有多好或多么安全,因此任何阅读此方法的人都不应假定其是“正确”的方法,它才有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM