Version: 2018.4
言語: 日本語
ユニバーサル Windowsプラットフォーム: IL2CPP スクリプトバックエンドを使用して生成したプロジェクト
ユニバーサル Windows プラットフォーム: IL2CPP スクリプティングバックエンドのデバッグ

ユニバーサル Windows プラットフォーム: IL2CPP スクリプティングバックエンドのプラグイン

ユニバーサル Windows プラットフォームのプラグインモデルは、他の Unity プラットフォーム (Windows スタンドアロンなど) に似ています。

マネージプラグイン

デフォルトでは、IL2CPP は .NET 2.0 API の互換性レベルをターゲットにしています。つまり、.NET 4.5 をターゲットとするマネージプラグインや、Windows ランタイム API を使用するマネージラグインはサポートされません。この互換性レベルを使用する場合、すべてのマネージプラグインは .NET 4.5 または同等の API をターゲットにする必要があります。これらの制限を解除したい場合は、Player 設定の .NET 4.6 API 互換レベルに切り替えてください。

注意 .Net 3.5 スクリプティングランタイムは非推奨ですが、Unity 2018.3 と 2018.4 LTS で使用可能になります。.NET 4.x ランタイムを使用して新しいプロジェクトを移行または開始してください。

IL2CPP スクリプティングバックエンドは、Unity エディターやスタンドアロンプレイヤーとまったく同じ .NET API サーフェスを公開します。そのため、ユニバーサル Windows プラットフォームのさまざまな .NET API をターゲットとする別々のバージョンをコンパイルする必要なく、同じプラグインを使用できます。

ネイティブプラグイン

IL2CPP スクリプティングバックエンドは、P/Invoke メカニズムを通したネイティブブラグインの使用をサポートしています。つまり、ネイティブの関数のプロトタイプを指定して呼び出すことによって、C# のコード から直接ネイティブプラグインを呼び出すことができます。

[DllImport("MyPlugin.dll")]
private static extern int CountLettersInString([MarshalAs(UnmanagedType.LPWSTR)]string str);

private void Start()
{
    Debug.Log(CountLettersInString("Hello, native plugin!"));
}

MyPlugin.dll 内でのこの関数の実装は、以下のようになります。

extern "C" __declspec(dllexport)
int __stdcall CountLettersInString(wchar_t* str)
{
    int length = 0;
    while (*str++ != nullptr)
        length++;
    return length;
}

サポートしない以下の型を除き、P/Invoke のマーシャリングルールは、公式の .NET マーシャリングのものと一致します。

  • AnsiBStr
  • Currency
  • SAFEARRAY
  • IDispatch
  • TBStr
  • VBByRefStr

x86 での P/Invoke 関数のデフォルトの呼び出し規約は __stdcall です。

ネイティブプラグインは、2 通りの方法で作成することができます。precompiled DLL と C++ ソースコードです。

プリコンパイルしたネイティブプラグイン

ランタイムで DLL を読み込み、関数のエントリーポイントを見つけ、呼び出すことによって、プリコンパイルしたネイティブプラグインを P/Invoke 呼び出しできます。これらの DLL は、ターゲットにする CPU アーキテクチャ用の適切な Windows SDK に対してコンパイルする必要があります。また、DLL は、Unity プロジェクトに追加するとき Plugin インスペクター上でも設定しなければいけません。

C++ ソースコードのネイティブプラグイン

C++ (.cpp) コードファイルは Unity プロジェクトに直接加えることができ、Plugin インスペクターでプラグインとして動作します。これらのC++ ファイルがユニバーサル Windows プラットフォーム、および IL2CPP スクリプティングバックエンドと互換性があるように設定されている場合は、マネージアセンブリから生成される C++ コードと共にコンパイルされます。

関数は生成された C++ コードと一緒にリンクされるので、P/Invoke を行う DLL はありません。このため、DLL の名前の代わりに Internal キーワードを使用することができます。これにより、 Internal キーワードは、関数をランタイムに読み込む代わりに、C++ リンカーに関数を解決させます。

[DllImport("__Internal")]
private static extern int CountLettersInString([MarshalAs(UnmanagedType.LPWSTR)]string str);

呼び出しはリンカーによって解決されるので、マネージサイドで関数の宣言のエラーが発生すると、ランタイムのエラーではなくリンカーのエラーが発生します。これはまた、動的な読み込みがランタイム時に行われる必要がないことを意味し、関数は直接呼び出されます。これによって、P/Invoke 呼び出しのオーバーヘッドは著しく減少します。

P/Invoke の制限

ユニバーサル Windows プラットフォームでは、IL2CPP スクリプティングバックエンドを使用するときに dll 名(kernelbase.dll など) を指定して、特定のシステムライブラリに P/Invoke を行うことはできません。 プロジェクトの外部に存在する DLL に P/Invoke を行なおうとすると、実行時に DllNotFoundException が発生します。

ただし、 DLL の名前の代わりに kennsaInternal キーワードを指定して、システム関数に P/Invoke を行うことは可能です。これにより、リンカーがビルド時に関数を解決します。

参考資料

Plugin インスペクター


ユニバーサル Windowsプラットフォーム: IL2CPP スクリプトバックエンドを使用して生成したプロジェクト
ユニバーサル Windows プラットフォーム: IL2CPP スクリプティングバックエンドのデバッグ