呼び元ダイアログを触れないようにするには?

解決


たま  2012-03-05 14:13:41  No: 73215  IP: 192.*.*.*

たまです。
画面表示の仕組みについて質問させてください。

現在、呼び元のダイアログAからファイル選択用ダイアログBをDoModalで呼び出しています。
Bのダイアログにはツリーコントロールとリストコントロールを配置しています。
Bのダイアログでファイルを検索する為、画面表示時に時間がかかりるため、まず、画面を空の状態で表示させ、その後データを読み込み&表示しようと思っています。
そのため、OnInitDialogでは画面のレイアウトの生成後、
最後にB自身にメッセージを送ってデータ表示関数を呼び出すようにしています。

現状、ダイアログAからBを呼び出すとOnINitDialog終了後Bを表示した状態でデータ読み込み処理を行いますが、
データ表示関数処理中に、ダイアログAの右上の×ボタンがクリック出来てしまいます。
データ表示関数の処理を抜けると、ダイアログAは触ることができなくなります。

OnInitDialogを抜けたら画面表示処理は一通り終わるので、ダイアログAは触れなくなると思っていたのですが、違うのでしょうか?

ちなみにデータ表示関数の初めで
this->ShowWindow(SW_SHOW);
this->RedrawWindow();
としており、
この後にフォルダ読み込み&表示処理を行っています。

どの時点で画面生成が終了になるのでしょうか?
宜しくお願いします。

編集 削除
瀬戸っぷ  2012-03-05 14:57:15  No: 73216  IP: 192.*.*.*

一応確認です。

>そのため、OnInitDialogでは画面のレイアウトの生成後、
>最後にB自身にメッセージを送ってデータ表示関数を呼び出すようにしています。

OnInitDialog()の中で、「ファイルを検索」して、一通りデータが揃ってから自分自身にメッセージを発行(PostMessage()?)してOnInitDialog()を抜ける。
という動作なんでしょうか?
その場合は、ファイル検索をやっている間WM_INITDIALOGに応答していない。ということになりますが……。
# まあ、それでも…Aダイアログの「×」ボタン押下は…Aダイアログのメッセージキューに溜まったまま…のような?
# DoModal()のBダイアログを閉じた後で処理されているかと思われますけど…どうなんでしょう??

ワーカースレッド作ってそっちでファイル検索、終わったらメッセージで通知。
というのが妥当かと。
# 同期処理(ファイル検索中にBダイアログが閉じられる…とか)には注意が必要ですが。

編集 削除
たま  2012-03-05 15:43:07  No: 73217  IP: 192.*.*.*

瀬戸っぷ さんコメントありがとうございます。
説明不足で済みません。

ダイアログBのOnInitDialogではフォルダデータ検索処理は行っていません。
フォルダデータの検索と表示は同じ関数で行っていますが、
OnInitDialogの最後でPostMessageして呼び出した関数で行っています。
OnInitDialogはPostMesage後、TRUEで抜けています。

データ検索関数数処理中にダイアログAの×ボタンをクリックすると、
「プログラムが応答していません」メッセージが表示されます。
OKするとアプリが落ち、キャンセルすると処理待ち状態に戻ります。
関数修理中にダイアログBが「応答なし」状態になるのは今の作りでは正しいのですが、
なぜ、ダイアログBをDoModalで呼び出している状態でダイアログAの×がクリック出来るのか、原因がつかめません。

関数が行っている処理自体はSetFileListConditionでツリーコントロールとリストコントロールを連携させ、
ツリーコントロールをCreateTreeしているのですが、検索先がサーバーの場合、処理に10秒ほど時間がかかります。
10秒ほどなので、スレッドを作るほどではないとおもっているのですが・・・

宜しくお願いします。

編集 削除
gak  2012-03-05 19:06:01  No: 73218  IP: 192.*.*.*

> なぜ、ダイアログBをDoModalで呼び出している状態でダイアログAの×がクリック出来るのか、原因がつかめません。
それはゴーストの仕業。ダイアログAに見えて実は別の何か、という状況になっている。
http://msdn.microsoft.com/ja-jp/library/dd744765.aspx

> 10秒ほどなので、スレッドを作るほどではないとおもっているのですが・・・
MS的にはUIスレッドが停まるのは 5 秒が限界らしい。
ゴーストは DisableProcessWindowsGhosting() で防ぐ事は可能だが、其れを善しとするかどうかは別の話。

編集 削除
たま  2012-03-05 19:24:15  No: 73219  IP: 192.*.*.*

gakさん、コメントありがとうございます。

5秒が限界、確かに自分が操作側ですと納得です。
固まっていないことを表現する何かを考えたいと思います。


いろいろ触って確認して気が付いたのですが、
サーバー検索を行う際にサーバーに接続処理を行うCFtpConnectionクラスのGetFtpConnectionを呼んでいる間、ダイアログAがクリックできるようになることがわかりました。
#GetFtpConnectionが戻ってくるとクリックできないようになります。

GetFtpConnectionを呼ぶと現在アクティブなダイアログがアクティブではなくなることがあるのでしょうか?

編集 削除
gak  2012-03-06 13:08:39  No: 73220  IP: 192.*.*.*

> いろいろ触って確認して気が付いたのですが、
ん? ゴースト関係無かった? ↓の様な状況になってるんだと思ったんだが。

1、UIスレッドが5秒以上応答できない状況になった
2、DWM が「1」を検知
3、DWM が対象スレッドに所属するWindow(応答不可状態)を非表示化する
4、非表示化したWindowの代わりに(ユーザの入力を受付可な)ゴーストウィンドウ配置
5、ゴーストに対してユーザ入力が行われた際、ハング中である事を示して強制終了するか応答を待つかを確認

> GetFtpConnectionを呼ぶと現在アクティブなダイアログがアクティブではなくなることがあるのでしょうか?
そんな事は無いハズ。ただUIスレッドを5秒以上停めるとゴーストが出る。で、そのゴーストは最低限(移動、終了等)のユーザ入力可なのでアクティブといえばアクティブ。

> #GetFtpConnectionが戻ってくるとクリックできないようになります。
UIスレッドが動き出し、ゴーストが引っ込んで元Windowが出てきた為じゃなかろうか。

編集 削除
たま  2012-03-12 14:53:44  No: 73221  IP: 192.*.*.*

gakさん、コメントありがとうございます。
別件でごたごたしておりその後の確認が中断していました。

あれからいろいろ動かしてみたところ、gakさんが指摘された様にゴーストが動いたため現象が発生していたようです。

サーバー検索時の処理を5秒未満にすることはできないので、GetFtpConnectionを呼び出す処理をスレッドにし、その間処理中画面を表示させる様に処理の流れを変更しようと思います。

アドバイスありがとうございました。

編集 削除