Calling CoInitializeEx from DllMain may cause unexpected behavior
Closed this issue · 0 comments
概要
EffekseerPlugin.cpp
の DllMain
関数の中で、CoInitializeEx(NULL, COINIT_MULTITHREADED)
と CoUninitialize()
が呼び出されていますが、これが予期しない動作を引き起こす可能性があります。
説明するのがとても難しいので、Microsoft のドキュメントのリンクをいくつかあげますので、ご覧ください。
-
Some reasons not to do anything scary in your DllMain, part 3
-
INFO: Calling Shell Functions and Interfaces from a Multithreaded Apartment
具体的に発生した問題
-
再現率が 100% ではないため、必ずしも
CoInitializeEx
が原因とは言い切れませんが、しばしば発生している問題を書きます。 -
UnityEditor において、EffekseerForUnity プラグインアセットを追加したプロジェクトで、ファイルダイアログを開く操作 (シーンを開くなど) を実行すると、ダイアログが表示されず、Editor の操作ができなくなることがあります。
再現手順
-
UnityEditor を起動し、エフェクトの設定をしたシーンを開きます。
-
Hierarchy から
Effekseer Emitter
コンポーネントが設定されているオブジェクトを選択し、Scene View に Effekseer の GUI を表示します。 -
数分待ちます。
-
UnityEditor に戻り、ファイルダイアログ(Open Scene, Save as Scene, Create New Animation など)を開く操作をすると、ダイアログが表示されず、Editor の操作ができなくなることがあります。
必ず再現するわけではありませんが、しばらく作業したのち、ファイルダイアログを開こうとしたときに、しばしば発生します。
再現環境
-
OS: Windows 10 1903 64bit (クリーンインストールした環境で再現)
-
Unity: 2018.4.5f1, 2019.2.9f1, Unity 2017.4.32f1
-
Effekseer, EffekseerForUnity: 2019-10-15 時点の master ブランチをビルド。
-
Visual Studio 2019
根拠
-
EffekseerPlugin.cpp
と同様に、DllMain
関数の中で、CoInitializeEx(NULL, COINIT_MULTITHREADED)
とCoUninitialize()
を実行する、ダミーの Unity プラグインを作成したところ、ファイルダイアログが表示されず、Editor の操作ができなくなる現象が再現しました。 -
CoInitializeEx
とCoUninitialize
をコメントアウトすると、再現しなくなるようです。 -
ドキュメントのリンクにあげた中で、マルチスレッドアパートメントから
GetOpenFileName/GetSaveFileName
を呼び出したときの問題が述べられており、これが該当するかもしれません。
ダミーの Unity プラグインのコード
#include "uni-dummy-coinit.h"
UNI_DUMMY_COINIT_API int UNI_PLUGIN_API DummyFunc(int a, int b) {
::OutputDebugString(L"DummyFunc called\n");
return a + b;
}
BOOL APIENTRY DllMain(
HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
) {
HRESULT hr;
wchar_t buffer[256];
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
::_snwprintf_s(buffer, sizeof(buffer) / sizeof(wchar_t), _TRUNCATE, L"DLL_PROCESS_ATTACH, hr = 0x%08X\n", hr);
::OutputDebugString(buffer);
break;
case DLL_THREAD_ATTACH:
hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
::_snwprintf_s(buffer, sizeof(buffer) / sizeof(wchar_t), _TRUNCATE, L"DLL_THREAD_ATTACH, hr = 0x%08X\n", hr);
::OutputDebugString(buffer);
break;
case DLL_THREAD_DETACH:
::CoUninitialize();
::OutputDebugString(L"DLL_THREAD_DETACH\n");
break;
case DLL_PROCESS_DETACH:
::CoUninitialize();
::OutputDebugString(L"DLL_PROCESS_DETACH\n");
break;
}
return TRUE;
}