忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

C++/CLI マネージ配列からネイティブの配列へ変換

さて、今Direct3D 10をC++/CLIから使おうとしているのですが、ここで困ったことがありました。

それは、「せっかくC++/CLIを使っているのだから、.netの配列を使いたい!でもそれをD3D10に渡すやり方がわからない(笑)」というものです。
D3D10のVertexBuffer(モデルの頂点データ)やInputLayout(xnaでいうVertexDeclaration。つまりグラフィックスカードに入力する頂点データがどのように解釈されるかを定義するオブジェクト)では、おそらく.netの配列を使うと便利です(作るのに配列のサイズが必要だからです。sizeofとかで計算してもいいですが、Array.Lengthを使った方が美しいような気がします)

しかし、.netのマネージ配列をそのままネイティブの関数や変数やメソッドとかに渡そうとすると、コンパイルエラーが出ます(cannot convert from 'cli::array<Type> ^' to 'unsigned char *' with [Type=unsigned char])。
おそらく.netのオブジェクトはガベージコレクションが動いた時にアドレスが動くので、そのままではネイティブに渡せないのでしょう(固定しなきゃいけない?)。
これはどうあがいても不可能で、あきらめなきゃいけない・・・ということはないでしょう。
C#ではマネージ配列をネイティブに渡せるので、C++/CLIに出来ないはずがありません。
なにか簡単な方法があるはずです。

で、調べてみたのですが、ありました。(英語ですが)
みんな同じことを考えるんですね。

convert managed array to unmanaged array.  (c++/c#) - GameDev.Net Discussion Forums

つまり、C++/CLIのpin_ptrを使えばいいんです。
これでどうやらメモリを固定できるようです。

なんとmsdnにサンプルもあります。
うーん、きちんとチェックしとけばよかったですね。

How to: Pin Pointers and Arrays

msdnのサンプルが十分わかりやすいので、二番煎じ感が拭えませんが、一応サンプルを作ってみましょう。
#include<stdio.h>

using namespace System;

int main()
{
    array<Byte>^ managedText = gcnew array<Byte>(6);
    managedText[0] = 'H';
    managedText[1] = 'e';
    managedText[2] = 'l';
    managedText[3] = 'l';
    managedText[4] = 'o';
    managedText[5] = '\0';

    pin_ptr<Byte> pinnedText = &managedText[0];
    printf((char *)pinnedText);
}

実行結果は

Hello

です。

これでかんたん(?)に、マネージ配列をネイティブな配列に変換することが出来ます。

拍手[2回]

PR