お世話になります。
OS : WinServer 2003
開発環境 : VS2008
現在MFCにてダイアログアプリケーションを作成しています。
プログラム中に重い処理が存在するため、その処理を別スレッドにて実行し、
その処理が完了するまでメッセージダイアログをDoModal()にて表示する。
重い処理が終了後、別スレッドからメッセージダイアログのEndDialog()を呼び出すこと
でメッセージダイアログを閉じる、といった実装を考えています。
//サンプルコード
static UINT AFX_CDECL ThreadProc(LPVOID pParam)
{
CSampleDlg* pDlgSample = (CSampleDlg*)pParam;
//重い処理
execute();
//メッセージダイアログを閉じる
pDlgSample->EndDialog(1);
return 0;
}
void SampleFunc(){
CSampleDlg dlgSample; //メッセージダイアログ
//スレッドを生成
AfxBeginThread(ThreadProc, &dlgSample);
//メッセージダイアログを表示
dlgSample.DoModal();
}
上記コードを実行すると、
//メッセージダイアログを閉じる
pDlgSample->EndDialog(1);
の箇所でアクセス違反が発生してしまいます。
上記方法でダイアログを閉じるのは適切ではないのでしょうか?
また、適切な方法があれば教えて頂けると有難いです。
宜しくお願いします。
スレッドはダイアログに何かメッセージをポストして終る
→ダイアログ側がそのメッセージのハンドラでEndDialog()
ではどうでしょうか.
あと,提示コードの場合だと,
dlgSample.DoModal()の前にスレッドが終わってしまったりすると
どうなるのだろうか? とか個人的に不安になります.
CWnd でなく HWND に対して WM_CLOSE を送ればいけるはず。
> dlgSample.DoModal()の前にスレッドが終わってしまったりすると
御意。
全体的に堅牢性に不安が残るので、もっと安全に実装したほうがいいと思う。
メッセージ用ダイアログは、モードレスにしたほうがいいですね。
すべてのボタンを「なし」に設定するといいと思います。
WM_TIMERでフラグを監視して、重い処理が終了したら
DestroyWindow();を実行して終了する。
でどうでしょうか?
CSampleDlg の OnInitDialogでスレッドをm_AutoDeleteをFALSEで開始して,
あとはタイマで待つ(WaitForMultipleObjectsなんか)
でシグナルで自分(CSampleDlg)をEndDialog
なんかどうでしょ?
DoModal前にスレッドが終わることもないし,
確実にダイアログも終わらせそうです
で,いかがでしょうか
自分の発言は補足です。
CWndは「それを生成したスレッドに依存」してます。
従ってCWndのインスタンスをスレッドをまたいだ処理で利用することはできません。
つまりスレッド関数にCWnd *を渡す方法は、一般にはやってはいけないことです。
ただし、tetrapod さんの発言どおりHWNDを使用した処理は有効ですので、
その目的だけならOKです。
CWndクラスから派生したインスタンスをスレッド間で
やり取りしてはいけないと言うのはマイクロソフトが
はっきりとMSDN内で書いているのでそれを確認してください。
解決手段としては既にHWNDを使った話が出ているので
そちらを使います。
あと、やり方論としてモーダルダイアログの方で
ワーカースレッドを上げて自分自身のHWNDを渡しておいて
ワーカースレッドはモーダルダイアログにユーザー定義の
ウインドウメッセージを送って動作完了を通知する。
モーダルダイアログはウインドウメッセージを受け取ったら
ワーカースレッドの終了を確認して自分自身のEndDialogを
呼び出すでも良さそうな気がしました。
まあ、ワーカースレッドに渡す情報が必要な場合に
一旦、モーダルダイアログに引き渡すような処理が必要に
なるかもしれませんけれど。
がーん、Firefox4にしてからオートコンプリートが
化けるようになっていたの忘れてた。
上の投稿は、私の投稿です。
あしからず。