2011-01-02 30 views
14

私が見たところで、固定{}、Marshal.AllocHGlobal()とGCHandle .Alloc()はこのフォーラム全体を通して、またウェブ上の多くのリンクにあります。しかし、MarshalクラスとGCHandleクラス(固定{}を使用して使用する場合と使用しない場合)を使用するタイミングの簡潔な説明はまだ見つかりません。固定{}、Marshal.AllocHGlobal()とGCHandle.Alloc()の使用の違いを理解する

"バッファ"クラスのReadline()というメソッドを持つサードパーティの.NETライブラリを使用しています。このマニュアルでは、次の関数プロトタイプを示します。

bool ReadLine(int x1、int x2、int y2、System.IntPtr bufData、out int numRead);言いbufDataの説明と

は...メモリ領域は、ライン長回 BytesPerPixelプロパティによって返される値以上のバイト数を有していなければなりません。

今後の彼らはは(私は私の具体的な例を少し微調整しました)バッファにアクセスする例与えないユーザーマニュアルで:

// Create an array large enough to hold one line from buffer 
int size = 640; 
byte[] dataLine = new byte[size * 2]; // 2 bytes per pixel 

// Pin the array to avoid Garbage collector moving it 
GCHandle dataLineHandle = GCHandle.Alloc(dataLine, GCHandleType.Pinned); 
IntPtr dataLineAddress = dataLineHandle.AddrOfPinnedObject(); 

を、私は上記に従うことができます「例」のコード:物語の終わり(と私は上記のコードをテストするためには至っていない)可能性があり

// Read one line of buffer data 
success = buffer.ReadLine(0, 0, 639, 0, dataLineAddress, out numRead); 

// Unpin the array 
dataLineHandle.Free() 

が、私は、.NETのパスを私を運転したGCHandleクラスをグーグルで終わりました相互運用など

ility、PInvokeの、だから私の質問... 1)なぜ私が使用できません。

IntPtr dataLineAddress = Marshal.AllocHGlobal(size * 2); 

とReadLineメソッド(にそれを渡しますか)?

2)私はまた、次のコードスニペット(ウェブ上の例から抽出され、微調整)を使用することができ:私は誰に興味があるだろう

int size = 640; 
byte[] dataLine= new byte[size * 2]; // 2 bytes per pixel 

// prevent garbage collector from moving buffer around in memory 
fixed (byte* fixedDataLine = dataLine) 
{ 
    // get IntPtr representing address of first buffer element 
    IntPtr dataLineAddress= Marshal.UnsafeAddrOfPinnedArrayElement(fixedDataLine , 0); 
    success = buffer.ReadLine(0, 0, 639, 0, dataLineAddress, out numRead); 
} 

を上記の技術に光を当てると指摘することができ上記の方法が適切であることを指摘するだけでなく、実装上の間違いも指摘しています。最後に、上記の方法がすべて有効であっても、過去数年間に1つのアプローチまたは他のアプローチに向かって一般的なプッシュが行われていますか?

ありがとうございます! ハイフード

+0

恐ろしいAPIのようです。 – SLaks

答えて

2

まあ、別の方法もうまくいくでしょう。しかし、Marshal.AllocHGlobalサンプルは完全ではありません。データは管理されていないメモリに格納されています。簡単にアクセスできるように、管理されたオブジェクト(配列)に取り込む必要がありますが、Marshal.Copy()を呼び出す必要があります。非効率なので、データを2回コピーします。 Marshal.FreeHGlobal()を呼び出すことを忘れないでください。

固定サンプルは、ベンダーのサンプルと同じことをし、それが暗黙のうちにメモリをピン。ここでの不自然さは、APIがバイトではなくIntPtrを取ることです。また、の安全でないキーワードを許可するようにコンパイル設定を変更する必要があります。他の方法より効率的ではありません。

あなたは異なっこれを行うことにより、先にありません。

+0

Hans - もし私が "fill"するメモリブロックへのバイトポインタを必要としていた、アンマネージDLL関数を持っていたら、 "Marshal"と "GCHandle"上記のお返事ありがとうございます。 – Hyped

+0

@Hyped - P/Invokeマーシャラーにそれをさせるには常に*あなたの設定をするべきです。それはほとんど常に可能です。あなたの例では、引数を配列として宣言します。 byte []またはPixelData []と同様、PixelDataは2バイトのメンバーを持つ構造体です。 –

関連する問題