web-dev-qa-db-ja.com

アンマネージデータをマネージアレイにコピーする

C++/CLI(配列)を使用して、ネイティブ(つまりアンマネージド)データ(バイト*)をマネージドバイト配列にコピーする必要があります。

Marshal :: Copyを試しました(データはconst void * dataによってポイントされ、dataSizeバイトです)

array<byte>^ _Data=gcnew array<byte>(dataSize);
System::Runtime::InteropServices::Marshal::Copy((byte*)data, _Data, 0, dataSize);

これにより、エラーC2665が発生します。16個のオーバーロードはすべて、すべてのパラメーターを変換できません。それから私は試しました

System::Runtime::InteropServices::Marshal::Copy(new IntPtr(data), _Data, 0, dataSize);

これにより、エラーC2664が生成されます。パラメーター1を「constvoid *」から「__w64int」に変換できません。

では、どのようにそれを行うことができ、Marshal :: Copyは実際にそうするための「最良の」(最も簡単/最速の)方法ですか?

18
JeffRSon

" IntPtr "は、 "void *"の単なるラッパーです。新しい構文は必要ありません。明示的な変換演算子を使用するだけです。

System::Runtime::InteropServices::Marshal::Copy( IntPtr( ( void * ) data ), _Data, 0, dataSize );

動作するはずです。

12
Brandon Moretz

お気づきのとおり、Marshal::Copy(および.NET全般)、const- safeではありません。

ただし、通常のCおよびC++関数はそうです。あなたはどちらかを書くことができます:

array<byte>^ data_array =gcnew array<byte>(dataSize);
pin_ptr<byte> data_array_start = &data_array[0];
memcpy(data_array_start, data, dataSize);

またはピン留めを回避するには:

array<byte>^ data_array =gcnew array<byte>(dataSize);
for( int i = 0; i < data_array->Length; ++i )
    data_array[i] = data[i];
13
Ben Voigt

これらの答えはすべて、元の質問の本当の誤解を中心に踊っています。本質的な間違いは、次のコードです。

System::Runtime::InteropServices::Marshal::Copy(new IntPtr(data), 
                                                _Data, 
                                                0, 
                                                dataSize)

intPtrを新規(またはgcnew)しない。その値のタイプ。答えの1つはこれを示していますが、元々の誤解を指摘していません。正しいコードは次のように表現できます。

System::Runtime::InteropServices::Marshal::Copy(IntPtr((void *)data), 
                                                _Data, 
                                                0, 
                                                dataSize)

私が最初にこれらの構造を使い始めたとき、これは私を混乱させました。

IntPtrはC#構造体です。値の型です。

9
Richard K.

C++/CLIコンパイラは、これについて少し鈍感です。 IntPtrの正式な定義は「ネイティブ整数」であり、ポインタ型ではありません。ただし、C++言語では、void *からポインタ型への変換のみが許可されています。 CLIはポインター型をサポートしますが、それらを受け入れるフレームワークメソッドはほとんどありません。 Marshal :: Copy()にはありません。 3つのIntPtrコンストラクターの1つがそうします。

キャストを使用するか、IntPtrコンストラクターを使用して、コンパイラーを頭上で叩く必要があります。 128ビットのオペレーティングシステムでもこれが機能するかどうかは、だれでも推測できますが、しばらくは心配しません。

8
Hans Passant

System :: Runtime :: InteropServices :: Marshal :: Copy(new IntPtr((void *)data)、_ Data、0、dataSize);

(void *) which type-casts from(const void *)に注意してください。新しいIntPtrコンストラクターが引数として受け取ることができます。

1
David Karlaš