UnityのWindows C++ソースコードプラグインは__declspec(dllexport)しなくてもよい
はじめに
UnityではScripting Backendをil2cppにするとC++のソースを直接Pluginsフォルダに入れて利用できるようになりました。
このうちWindowsのC++ソースコードプラグインのドキュメントは以下の説明とサンプルコードがあります。
関数は生成された C++ コードでまとめてリンクされているため、_P/Invoke への別の DLL はありません
extern "C" __declspec(dllexport) int __stdcall CountLettersInString(wchar_t* str)
{
int length = 0;
while (*str++ != L'\0')
length++;
return length;
}
ですが、まとめてリンクされるなら外部から呼び出されないので__declspec(dllexport)
は宣言しなくてもよいはずです。
そこで本当に宣言しなくてもよいのか検証してみました。
__declspec(dllexport)ありでビルド
ドキュメントと同じ以下のC++ソースコードプラグイン[1:1]と一緒にアプリをビルドして実行すると引数の文字列の長さを返してくれます。
[DllImport("__Internal")]
private static extern int
CountLettersInString([MarshalAs(UnmanagedType.LPWStr)]string str);
extern "C" __declspec(dllexport) int __stdcall CountLettersInString(wchar_t* str)
{
int length = 0;
while (*str++ != L'\0')
length++;
return length;
}
それではビルドしたGameAssembly.dllの定義はどうでしょうか?
>dumpbin /exports GameAssembly.dll | findstr CountLettersInString
2 1 00109360 CountLettersInString = CountLettersInString
dumpbinで確認すると確かにC++ソースコードプラグインに定義した関数がエクスポートされています。
__declspec(dllexport)なしでビルド
今度は以下のように__declspec(dllexport)
だけを削除してビルドしたアプリを実行しても同様に引数の文字列の長さを返してくれます。
extern "C" int __stdcall CountLettersInString(wchar_t* str)
{
int length = 0;
while (*str++ != L'\0')
length++;
return length;
}
先程と同様にGameAssembly.dllの定義を確認すると今度は存在しません。
>dumpbin /exports GameAssembly.dll | findstr CountLettersInString
それならビルドした時に<ProductName>_ButDontShipItWithYourGame
に出力されたソースコードを調べるとAssembly-CSharp.cpp
から以下のようにCountLettersInString
関数を呼び出しています。
このフォルダにはC++ソースコードプラグインのNativeFunctions.cpp
も一緒に出力されているので__declspec(dllexport)
を宣言しなくてもCountLettersInString
関数を呼び出せるのです。
// System.Int32 NewBehaviourScript::CountLettersInString(System.String)
IL2CPP_EXTERN_C IL2CPP_METHOD_ATTR int32_t NewBehaviourScript_CountLettersInString_mED52AF1B6313A9C16FA9E483C3444661B539A17E (String_t* ___str0, const RuntimeMethod* method)
{
typedef int32_t (DEFAULT_CALL *PInvokeFunc) (Il2CppChar*);
// Marshaling of parameter '___str0' to native representation
Il2CppChar* ____str0_marshaled = NULL;
if (___str0 != NULL)
{
____str0_marshaled = ___str0->get_address_of_m_firstChar_1();
}
// Native function invocation
int32_t returnValue = reinterpret_cast<PInvokeFunc>(CountLettersInString)(____str0_marshaled);
return returnValue;
}
まとめ
Windowsでil2cppのC++ソースコードプラグインは__declspec(dllexport)
を宣言しなくても問題なく呼び出せる事が分かりました。
そのためクラック対策などで解析の手掛りを減らす手段の1つとなります。
-
https://docs.unity3d.com/2018.1/Documentation/Manual/WindowsPlayerCPlusPlusSourceCodePluginsForIL2CPP.html ↩︎ ↩︎
-
https://docs.unity3d.com/2018.1/Documentation/Manual/macOSPlayerCPlusPlusSourceCodePluginsForIL2CPP.html ↩︎
-
https://docs.unity3d.com/2018.2/Documentation/Manual/AndroidNativePlugins.html ↩︎
-
https://docs.unity3d.com/520/Documentation/Manual/PluginsForIOS.html ↩︎
Discussion