web-dev-qa-db-ja.com

Marshal.Copyを実行せずにIntPtrをバイト配列にキャストできますか?

IntPtrポインターからバイト配列にデータを取得したいのですが。次のコードを使用して実行できます。

_IntPtr intPtr = GetBuff();
byte[] b = new byte[length];
Marshal.Copy(intPtr, b, 0, length);
_

しかし、上記のコードは、IntPtrからバイト配列へのコピー操作を強制します。問題のデータが大きい場合は、適切なソリューションではありません。

IntPtrをバイト配列にキャストする方法はありますか?たとえば、次のようになります。

byte[] b = (byte[])intPtr

これにより、コピー操作が不要になります。

また:IntPtrが指すデータの長さをどのように決定できますか?

25
TTGroup

他の人が述べたように、コピーせずにmanagedbyte[]にデータを格納する方法はありません(現在の構造で提供されます*)。ただし、実際に必要としない場合マネージドバッファーにある場合は、unsafe操作を使用して、アンマネージメモリ。それは本当にあなたがそれで何をする必要があるかに依存します。

すべてのbyte[]およびその他の参照タイプはCLRガベージコレクターによって管理されます。これが、使用されなくなったときのメモリの割り当てと割り当て解除を担当します。 GetBufferの戻りによって示されるメモリは、C++コードによって割り当てられたアンマネージメモリのブロックであり、(メモリレイアウト/実装の詳細はさておき)、GCマネージメモリとは本質的に完全に分離されています。したがって、GCで管理されたCLR型(byte[])を使用して、IntPtrによってポイントされているアンマネージメモリ内に現在保持されているすべてのデータを含める場合は、それを(コピーして)に移動する必要があります。 GCが認識しているメモリ。これは、Marshal.Copyによって、またはunsafeコードまたはpinvokeを使用するカスタムメソッドによって、または何ができるかによって実行できます。

ただし、それをどのように処理するかによって異なります。あなたはそれがビデオデータだと述べました。データに変換またはフィルターを適用したい場合は、アンマネージバッファーで直接行うことができます。バッファーをディスクに保存する場合は、アンマネージバッファーで直接行うことができます。

長さに関しては、管理されていないメモリバッファの長さを知る方法はありません。ただし、バッファを割り当てた関数が長さを教えてくれない限りは。コメンターが述べたように、これはさまざまな方法で行うことができます(構造の最初のフィールド、メソッドのパラメーター)。

*最後に、C++コードを制御できる場合は、コードを変更して、データを書き込むバッファーの割り当てを行わないようにすることができます。代わりに、事前に割り当てられたバッファーへのポインターが提供されます。次に、managedbyte[]をC#で作成し、C++コードで必要なサイズに事前割り当てし、 GCHandle タイプして固定し、C++コードへのポインターを提供します。

23
jeffora

これを試して:

byte* b = (byte*)intPtr;

nsafe が必要(関数のシグネチャ、ブロック、またはコンパイラフラグ内) /unsafe )。

8
Vinod

管理された配列が管理されていないメモリを占有することはできません。アンマネージデータを一度に1チャンクずつコピーして各チャンクを処理するか、UnmanagedArrayを受け取り、Marshal.Copyを使用してアクセスするインデクサーを提供するIntPtrクラスを作成できます。データ。

@Vinodが指摘したように、unsafeコードでこれを行うことができます。これにより、Cのようなポインターを使用して、メモリに直接アクセスできます。ただし、安全でない.NETメソッドを呼び出す前に、データをマネージメモリにマーシャリングする必要があるため、独自のCのようなコードにかなり制限されます。私はあなたがこれを気にする必要はないと思います、ただC++でコードを書いてください。

3
zmbq

アンマネージ配列を操作するための解決策については、この Code Project ページを確認してください。

1
Tsabo