2

ImageMagick のライブラリにある NewPixelRegionIterator 関数を C# コードから呼び出そうとしましたが、パラメータの受け渡しに問題が発生しました。
具体的には、NewPixelRegionIterator の定義は次のとおりです。

PixelIterator NewPixelRegionIterator(MagickWand *wand,const ssize_t x,
const ssize_t y,const size_t width,const size_t height)

この関数を C# コードにインポートするコードは次のとおりです。

[DllImport("libMagickWandDev.so")]
internal static extern PixelIterator NewPixelRegionIterator(IntPtr MagickWand,  
          IntPtr left, IntPtr top, UIntPtr width, UIntPtr height);

libMagickWand.soではなくlibMagickWandDev.soをインポートするという事実は、libMagickWandDev.so がデバッグ サポートを有効にしてコンパイルされているためです。そのため、gdb で mono を実行して、C 関数の呼び出しに問題があるかどうかを知ることができました (実際には、そうだった)。

gdb で見つかった問題は、次のように NewPixelRegionIterator を呼び出す場合です。

PixelIterator PixIt = PixelIteratorImports.NewPixelRegionIterator(MagickWandPtr,  
         new IntPtr(x), new IntPtr(y), new UIntPtr(1), new UIntPtr(1));

渡される実際のパラメーターは、gdb を介して次のとおりです。

Breakpoint 1, NewPixelRegionIterator (wand=0x7fffffffc7a8, x=10744336, y=5, 
width=6, height=1) at wand/pixel-iterator.c:418
  • 5 と 6 が適切ですが、これらは関数に渡される実際の数値です (ただし、xは 5 に等しく、yは 6 に等しくなければならず、高さは両方とも 1 に等しくなります)。これは、パラメーターの順序が右にシフトされていることを意味し、0x7fffffffc7a8 はおそらく返される構造体の一部であるか、または他の何かです。
  • それが役立つ場合、10744336MagickWandPtr (Magick Wand のアドレス) の値です。これは、gdb でwandパラメーターをこれに設定し、 xを適切な値に設定すると、関数が正常に実行されるためです。
  • PixelIterator は非常に慎重にマップされた構造体です (Marshal.SizeOf と実際の C コードの sizeof() による構造体のサイズが同じ 4192 バイトであることも確認しました)。

もう一度、よろしくお願いします。

4

1 に答える 1

2

PInvoke 関数から構造体を返すことができますか? パラメータ/ポインタを使用して返す必要はありませんか?

パラメーターがシフトされているため、最初または最後のパラメーターとして PixelIterator* 型の隠しパラメーターが必要です。そして、void の return-type。これは、C コンパイラが内部で構造体を返す関数を実装する方法です。

コメントで、 PixelIterator* を返すと問題が解決すると説明しました。その理由はおそらく、C 関数がオブジェクトを割り当て、そのポインターを返すためです。ただし、定義はその手がかりを与えませんでした...とにかく、返されたオブジェクトを使い終わったら、おそらくそのメモリを解放する必要があります。

于 2012-04-06T21:23:36.527 に答える