バイト配列のマーシャリングについて

[戻る]
human 2009/08/26(水) 16:17:21
アンマネージ
unsigned char aaa[8];

マネージ
array<unsigned char>^ bbb;

上記の配列がありこれをマネージ配列aaaからアンマネージ配列bbbへマ
ーシャリングをしたところビルドでエラーとなりました。この記述方法
が正しいかどうかご教授お願いします。

マーシャリング
Marshal::Copy(static_cast<IntPtr>(aaa), bbb, 0, bbb->Length());

エラー内容
error C2064: 0引数を取り込む関数には評価されません。


宜しくお願いします。

human 2009/08/26(水) 16:18:41
失礼しました。

>>上記の配列がありこれをマネージ配列aaaからアンマネージ配列bbbへマ
>>ーシャリングをしたところビルドでエラーとなりました。この記述方法
>>が正しいかどうかご教授お願いします。

マネージ配列bbbからアンマネージ配列aaaの間違いです

human 2009/08/26(水) 17:33:28
たびたびすみません・・・。

>>上記の配列がありこれをマネージ配列aaaからアンマネージ配列bbbへマ
>>ーシャリングをしたところビルドでエラーとなりました。この記述方法
>>が正しいかどうかご教授お願いします。

アンマネージ配列aaaからマネージ配列bbbへのマーシャリングです。

Blue 2009/08/27(木) 10:05:35
引数の数が間違っていますね。
Marshal::CopyはIntPtrを引数に取るので、配列の先頭要素へのポインタをIntPtrにして
から渡します。

unsigned char aaa[8];
array<unsigned char>^ bbb = {1, 2, 3, 4, 5, 6, 7, 8};
System::Runtime::InteropServices::Marshal::Copy(bbb, 0, IntPtr(&aaa[0]),
bbb->Length);


もっとも、C++/CLIなのでmemcpyでもよいかも。

pin_ptr<unsigned char> p = &bbb[0];
memcpy(aaa, p, bbb->Length);

Blue 2009/08/27(木) 10:11:17
あー逆か。

逆でもどうにでもなりそう。

unsigned char aaa[8] = {1, 2, 3, 4, 5, 6, 7, 8};
array<unsigned char>^ bbb = gcnew array<unsigned char>(8);
System::Runtime::InteropServices::Marshal::Copy(IntPtr(&aaa[0]), bbb, 0, 8);

memcpyなら

pin_ptr<unsigned char> p = &bbb[0];
memcpy(p, aaa , bbb->Length);

Blue 2009/08/27(木) 10:13:22
ちなみに
>error C2064: 0引数を取り込む関数には評価されません。>bbb->Length()
に対してのエラーです。
プロパティなので () は不要です。

human 2009/08/27(木) 13:15:26
>>Blueさん

大変分かりやすい説明とサンプルコードありがとうございます。
1点確認ですが

>>引数の数が間違っていますね。
>>Marshal::CopyはIntPtrを引数に取るので、配列の先頭要素へのポインタをIntPtrにし
>>てから渡します。
>>unsigned char aaa[8];
>>array<unsigned char>^ bbb = {1, 2, 3, 4, 5, 6, 7, 8};
>>System::Runtime::InteropServices::Marshal::Copy(bbb, 0, IntPtr(&aaa[0]),
>>bbb->Length);

上記はマネージからアンマネージのマーシャリングですよね。

System::Runtime::InteropServices::Marshal::Copy(bbb, 0, 
static_cast<System::IntPtr>(aaa), bbb->Length);

この書き方でも値がコピーされているように見えるのですがこの記述では駄目なのでしょ
うか?そもそもマーシャリングでstatic_castはよろしくない??

human 2009/08/27(木) 13:17:21
>>ちなみに
>>>error C2064: 0引数を取り込む関数には評価されません。>>>bbb->Length()
>>に対してのエラーです。
>>プロパティなので () は不要です。

ありがとうございます。初歩的なところでハマってました。
このエラーの件については()を外して解決しました。

Blue 2009/08/27(木) 13:36:27
というかIntPtrとvoid*は型が全く違うわけなの(単純なキャストでうまくいくのか)で
IntPtrにvoid*を引数にするコンストラクタがある以上そちらを使うべきかと。
(IntPtrの実装がどうなっているかわからないし。)

subaru 2009/08/27(木) 13:49:54
>System::Runtime::InteropServices::Marshal::Copy(bbb, 0, 
>static_cast<System::IntPtr>(aaa), bbb->Length);
>
>この書き方でも値がコピーされているように見えるのですがこの記述では駄目なのでしょ
>うか?そもそもマーシャリングでstatic_castはよろしくない??

たぶん operator の方が呼ばれて結果は同じということではないかと。
http://msdn.microsoft.com/ja-jp/library/e4y9h1at(VS.80).aspx

Blue 2009/08/27(木) 14:01:27
>たぶん operator の方が呼ばれて結果は同じということではないかと。
メソッドのツリーのほうにあったの気付かなかった。。。(メンバだけみただけ)

でも、個人的には逆の場合はIntPtr::ToPointerを使うわけなんでコンストラクタを使う
やり方のほうが好きですね。

Blue 2009/08/27(木) 14:05:31
>逆の場合はIntPtr::ToPointerを使うわけなんで
ではなかったでした。void*にならoperatorでキャストできますね。
まあ、unsigend char*に一気にキャストできるわけではないですが。
(ToPointerを使ったほうが普通っぽい。)

human 2009/08/27(木) 14:47:13
>>Blueさん

>>というかIntPtrとvoid*は型が全く違うわけなの(単純なキャストでうまくいくのか)で
>>IntPtrにvoid*を引数にするコンストラクタがある以上そちらを使うべきかと。

なるほど確かにおっしゃるとおりですね。

System::Runtime::InteropServices::Marshal::Copy(IntPtr(&aaa[0]), bbb, 0, 8);


試しに上記のコードでアンマネージからマネージへコピーしてみたところビルドは通るの
ですが
パラメータのbbbで"NullReferenceException" が発生しエラーとなりました。

bbbの配列は構造体のpublicなメンバで構造体の中で

[System::Runtime::InteropServices::MarshalAs(UnmanagedType::ByValArray, 
SizeConst=8]
array<unsigned char>^ bbb;

としています。考えられる原因は何でしょうか?

Blue 2009/08/27(木) 15:31:11
bbbの実態を作成していないからではでは?

  >unsigned char aaa[8] = {1, 2, 3, 4, 5, 6, 7, 8};
>>>array<unsigned char>^ bbb = gcnew array<unsigned char>(8);
  >System::Runtime::InteropServices::Marshal::Copy(IntPtr(&aaa[0]), bbb, 0, 8);

human 2009/08/27(木) 16:02:42
Blueさんのご指摘通り実態を生成しないで直接構造体のメンバbbbを見に行っておりまし
た。この場合、一旦、array<unsigned char>^ ccc = gcnew array<unsigned char>(8);
で実態を生成して構造体のメンバbbbにコピーしなければいけないのでしょうか?cccを生
成しなくても直接構造体のメンバbbbの実態を生成出来ますでしょうか?

構造体の定義は以下です。

public value struct TEST
{
public:

[System::Runtime::InteropServices::MarshalAs(UnmanagedType::ByValArray, 
SizeConst=8]
array<unsigned char>^ bbb;

}

マーシャリングをおこなう関数の先頭で

TEST test;

として

System::Runtime::InteropServices::Marshal::Copy(IntPtr(&aaa[0]), test.bbb, 0, 
8);

とするとtest.bbbの実態が生成されていないためエラーとなる。

複数コードにならずに1行で直接test.bbbの実態を生成出来るのでしょうか?あまりテク
ニックがなくて申し訳ございません。

human 2009/08/27(木) 16:11:34
[[解決]]
>>Blueさん

マーシャリングをおこなう関数の先頭で

TEST test;
test.bbb = gcnew cli::array<unsigned char>(8);

と定義したところ構造体メンバbbbの実態が生成出来ました。

この書き方よりスマートな書き方があるかと思いますがこれで問題なく
マーシャリングすることが出来ました。

いろいろとお手数おかけしました。

古いスレッドには追加発言できません。