D言語でBox2Dを使ってみる。


とりあえずこれで動いたのでメモってみますが、D言語もdllも大して知らないのでつっこみ歓迎です。

連携方針

  • Win32に限定する
  • Box2DではC++で書かれていて、classをふんだんに使ってるのでD言語から直接扱えないっぽい。
  • ので、Cのインターフェースを作ってdll化してみる
  • dll関数の呼び出し規約にはstdcallを使うことにしてみる
    • Win32APIと同じなので調べるのが楽だった。
    • DXライブラリのDllもstdcallな感じっぽい
    • stdcallがベストなのかは謎

dllつくる

Box2Dをもとにして。使いたい関数のラッパーを適当に作る。Cのインターフェースなので、extern "C"で囲ってください。

extern "C"
{
	__declspec(dllexport) int func(int a, int b, int c);
}

みたいな感じでexportする。


D言語からC++インスタンスは直接扱えない(ですよね?)ので、常にdll側で操作するようにする。そのために、インスタンスを作ってポインタを返したり、引数にインスタンスへのポインタを引数にとる関数をつくる。たとえばこんなんでしょうか。

extern "C"
{
	__declspec(dllexport) Object *create_instance();
	__declspec(dllexport) int set_x(Object *o, int x);
	__declspec(dllexport) void delete_instance(Object *o);
}

そんなこんなでBOX2D.DLLができる。

インポートライブラリつくる

こんな感じのBox2D.defを書く。

LIBRARY     "BOX2D.DLL"

EXPORTS
    _func@12
    _create_instance@0
    _set_x@8
    _delete_instance@4

@の後ろの数字は引数のバイト数で、これを間違うとうまくいかないです。


で、このdefからimplibを使ってインポートライブラリBox2D.libを作る。

implib /system Box2D.lib Box2D.def

implibはこの辺からダウンロードできる。
http://www.digitalmars.com/ctg/implib.html

D言語から使う

extern (Windows)
{
	pragma ( lib, "Box2D.lib" );

	int func(int a, int b, int c);
	void* create_instance();
        int set_x(void* o, int x);
	void delete_instance(void *o);
}

これでdll側のfuncが使えるようになります。すごいね!
C++側のインスタンスへのポインタがvoid*なのはアレなので、C++側のクラス名をtypedefしておいたほうがいいかも。

補足

defファイルを

LIBRARY     "lib\BOX2D.DLL"

EXPORTS
    _func@12
    _set_x@8

みたいに書いておけば、DLLをlibディレクトリに突っ込んでおけるので、exeと同じところが散らからずに済む。