2010-12-19 18 views
1

私はあなたの助けが必要です。C#import C DLL。 structの配列ポインタ。の仕方?

C DllをC#プロジェクトにインポートしようとしています。これを実行しながら、私はDllとC#プロジェクトの間の構造体を両方向に渡す必要があります。ここで

はCの定義である:ここで

struct mwBITMAP 
{ 
int bmWidth; 
int bmHeight; 
BYTE* bmData; 
}; 

は、C#の定義である:

[StructLayout(LayoutKind.Sequential)] 
    public struct MwRemoteBmp 
    { 
     public int Width; 
     public int Height; 
     public byte[] Data; 
    } 

私はでDLLのテスト関数にC#のから(データはうまく初期化された)構造体を渡そうとしました参照。幅と高さはどちらも右です。しかし、データはすべて間違っています。

どこでミスをしましたか?

答えて

3

はい、配列はSAFEARRAYとしてマーシャリングされます。 pinvoke marshallerをクラッシュさせないことはかなり珍しいことです。データメンバをIntPtrとして宣言し、Marshal.Copy()を使用してデータをコピーします。

これはCでも使いにくいことに注意してください。メモリ管理の問題があります。誰がアレイを所有しているのかは不明です。最も一般的には、C関数はmalloc()を使用して配列を割り当てます。それは大きな問題です、あなたはC#で配列を解放することはできません。free()を呼び出す方法はありません。あなたは、プラグインできないメモリリークがあります。 Cコードを書き直すことができない場合は、C++/CLI言語でラッパーを記述してfree()を呼び出す必要があります。 CのDLLがC++/CLIコードと同じCRTを使用しない場合でも、それは難しいです。/MDオプションを使用してCコードをコンパイルする必要があります。

+0

ヒントをありがとう。 – MaoWoo

+0

私はデータメンバのメモリをC#でのみ割り当て、Cの構造体を渡してデータの値を変更するとします。 C#のMarshal.FreeHGlobalを呼び出して、完了後にメモリを解放します。それはOKでしょうか? – MaoWoo

+0

はい、値ではなく、データの* content *を変更する限りです。しかし、ビットマップのサイズを知るまでは、どのくらいのメモリを割り当てるのか分かりません。 SAFEARRAY APIを使用していない場合、GlobalAllocを呼び出すことでCの問題を解決できるため、C#でMarshal.FreeHGlobalを使用できます。 –

2

byte []タイプの代わりにIntPtrタイプを使用してください。あなたの例では :

[StructLayout(LayoutKind.Sequential)] 
public struct MwRemoteBmp 
{ 
    public int Width; 
    public int Height; 
    public IntPtr Data; 
} 
+0

ありがとうございました。できます。 – MaoWoo