5

そうです、必要なことは単純に聞こえますが、それは本当に苦痛であることが証明されています.

私はC#でいくつかのGUIコードを持っています(これまでC#を使用したことはありませんが、構文に精通していることに注意してください)。CLIを使用して対話するC++コードがあります。

C# で double の配列を作成し、それを C++ コードに送信したいと考えています。配列を渡す手段として以下のコードを使用していますが、これは単独で準拠しています。

そのため、C# im から 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*' 

これが少し明確になることを願っています。

4

2 に答える 2

3

マネージ配列を 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() が格納しないことが重要であることに注意してください。その場合は、配列をコピーする必要があります。

于 2013-03-17T14:51:17.450 に答える
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);

float ポインターを期待する C++ 関数で取得するには、次のようにします。

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

これはすべてうまくいくようです:)、このアプローチがどれほど優れているか安全かはわかりません。

于 2013-03-17T20:14:30.720 に答える