現時点では、 IL2CPP スクリプトバックエンドによる Windows Store 向けのプラグイン方式は、 .NET よりはむしろ Unity の他のプラットホーム (Windows スタンドアローン版など) とよく似ています。
.NET スクリプトバックエンドと違って、IL2CPP スクリプトバックエンドは、.NET 4.5 やWindows Runtime API を対象としたマネージドプラグインをサポートしません。すべてのマネージドプラグインは、.NET 3.5 か 同等の API を対象とする必要があります。
.NET スクリプトバックエンドと比べてもう1つの違いは、スクリプトバックエンドでの 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マーシャリングのルールと一致します。
x86 での P/Invoke 関数用デフォルトのコーリングコンベンションは、**stdcall
です。
ネイティブプラグインは、2通りの方法で作成することができます。precompiled DLL とC++ ソースコードです。
ランタイムで DLL を読み込み、関数のエントリーポイントを見つけ、呼び出すことによって、プリコンパイルしたネイティブプラグインを P/Invoke 呼び出しできます。これらの DLL は、ターゲットにする CPU アーキテクチャ用の適切な Windows SDK に対してコンパイルする必要があります。また、DLL は、Unity プロジェクトに追加するとき Plugin インスペクター上でも設定しなければいけません。
Unity プロジェクトに直接 C++ (.cpp) コードファイルを追加することが可能です。それは、プラグインインスペクターでプラグインとして動作します。Windows Store やスクリプトバックエンド上の IL2CPP と互換性があるように設定された場合、これらの C++ ファイルはマネージド・アセンブリから生成されて取得した C++ コードと一緒にコンパイラされます。
関数は生成された C++ コードと一緒にリンクされるので、P/Invoke を行う DLL はありません。このため、DLL の名前の代わりに Internal キーワードを使用することができます。これにより、 Internal キーワードは、関数をランタイムに読み込む代わりに、C++ リンカーに関数を解決させます。
[DllImport("__Internal")]
private static extern int CountLettersInString([MarshalAs(UnmanagedType.LPWSTR)]string str);
呼び出しはリンカーによって解決されるので、マネージサイドで関数の宣言のエラーが発生すると、ランタイムのエラーではなくリンカーのエラーが発生します。これはまた、動的な読み込みがランタイム時に行われる必要がないことを意味し、関数は直接呼び出されます。これによって、P/Invoke 呼び出しのオーバーヘッドは著しく減少します。
Windows Store では、スクリプトバックエンドで IL2CPP を設定する場合、dll の名前(kernelbase.dll のような)を指定することで特定のシステムライブラリに P/Invoke することはできません。プロジェクトの外部に存在する DLL に P/Invoke を試みることでランタイム時 DllNotFoundException になります。
しかし、ビルド時に関数を解決するリンカになる DLL 名に代わって、「**Internal」のキーワードを指定することで、まだこれらのシステム関数に P/Invoke することが可能です。