UDN
Search public documentation:

DLLBindJP
English Translation
中国翻译
한국어

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

UnrealScript からの DLLs 呼び出し (DLLBind)

ドキュメントの概要: UnrealScript から DLLs を呼び出す方法の説明。

ドキュメントの変更ログ: Jack Porter により作成。

概要

2009 年 12 月バージョンから、UnrealScript には Windows DLL に実装された関数を呼び出す機能が追加されています。この機能は、UDK 開発者や、サードパーティ Unreal Engine 3 製品の拡張開発に取り組む MOD 制作者用に追加されたものです。完全ライセンスを持つ Unreal Engine 3 開発者は、Native クラスを作成 して native コードを 直接呼び出せるので、この機能を使用する必要はありません。ライセンシーのソースコードではデフォルトで無効にされています。有効にするには、UE3BuildWin32.cs の libffi セクションを有効にします。

UnrealScript 側

1 つの UnrealScript クラスは、1 つの dll だけにバインドできます。 DLLBind ディレクティブを使って DLL のバインドを指示し、バインドする DLL の名前をカッコ内に指定します。パスまたは .Dll 拡張子を含めないでください。DLL はBinaries\Win32\UserCode フォルダからのみロードできます。

インポートした関数は、UnrealScript 関数のように dllimport 関数ディレクティブを使って宣言します。

DLL インポート関数は final 宣言にする必要があります。DLLBind クラスのサブクラスは作成できません。

以下に例を示します。

class TestDLLPlayerController extends PlayerController
   DLLBind(TestDLL);

dllimport final function CallDLL1(out string s);
dllimport final function vector CallDLL2(float x, float y, float z);
dllimport final function bool CallDLL3(string s, int i[2], out float f, out vector v);

TestDLLPlayerController クラスがロードされると、Binaries\Win32\UserCode\TestDLL.dll にバインドされます。DLL が見つからない場合はログに警告が残ります。DLL で 3 つのエクスポート (CallDLL1、CallDLL2 および CallDLL3) のエントリポイントを探します。バウンドされたこれらの関数は、他の UnrealScript (Unreal スクリプト) 関数と同様に呼び出されます。バインドに失敗すると、これらの関数のいずれかを呼び出しても何も起こりません。

DLL 側

これらの関数は、C++ DLL で次のように実装できます。

extern "C"
{
   struct FVector
   {
      float x,y,z;
   };

   __declspec(dllexport) void CallDLL1(wchar_t* s)
   {
      MessageBox(0, s, L"Inside the DLL: CallDLL1", MB_OK);
      // reverse the out parameter string (out パラメータ文字列を逆順にする)
      int len = wcslen(s);
      for(int i=0; i<len>>1;i++)
      {
         wchar_t temp = s[i];
         s[i] = s[len-i-1];
         s[len-i-1] = temp;
      }
   }

   __declspec(dllexport) FVector* CallDLL2(float x, float y, float z)
   {
      static FVector result;   // declared static so that the struct's memory is still valid after the function returns. (static 宣言し、関数が戻った後も struct のメモリが有効であるようにする)
      result.x = x;
      result.y = y;
      result.z = z;
      return &result;
   }

   __declspec(dllexport) bool CallDLL3(wchar_t* s, int i[2], float* f, FVector* V)
   {
      wchar_t temp[1024];
      swprintf_s(temp, 1024, L"string: %s, i: {%d,%d}, float: %f, V was (%f,%f,%f)", s, i[0], i[1], *f, V->x, V->y, V->z);
      V->x = (float)i[0];
      V->y = (float)i[1];
      V->z = (*f);
      return (MessageBox(0, temp, L"Inside the DLL: CallDLL3", MB_OKCANCEL) == IDOK);
   }
}

アンロード

DLLBind クラスのクラスオブジェクトが破壊されると、DLL は FreeLibrary API を使ってアンロードされます。これは、最後のクラスオブジェクト参照が削除され、ガーベジコレクションが発生すると発生します。クリーンアップは、DLL の DllMain() 関数で、引数fdwReason がDLL_PROCESS_DETACH のときに応答することで実行できます。

サポートされているパラメータ タイプ

以下のパラメータタイプがサポートされています。

UnrealScript タイプ C タイプ  
int 値 int 値 (32 ビット) 値渡し
int 値[..] int 値 (32 ビット) 参照渡し
out int 値 int* 値 (32 ビット) 参照渡し
float 値 float 値 値渡し
float 値[..] float* 値 参照渡し
out float 値 float* 値 参照渡し
byte 値 unsigned char 値 値渡し
byte 値[..] unsigned char* 値 参照渡し
out byte 値 unsigned char* 値 参照渡し
string 値 wchar_t* 値 参照渡し
out string 値 wchar_t* 値 参照渡し。 下記警告を参照のこと
struct foo struct foo* 値 参照渡し。DLL は UnrealScript の struct に一致する struct を宣言する必要がある。
out struct foo struct foo* 値 参照渡し

以下の戻り値タイプがサポートされています。

UnrealScript タイプ C タイプ  
int int (32 ビット) 値を直接返す
float float 値 値を直接返す
byte unsigned char 値を直接返す
bool unsigned int (32 ビット) 値を直接返す。ゼロ以外の場合 true
string wchar_t* ポインタ値は UnrealScript string に strcpy される。 下記の警告を参照のこと
struct foo struct foo* struct データは UnrealScript struct に memcpy される。 下記の警告を参照のこと

制限事項

  • ユニコード (UTF-16) 文字列のみサポートされています。ユニコード指定の DLL コンパイルは有効です。
  • 利用可能なのは 32 ビットバージョンの UDK だけなので、32 ビットの DLLs だけサポートされています。64 ビットバージョンの UDK が利用可能になる際には、64 ビット DLLs もサポートされます。
  • DLLs は Binaries\Win32\UserCode だけからロードできます。
  • Win32 環境では、stdcall のみサポートされています (呼び出し規則については、こちらのリンク を参照してください)。

警告

  • string out パラメータを変更する場合、新しい文字列は渡される文字列の前の値と同じ長さかそれより短くなければなりません。これには、UnrealScript の string を DLL が格納できる最大値より長い値に初期化します。このようにしなければ、メモリが上書きされ、クラッシュの原因となる可能性があります。
  • 構造体または文字列を返すときに DLL はポインタを返し、Unreal は値を UnrealScript にコピーします。ただし、参照データを格納するためのメモリを確保するのは DLL の役目です。例えば、CallDLL2 のように静的変数へのポインタを返すことができます。スタック上で宣言された変数へのポインタを返すと、DLL 関数が戻ったときにスタックが破壊されるため、データ破損またはクラッシュを引き起こします。
  • UnrealScript struct メンバは 4 バイト境界にアラインされているので、DLL のビルド時に /Zp4 コンパイラオプションを使用できます。
  • DLL が理解できない Unreal データタイプを含む struct を宣言できますが、これは推奨されていません。
  • 現在の作業ディレクトリは UserCode ではなく Binaries\Win32 フォルダに設定されています。したがって、作成した DLL から LoadLibrary を使って別の DLL をロードする場合、または相対パスを使用する他のファイルタイプにアクセスする場合は、作業フォルダの場所に注意する必要があります。2010 年 2 月バージョンでは、任意の DLLBind 関数を呼び出す前に、作業フォルダが UserCode フォルダに変更されるようにする予定です。

サンプル