いくつかの非同期タスクに並列パターン ライブラリを使用する MFC アプリケーションがあります。それらのいくつかは COM オブジェクトを使用するため、そのようなタスクでは COM ライブラリを初期化する必要があります。メイン スレッドは MFC アプリ (MFC アプリ スレッドは STA のみ) であり、タスクがどのトレッド コンテキストで呼び出されるかわからないため、このような場合はすべて COM STA モデルの初期化を使用します。
いくつかの例:
BOOL CMyApp::InitInstance() {
// base initialization
CWinAppEx::InitInstance();
AfxOleInit();
// ... some code ...
// PPL usage
{
Concurrency::task_group aTasks;
// Task1
aTasks.run([&](){
HRESULT hRes = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(hRes)) {
Sleep(100);
::CoUninitialize();
}
});
// Task2
aTasks.run([&](){
HRESULT hRes = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(hRes)) {
Sleep(100);
::CoUninitialize();
}
});
// Task3
aTasks.run([&](){
HRESULT hRes = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(hRes)) {
Sleep(100);
::CoUninitialize();
}
});
aTasks.wait();
}
}
このコードは Windows 7/XP で正常に動作します。しかし、C++ 2012 Platform Toolset を使用する Windows 8.1 では、CoInitializeEx() が RPC_E_CHANGED_MODE エラーを返すため、タスク 1 と 2 が機能しません! タスク 3 は通常、OLE であるメイン MFC スレッド コンテキストで PPL コアによって呼び出され、その COM は既に COINIT_APARTMENTTHREADED として初期化されているため、CoInitializeEx() は成功の S_FALSE コード (二重初期化) を返します。
タスク 2 および 3 の場合、PPL コアは、Windows 7/XP で COM として PRE 初期化されていない個別のスレッドを作成するため、タスクの最初の行で COM を正常に初期化します。 しかし、Windows 8.1 では、すべてのスレッドが COINIT_MULTITHREADED フラグを持つ COM として事前に初期化されているように見え、その後の CoInitializeEx(..., COINIT_APARTMENTTHREADED) 呼び出しはエラーを返します!
なんてこったい!Window 8.1 で正しい COM 初期化ルールを定義するにはどうすればよいですか? 私の間違いはどこですか?PPL は、タスクのスレッド コンテキストに対して保証されておらず、MFC では STA でなければならないメイン スレッドである可能性があります。また、いつ MTA または STA COM 初期化を使用する必要があるかを定義できません。
私を助けてください。これは、2012 C++ プラットフォーム ツールセットの PPL コア コードのエラーか、Windows 8.1 での PPL 使用のエラーでしょうか?