1

プロトタイプでC++関数を持っているとしましょう

int someFunction(const float ** raws)

float[][]C#の引数を使用してこの関数を呼び出すにはどうすればよいですか?おそらく安全でないコードを使用せずに。

4

2 に答える 2

5

私の知る限り、ほとんどの作業は自分で行う必要があります。Interopは、最上位の配列をマーシャリングするのに役立ちますが、ネストされたすべての配列を固定し、完了したらそれらの固定を解除するのがあなたの仕事になります。このコードは、それを行う1つの方法を示しています。

using System;
using System.Runtime.InteropServices;

namespace ManagedClient
{
    class Program
    {
        [DllImport("UnmanagedDll.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern int UseFloats([MarshalAs(UnmanagedType.LPArray)] IntPtr[] raws);

        static void Main(string[] args)
        {
            float[][] data =
            {
                new[] { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f },
                new[] { 1.0f, 1.1f, 1.2f, 1.3f },
                new[] { 2.0f },
                new[] { 3.0f, 3.1f }
            };

            var handles = new GCHandle[data.Length];
            var pointers = new IntPtr[data.Length];

            try
            {
                for (int i = 0; i < data.Length; ++i)
                {
                    var h = GCHandle.Alloc(data[i], GCHandleType.Pinned);
                    handles[i] = h;
                    pointers[i] = h.AddrOfPinnedObject();
                }

                UseFloats(pointers);
            }
            finally
            {
                for (int i = 0; i < handles.Length; ++i)
                {
                    if (handles[i].IsAllocated)
                    {
                        handles[i].Free();
                    }
                }
            }
        }
    }
}

floatこれにより、ポインターの配列が作成されます。各ポインターは、入力配列のデータを指します。(これは、C関数がデータの到着を期待する形式です。)Cコードがこれらの各サブ配列の長さをどのように認識するかは、ユーザー次第です。私のテストコードでは、C#コードが渡したものと一致するようにハードコーディングしました。

__declspec(dllexport) int __stdcall UseFloats(const float ** raws) 
{
    printf("%f %f %f %f %f\n", raws[0][0], raws[0][1], raws[0][2], raws[0][3], raws[0][4]);
    printf("%f %f %f %f\n", raws[1][0], raws[1][1], raws[1][2], raws[1][3], raws[0][4]);
    printf("%f\n", raws[2][0]);
    printf("%f %f\n", raws[3][0], raws[3][1]);
    return 0;
}

実際には、アンマネージコードに各サブアレイの長さを伝えるために何かをしたいと思うでしょう。選択したアンマネージ関数のシグネチャは、呼び出されたコードに各サブアレイの長さを知る方法を提供しません。(おそらく、float **を使用している理由は、ジャグ配列が必要なためです。そうでない場合、および各サブ配列がまったく同じ長さである場合は、ここでの配列の代わりに長方形の配列を使用する方がはるかに効率的です。ポインタ、そしてそれはマーシャリングも簡単にするでしょう。)

于 2013-02-11T10:21:00.727 に答える
2

Ianはすでにあなたの質問に答えています、私はC++側でSAFEARRAYを使用することを提案したいだけです。

SAFEARRAYは、C / C ++でのあいまいな配列定義の問題に対する、COMの回答です。これらは、基になる要素の数とサイズを含む構造であり、.Net配列により適しています。それらを使用すると、C#からの配列の自動マーシャリングが可能になります。

SAFEARRAYはC++での作業に苦労しますが、ATLには作業を簡単にするための優れたラッパーがいくつかあります。可能であれば、C ++関数を変更して使用するか、C++ラッパーを使用してマーシャリングコードをC++で記述した.Netとの相互運用用のC++ラッパーを作成することを検討してください。

于 2013-02-11T11:08:45.350 に答える