皆さんは、こんなダイアログを見たことがありますか?
これは、COM のメソッドを呼び出して一定時間応答が無かった場合に発生します。
いつもいつも勝手に出てきて、再試行を選択するとすぐに出てきて、切り替えを選択してもまたすぐに出てきて、あげくキャンセルが Disable になってたりして非常にうざいダイアログです。
特に、応答が無いというのが正当な理由によるものだった場合には、思わず暴れ出したくなります。
これを何とか出さないように出来ないものでしょうか。
自分はずっと、これは COM のネイティブ部分が表示しているから制御するのは無理だと思っていたのですが、実際の所は全然違ってて、こいつは MFC の OLE 部分が IMessageFilter という機構を使って勝手に表示していました。
IMessageFilter は COM のメソッドが呼ばれる前にコールバックされるメソッドであり、ここで本当にメソッドを呼び出すかどうかを設定(フィルタリング)することが可能です。
例えばコネクションポイントで接続した COM にイベントを送信している途中は、その送信した COM 以外のメソッド呼び出しを弾きたい、もしくはメソッド呼び出しを待ってもらいたいという場合、IMessageFilter の HandleInComingCall() というメソッドを使って制御することが可能です。
メソッド呼び出しを待ってもらっている間は特定のメソッド(RetryRejectedCall() と MessagePending())がコールされ続けられるので、そこで待ち時間のタイムアウトを設定することが可能です。
MFC はデフォルトで IMessageFilter を継承した COleMessageFilter というのを設定していて、こいつは一定時間(デフォルトでは10秒)以上待つことになると、COleBusyDialog というのを表示しやがります。
COleBusyDialog というのが↑のダイアログのことです。
そこまで分かれば後は簡単で、COleMessageFilter はダイアログを表示させないようにするためのメソッドがちゃんと用意されているので、
COleMessageFilter* pFilter = ::AfxOleGetMessageFilter();
pFilter->EnableBusyDialog(FALSE);
pFilter->EnableNotRespondingDialog(FALSE);
とやれば、無事ダイアログが表示されなくなります。
ただ、実際には何の解決にもなってないので、本当に固まっている場合はちゃんと原因を突き止めて解決しましょう。
ダイアログが出ても構わないが↑の COleMessageFilter のダイアログはかっこ悪くてダメダメだ、という場合は、COleMessageFilter を継承して OnBusyDialog() と OnNotRespondingDialog() をオーバーライドして、そこで自分の作ったダイアログを表示するようにします。
で、そのクラスをどこかで ::CoRegisterMessageFilter() してやれば、メソッド呼び出しがタイムアウトになったときに自前のダイアログが表示されるようになるかと思います。
ビジー状態ダイアログが表示されて困っている場合は是非試してみてください。