【问题标题】:Passing a C# double array to a C++ function using CLI使用 CLI 将 C# 双精度数组传递给 C++ 函数
【发布时间】:2013-03-05 20:55:36
【问题描述】:

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

我在 C# 中有一些 GUI 代码(注意我以前从未使用过 C#,但对语法很熟悉)并且我有 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){} 

但没有编译,通常最后一个带有“数组不是模板”的消息,并且

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

希望这能澄清一点。

【问题讨论】:

  • 您是否尝试将cli 命名空间添加到array&lt;double&gt;^?像这样:cli::array&lt;double&gt;^ values。请注意,还有一个std::array。可能是因为using namespace-directives 造成的命名空间冲突?
  • 你的意思是作为 MyFunction() 中的参数吗? Error 1 error : name followed by "::" must be a class or namespace name 是它的结果,然后是许多预期的“)”错误。如果您的意思是在ImageNoiseFiler 内部,那没有区别。
  • 您实际上并不需要使用 cli 来获得资格。您显示的第三个签名是正确的。当您使用那个时,您会收到什么错误消息?
  • 您确定要使用/clr 选项进行编译吗?我假设您是从 VS 中编译的。如果是这样,则应将适当的选项隐藏在 [your-project]->properties 中的某个位置。
  • error : name followed by "::" must be a class or namespace name error : expected an identifier error : invalid combination of type specifiers error : expected a ")" 这些是我使用第三个时遇到的错误。 /clr 正在使用,是的。

标签: c# c++ arrays pointers c++-cli


【解决方案1】:

您应该使用pin_ptr<> class 将托管数组转换为双精度*。它固定数组,因此当您的本机函数正在执行和访问数组数据时,垃圾收集器无法移动它。

#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() 不会 存储传递的指针。如果是这种情况,那么您必须复制数组。

【讨论】:

  • 恐怕我不确定我是否遵循这个。如果我声明一个接受 pin_ptr 的函数,我会得到这个错误:error C3824: 'cli::pin_ptr&lt;Type&gt;': this type cannot appear in this context (function parameter, return type, or a static member) 如果我把它放在 C# 代码中,它不会接受它。
  • 你把它放在你的 ImageNoiseFilter() 函数中。我猜不出你可能把它放在哪里了。
  • 我已经更新了主帖以突出显示我所做的更改以及我遇到的错误。
【解决方案2】:

好的,所以大多数尝试对我来说都失败了;可能是因为我做错了: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));
}

这一切似乎都很好:),我不知道这种方法有多好或安全,所以任何阅读本文的人都不应该认为它是“正确”的方法,它只是有效。

【讨论】:

  • +1 这正是gcroot 模板在内部所做的。看了你的回答后才发现。谢谢
猜你喜欢
  • 2016-01-15
  • 1970-01-01
  • 2013-02-26
  • 1970-01-01
  • 2016-09-20
  • 2023-02-01
  • 2018-11-14
  • 2019-12-06
  • 1970-01-01
相关资源
最近更新 更多