スレッド内でCDialog::OnCancel

解決


名古屋  2005-05-13 06:25:38  No: 57384

お世話になります。

スレッド内でCDialog::OnCancelをすると、
実行しているスレッドのクラスのメンバ変数の
値がクリアされてしまいます。

CDialog::OnCancel(画面を閉じる)後もクラスのメンバ変数
にアクセスしたいのですが、方法はあるでしょうか。


huruya  2005-05-13 18:42:07  No: 57385

画面を閉じるときにShowWindowで非表示にしたらどうですか??
今回閉じてアクセスしたいクラスというのが子画面なら
この方法で大丈夫だと思います。
他に方法があるかもしれませんが。


名古屋  2005-05-13 20:04:21  No: 57386

回答ありがとうございます。

>今回閉じてアクセスしたいクラスというのが子画面なら
>この方法で大丈夫だと思います。

質問の説明不足でした。
閉じた後の処理は、ビュークラスを親に持つ画面を表示する処理を
行うようにしたいです。

この場合、やはり一度画面を閉じる必要があるでしょうか?

なお、閉じる画面もビュークラスを親にもつ画面です。


名古屋  2005-05-13 20:15:41  No: 57387

追加で質問させてください。

スレッド化する前は、CDialog::OnCancel後もクラスのメンバ変数
はクリアされなかったので、スレッド化後にクリアされてしまう
理由をご教授願いたいと思っています。
宜しくお願いします。


WIZ  2005-05-14 02:36:43  No: 57388

> スレッド化する前は、CDialog::OnCancel後もクラスのメンバ変数
> はクリアされなかったので、スレッド化後にクリアされてしまう
> 理由をご教授願いたいと思っています。

CDialog::OnCancel してもダイアログクラスのインスタンスは破棄されません。
従って、インスタンス内のメンバにアクセス可能な筈です。

# ここからは、エスパーモードで回答します。

ダイアログクラスのインスタンスがスレッド内のローカル変数であるとか、
スレッド開始時に new で生成し、スレッド終了時に delete で破棄するように
なっている。そして、ダイアログを閉じるとスレッドを終了するようになって
いるとか?


名古屋  2005-05-14 06:07:16  No: 57389

回答ありがとうございます。

>CDialog::OnCancel してもダイアログクラスのインスタンスは破棄されません。
>従って、インスタンス内のメンバにアクセス可能な筈です。

失礼しました。
CDialog::OnCancelでは変数は破棄されていませんでした。
CDialog::OnCancelの次にAfxMessageBox関数にてメッセージボックス
を表示しているのですが、「はい」または「いいえ」を選択後
メッセージボックスを閉じた後、インスタンスが破棄されていました。
VC++では、そのような動作をするのでしょうか?また回避方法はあるでしょうか?

あと、もう一点質問ですが、
スレッド処理の終盤でモードレスダイアログ(ビューが親)を表示している
のですが、ダイアログが表示されません。(スレッド化前は表示されてます。)

なお、モードレスダイアログ表示処理後、スレッドおよびダイアログは終了
した状態となります。

表示されない理由をご教授ください。
宜しくお願いします。


WIZ  2005-05-14 17:10:12  No: 57390

言葉だけで書くと(回答者が)誤解する可能性があるので、コードを示してください。
例えば以下のような(ひとつの関数内の連続した)コードだと思っていますが
あっていますか?

CAAADlg aaaDlg(...);
aaaDlg.DoModal(); // aaaDlg の CANCEL ポタンをクリックし、
                  // CDialog::OnCancel が実行され、aaaDlg が閉じる。

// インスタンス aaaDlg はまだ破棄されていない。

AfxMessageBox(...); //「はい」または「いいえ」を選択してメッセージボックスを閉じる

// インスタンス aaaDlg が破棄されている?そんなことは無い筈だか・・・。

CBBBDlg bbbDlg(...);
bbbDlg.Create(...); // モードレスダイアログが表示されない?

// スレッド終了処理


名古屋  2005-05-14 22:17:22  No: 57391

回答ありがとうございます。
月曜日に会社で確認します。

ただ、概ねコードはあっています。
AfxMessageBox(...); のひとつ前に
OnCanCel()を実行しています。
ちなみに、このOnCancel()を実行しなければ
クラスのメンバ変数は破棄されません。


WIZ  2005-05-17 21:53:00  No: 57392

> ただ、概ねコードはあっています。
> AfxMessageBox(...); のひとつ前に
> OnCanCel()を実行しています。

以下のようにコーディングしていると言う意味でしょうか?
OnCancel は IDCANCEL のポタンクリックのハンドラですので、下記のような
使い方は誤りです。

CAAADlg aaaDlg(...);
aaaDlg.DoModal();
aaaDlg.OnCancel();


名古屋  2005-05-18 06:19:36  No: 57393

回答ありがとうございます。

>以下のようにコーディングしていると言う意味でしょうか?
>OnCancel は IDCANCEL のポタンクリックのハンドラですので、下記のような
>使い方は誤りです。

誤解があるといけないので、
コードを整理しました。

//ビュークラスの関数(或るメニューを選択したときの処理)
void CXXXView::OnMenu() 
{
  CDlgXXX dlg;

  dlg.DoModal();    //モーダルでダイアログ開く
}

//ダイアログ表示前の処理
BOOL CDlgXXX::OnInitDialog() 
{
  CDialog::OnInitDialog();

  SetTimer(0 , 500 , NULL); //表示と同時に長い処理
                                  //が実行されるので、SetTimer関数により
                                  //ダイアログを表示する
  return TRUE;  
}

//タイマ起動後の処理
void CDlgXXX::OnTimer(UINT nIDEvent) 
{
  KillTimer(nIDEvent);

  //スレッド起動
  m_pThread = AfxBeginThread(ThreadFunc , this );    

}

//スレッドから呼び出される関数
UINT CDlgXXX::ThreadFunc( LPVOID pParam )
{
  ((CDlgXXX*)pParam)->CrtAjtMain();

  return 0;
}

//メイン処理
void CDlgXXX::CrtAjtMain()
{
   メイン処理・・・

   OnCancel();
   AfxMessageBox("メッセージ" , MB_YESNO|MB_APPLMODAL|MB_ICONQUESTION                       |MB_DEFBUTTON1) == IDYES)
  {
    ・・・
  }
  
   CDlgYYY* dlg = new CDlgYYY;
    //モードレスダイアログ表示
   dlg->Create( IDD_DLGYYY, m_pView );
                           //m_pView:ビューオブジェクトへのポインタ 
                            //(CDlgXXXのメンバ変数)
}

上記のコードで、
OnCancel();
AfxMessageBox(...);
の処理後、変数m_pView(ビューへのポインタ)が
クリアされてしまいました。

また、OnCancel();をコメントアウトし実行したら、
変数m_pViewの値は保持されるのですが、
モードレスダイアログが表示されません。

上記のコードで、何か問題点があればご指摘ください。
なかなかうまく動作しなくて困っています。

あと、上記のコードで、
プロジェクトの設定の、「C/C++ -コード生成-ランタイムライブラリ」の
「マルチスレッド」を選択
をする必要はあるでしょうか?


REE  2005-05-18 19:27:26  No: 57394

OnCancel();の実行により、以下の処理が元の“別スレッド”で同時進行されます。
CXXXView::OnMenuで開いていたCDlgXXXが閉じ、CXXXView::OnMenu関数が終了します。そして同時のその関数のローカル変数であるdlgが破棄されます。

その時点で、CDlgXXXのメンバ変数は使用不能になります。

またMFCでは、スレッドまたいでの、CWndオブジェクトのポインタによるウインドウ操作は保証されていません。


名古屋  2005-05-18 20:15:16  No: 57395

回答ありがとうございます。

>またMFCでは、スレッドまたいでの、CWndオブジェクトのポインタによる
>ウインドウ操作は保証されていません。

そのような制約があるのですか。参考になります。

モードレスダイアログの表示は、CDlgXXXのダイアログが閉じた後
でよかったので、CDlgXXX::PostNcDestroy()関数(スレッド外)で
行うようにしたら、正常に動作しました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加