簡単に言うと、COM inproc-server(dll)で動作するC#アプリケーションで、「0x80010100:システムコールに失敗しました」という例外が発生し、デバッグモードでもContextSwitchDeadlock例外が発生します。
詳細は次のとおりです。
1)C#アプリはSTAを初期化し、COMオブジェクト(「Apartment」として登録)を作成します。次に、inはその接続ポイントにサブスクライブし、オブジェクトの操作を開始します。
2)ある段階で、COMオブジェクトは多くのイベントを生成し、同じアパートで作成されたCOMオブジェクトの非常に大きなコレクションを引数として渡します。
3)C#側のイベントハンドラーは上記のコレクションを処理し、オブジェクトのいくつかのメソッドを呼び出すことがあります。ある段階で、後者の呼び出しは上記の例外を除いて失敗し始めます。
COM側では、アパートはwinprocが次のように見える非表示のウィンドウを使用します。
typedef std::function<void(void)> Functor;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case AM_FUNCTOR:
{
Functor *f = reinterpret_cast<Functor *>(lParam);
(*f)();
delete f;
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
イベントは、COMサーバーの他の部分からこのウィンドウに投稿されます。
void post(const Functor &func)
{
Functor *f = new Functor(func);
PostMessage(hWind_, AM_FUNCTOR, 0, reinterpret_cast<LPARAM>(f));
}
イベントは、実際のパラメータにバインドされた標準のATL CP実装であり、要約すると次のようになります。
pConnection->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &varResult, NULL, NULL);
C#では、ハンドラーは次のようになります。
private void onEvent(IMyCollection objs)
{
int len = objs.Count; // usually 10000 - 25000
foreach (IMyObj obj in objs)
{
// some of the following calls fail with 0x80010100
int id = obj.id;
string name = obj.name;
// etc...
}
}
==================
それで、アパートのメッセージキューが配信しようとするイベントでいっぱいになっているという理由だけで、上記の問題が発生する可能性がありますか?または、そのような動作を引き起こすために、メッセージループを完全にブロックする必要がありますか?
メッセージキューに、「onEvent」呼び出しと評価される2つの連続したイベントがあると仮定します。最初のコードはC#マネージコードを入力します。これは、同じアパートであるアンマネージコードを再入力しようとします。通常、これは許可されており、私たちはこれを頻繁に行います。いつ、どのような状況で失敗する可能性がありますか?
ありがとう。