2

私は近いと思いますし、解決策はばかげているに違いありません。

次の関数を定義する C++ ネイティブ DLL があります。

DllExport bool __stdcall Open(const char* filePath, int *numFrames, void** data);
{
  //creates the list of arrays here... don't worry, lifetime is managed somewhere else

  //foreach item of the list:
  {
      BYTE* pByte = GetArray(i);

      //here's where my problem lives
      *(data + i * sizeofarray) = pByte;
  }
  *numFrames = total number of items in the list
  return true;
}

基本的に、ファイル パスを指定すると、この関数はバイト配列 (BYTE*) のリストを作成し、データ パラメータを介してポインタのリストを返す必要があります。それぞれが異なるバイト配列を指しています。

C# から IntPtr の配列を渡し、個々の配列を順番にマーシャリングできるようにしたいと考えています。私が使用しているコードは次のとおりです。

    [DllImport("mydll.dll",EntryPoint = "Open")]
    private static extern bool MyOpen(
      string filePath, out int numFrames, out IntPtr[] ptr);

    internal static bool Open(
      string filePath, out int numFrames, out Bitmap[] images)
    {
        var ptrList = new IntPtr[512];

        MyOpen(filePath, out numFrames, out ptrList);

        images = new Bitmap[numFrames];
        var len = 100; //for sake of simplicity
        for (int i=0; i<numFrames;i++)
        {
            var buffer = new byte[len];
            Marshal.Copy(ptrList[i], buffer, 0, len);

            images[i] = CreateBitmapFromBuffer(buffer, height, width);
        }

        return true;
    }

問題は私の C++ コードにあります。*(data + i * sizeofarray) = pByte; を割り当てると、ポインターの配列が破損します...何が間違っていますか?

更新: 概念を分離するための新しいソリューションの作成を開始したところ、すでに非常に奇妙なものが見つかりました。見てみましょう:

C# コード

class Program
{
    [DllImport("ArrayProvider.dll")]
    private static extern bool Open(out int n, ref IntPtr[] ptr);


    static void Main(string[] args)
    {
        int n;

        var pList = new IntPtr[10];

        Program.Open(out n, ref pList);

        foreach (var p in pList)
        {
            Debug.WriteLine(p.ToInt32().ToString("X"));
        }
    }
}

C++ コード

#include "stdafx.h"
#define DllExport   __declspec( dllexport )

extern "C" {

DllExport bool __stdcall Open(int *n, void** data)
{
return true;
}

}

ネイティブ コードへの呼び出しの前に、pList には 10 個の IntPtr.Zero 要素があります。ネイティブ呼び出しから戻った後、1 つしかありません...何か問題があります...また、void** を BYTE** に置き換えた場合にも発生します

4

4 に答える 4

4

アンマネージ配列を受け取った場合、ランタイムは配列の長さを知ることができません。配列の長さを指定するには、 SizeParamIndexフィールドと組み合わせてMarshalAsAttributeを使用する必要があります。ここにその例があります。

メソッドのシグネチャを配列の ref IntPtr[] として定義する必要もありません。 InAttributeOutAttributeを使用してください。

元:

private static extern bool Open(out int n,[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] [In,Out] IntPtr[] ptr);
于 2011-01-06T12:41:04.097 に答える
2

変更してみる

out IntPtr[] ptr

ref IntPtr[] ptr

2と微妙な違いがあります。

アップデート:

試す:

data[i] = pByte
于 2011-01-06T06:43:37.390 に答える
2

データvoid*型の場合、これをどのように書くことができますか:

 //you cannot do such pointer arithmetic on void* type.
 *(data + i * sizeofarray) = pByte; 

これを typechar*またはのいずれかに変更しますint*

また、ここでは最後の引数のref代わりに使用します。out

MyOpen(filePath, out numFrames, out ptrList); //wrong

これは修正されたものです:

MyOpen(filePath, out numFrames, ref ptrList); //correct

それに応じてメソッドのシグネチャを変更する必要があります。

于 2011-01-06T06:44:57.427 に答える
1

欲しいと思います

*(data + i * sizeofarray) = pByte;

もっと似たものになる

data[i] = pByte;

したがって、ポインタの配列を何dataを指していても格納することになります。

于 2011-01-06T07:04:53.780 に答える