none
VC++2010 で Cwnd::ShowWindow()の挙動について RRS feed

  • 質問

  • VC++2010 SP1 で CWnd::ShowWindow()関数 を 使ってダイアログウインドウを表示・非表示するプログラムを作成しています。

    このダイアログウインドウは、カメラデバイスからCWnd::SetTimer()関数のタイマによって画像を取得して、表示する事を行っています。

    CWnd::ShowWindow()関数を使う際 CWnd::OnShowWindow()をオーバライドしてし、カメラの切断処理を書いています。

    このプログラムを実行したところ ダイアログウインドウが表示されているのにもかかわらず CWnd::ShowWindow(FALSE)又は(SW_HIDE)を実行した際に オーバーライドしたOnShowWindow()が呼び出されない事がたまにあります。後続する CWnd::ShowWindow(TRUE) 又は (SW_SHOWNORMAL)では OnShowWindow()は呼び出されます。 頻度はPCのスペックにより異なります。

    こんなことあり得るのでしょうか。

    CWnd::ShowWindow() は別のスレッドからこのダイアログウインドウに対しユーザー定義メッセージを発行し、 メッセージに関連づけた関数から呼び出します。

    ちなみに、カメラデバイスの制御とタイマによる画面更新の処理を排除したプログラムを実行しても、同じ事が置きます。

    よろしくお願いします。

    12/07/76 12:34追記 ソースコードの主要な部分を追加しました。

     xxxDlg::ChangeDevice()を別のスレッドから呼び出してます。

    xxxDlg::OnShowWindow()内部で staticで宣言された onshow 変数に、OnShowWindow()が呼ばれた際の bShow を保存しています。

    開く、閉じるが繰り返されるため onshow 変数が bShow と 同値になることはないと思っていたのですが、ごくまれに起きることがあります。

    #define WM_xxx_UPDATE_WINDOW WM_USER+3
    void xxxDlg::ChangeDevice(void)
    {
    	SendMessage( WM_xxx_UPDATE_WINDOW, 0, 0);
    }
    afx_msg LRESULT xxxFocusDlg::OnUpdateWindow(UINT wParam, LONG lParam)
    {
    	ShowWindow(FALSE);
    //	Sleep(10);
    	ShowWindow(TRUE);//ダイアログを表示する
    	return 0;
    }
    void xxxDlg::OnShowWindow(BOOL bShow, UINT nStatus)
    {
    	CDialog::OnShowWindow(bShow, nStatus);
    	CString msg;
    	static int onshow=-1;
    	// TODO: ここにメッセージ ハンドラー コードを追加します。
    	if( onshow < 0 ) {
    		onshow = (int)bShow;
    		SetTimer(TIMER_COUNTER_UPDATE, 1, NULL);
    	} else if( onshow != (int)bShow ) {
    		onshow = bShow;
    		Sleep(100);
    	} else {
            msg.Format("AutoFocusDlg::OnShowWindow onshow=%d bShow=%d nStatus=%d", onshow, bShow, nStatus);
        	AfxMessageBox(msg,MB_OK|MB_ICONWARNING);  // 不正な処理を検出した場合、ダイアログを出して停止する
    	}
    }



    • 編集済み shingenn1 2012年7月6日 3:45
    2012年7月6日 1:52

回答

  • 自分の発言のせいで議論がやや妙な方向に行ってしまいました。すみません。
    まず、タイマーによる定期的な画像の取得をが眼目であると仮定すると、
     1.画像取得はタイマーのタイミングで行うべきである(主処理)。
     2.そのときウインドウの表示が必要ならば、そうする(付随的処理)。
    ということが、言いたかったわけです。なぜなら、
     3.原理的にプログラマはあるウインドウの表示/非表示を完全には制御できない。
     4.従って「DLGの表示」と「画像の取得」との間は「本来因果関係があってはならない」
    からですね。
    「実装上は可能」であることが「意味的に正しい」こととはならないわけです。

    さて、スレッド越しのSendMessage()は可能です。このとき注意が必要なのは、
    SendMessage()の呼び出し元のスレッドは、関数が完了するまで「停止」
    させられている点ですね。なので、ビッグジョブをやらせてはいけないわけです。

    次に、あるスレッドで構築したCWndを別のスレッドに渡し、そのスレッドでCWndの
    メンバ関数を利用する試みは多くの失敗を覚悟しなければなりません。
    わかってやっている場合でさえ、効率的でも便利でもありませんので、
    一般に検討の余地はありません。
    自分の懸念は、shingenn1さんの「別のスレッドから呼び出してます」の内容の
    範囲から、最悪の条件を想定したもので、当たり前ですが、
    「呼び出す方法」によっては回避可能です。

    最後に、ShowWindow()とWM_SHOWWINDOWについて興味をもたれるのは良いことですが、
    その解析結果がPCのコンディションや将来のバージョンでは役に立たないケースが
    ありえることを覚悟してやりましょう。
    「観測結果」を頼りにしなければならないほど難しい仕様の場合はやむをえませんが。

    • 回答としてマーク shingenn1 2012年8月3日 0:45
    2012年7月9日 1:37

すべての返信

  • ShowWindow のパラメータは、BOOLではありません。SW_ で始まる定義値を指定します。あと、現在どうなっているかは、内部フラグではなく、HWNDに状態問い合わせを行うことをお勧めします。

    後の部分は、パッと見た感じではおかしそうな部分がないので、何とも言えません。

    ただ、メッセージ処理が行われる場合、メッセージループが回っていないと正しく処理が行われません。そのため場合によってはスキップしてしまう(状態変わらずのまま。。など)こともあるかもしれません。

    わかりませんけどね。ウィンドウの表示・非表示を頻繁に変えるなんてやったことないんで。。。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/

    2012年7月6日 5:44
  • 返信ありがとうございます。 ShowWindowのパラメータでTRUE/FALSE を使っていたのは かなり古いコードを引用していたもので。書き換えていませんでした。そうですね。最新のにあわせます。

    VC++2010の定義では SW_HIDEとFALSE / SW_SHOWNORMALとTRUEが同値であることは確認しています。

    SetTimer()で キューに送られる WM_TIMER メッセージ は 同じID複数送られた場合はまとめられると、ネット上で出てくるのですが ShowWindow()でこのような事が起きると、信頼できず OnShowWindow ()を使うことができません。


    • 編集済み shingenn1 2012年7月6日 6:26
    2012年7月6日 6:25
  • ダイアログアプリを作って、ShowWindow を行うものを試してみました。

    void CTestDlg::OnBnClickedOk()
    {
      TRACE( _T("\nCall ShowWindow( SW_SHOWMINIMIZED )\n") );
      ShowWindow( SW_SHOWMINIMIZED );
      TRACE( _T("Return ShowWindow( SW_SHOWMINIMIZED )\n") );
      TRACE( _T("Call ShowWindow( SW_SHOWNORMAL )\n") );
      ShowWindow( SW_SHOWNORMAL );
      TRACE( _T("Return ShowWindow( SW_SHOWNORMAL )\n\n") );
    }
    void CTestDlg::OnShowWindow(BOOL bShow, UINT nStatus)
    {
      CDialogEx::OnShowWindow(bShow, nStatus);
      TRACE( _T("OnShowWindow( %d, %u )\n"), bShow, nStatus );
    }
    

    実行結果は...

    Call ShowWindow( SW_HIDE )
    OnShowWindow( 0, 0 )
    Return ShowWindow( SW_HIDE )
    Call ShowWindow( SW_SHOWNORMAL )
    OnShowWindow( 1, 0 )
    Return ShowWindow( SW_SHOWNORMAL )

    でした。

    SW_HIDE をしない場合は、WM_SHOWWINDOW は呼ばれませんでした。

    ということで、スキップしてしまう状況がるのはもっと別の何かな気がします。それが何か?についてはわかりません。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/

    2012年7月6日 7:11
  • とっちゃん 様

    検証コードまで作って追っていただき、ありがとうございます。

    私もShowWindow(SW_HIDE)を連続で実行した場合、およびShowWindow(SW_SHOWNORMAL)を連続で実行した場合は、一回目で OnShowWindow()がコールされ、それ以降はコールされないのは確認してました。

    ちなみに ShowWindow(SW_HIDE) を実行した時に OnShowWindow()がコールされない事がほとんどです。質問に追記したコード 以上に難しいことはしていないものでも現象は発生しているので、もしや VC++2010のMFCのバグ!?と疑ってしまいます。

    発生頻度は、本当にまれです。が、マルチコア環境で発生頻度が高いような感じがします。

    2012年7月6日 8:26
  • MFCのバグを疑うのであれば...APIを直接呼び出してみてはいかがでしょうか?

    ShowWindow なら、::ShowWindow( m_hWnd, SW_HIDE ); で、API直呼び出しになります。

    プロシージャを疑うとなると、まぁ一筋縄ではいきませんが、デバッガで追いかけることもできますよ。

    ただし、画面表示周りは、フォーカス移動で意図しないメッセージ順になったりするので、リモートデバッグするか、トレース表示程度にしておくかくらいしかないですが。

    ちなみに、テストプログラムは、同一スレッド上でShowWindowしていますので、スレッド間のやり取りは発生していません。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/

    2012年7月6日 9:16
  • 回答ではありません。あしからず。
    本件とは関係ないかもしれませんが、
    原理的に、やってはいけない点が1点あります。

    >xxxDlg::ChangeDevice()を別のスレッドから呼び出してます。

    とのことですが、ご存知の通りCWndはそれを生成したスレッド以外からは利用できません。
    CWnd::m_hWndを単体で使用するのはOKですから代替処理にしたらどうでしょう。

    次に、メッセージドリブンなOSで注意しなければならないのは、
    SendMessage()などのようにOSがその到達を保証している場合や、
    WM_CREATEのように手順がOSによって規定されている場合を除くと
    あるメッセージが確実に来ることを前提にしてコードしてはいけない点ですね。
    例えばShowWindow()を実行するとWM_SHOWWINDOWが発行されるとは
    どこにも書いてないわけです。
    現実的にはShowWindow()の結果何らかのメッセージが来ることは
    十分期待しても良いのですが、原理上はアウトであると判定できます。

    つまり、このようなOSの場合は、処理すべき眼目は
    もっと確実な方法で行わなくてはならないということですね。

    例えば、ウインドウ消去時に、それが数秒かけてフェードアウトする仕様に変わった場合を
    想像してみると、現行のプログラムはうまく動かなくなるかもしれないことが容易に予測できます。

    2012年7月6日 9:38
  • 基本的にほぼ 仲澤@失業者 様の指摘内容への同意になってしましますが、

    原理的に、やってはいけない点が1点あります。

    >xxxDlg::ChangeDevice()を別のスレッドから呼び出してます。

    これが原因と予想します。

    やってはいけない内容なので動作予測できないですけど、あえて予想すると「メッセージがきちんと届かない」、「描画がおかしくなる」、「予定外の変数値動作」といった動作が考えられるかと・・・。

    後はメッセージの前提もあまり良くはないと思います。

    ドキュメント記述があれば前提にしますけど、条件付きのメッセージは意味の取り違いなどで問題を起こしてしまうコードを簡単に作ってしまうので、指摘されてるようなことを考えると後が怖いです。

    2012年7月6日 16:08
  • 回答ではありませんが、念のため。

    原理的に、やってはいけない点が1点あります。

    >xxxDlg::ChangeDevice()を別のスレッドから呼び出してます。

    これが原因と予想します。

    やってはいけない内容なので動作予測できないですけど、あえて予想すると「メッセージがきちんと届かない」、「描画がおかしくなる」、「予定外の変数値動作」といった動作が考えられるかと・・・。

    手元の Visual C++ 2010 SP1 の MFC における CWnd::SendMessage の実装を見たところ、以下のようなものでした。

    _AFXWIN_INLINE LRESULT CWnd::_AFX_FUNCNAME(SendMessage)
    (UINT message, WPARAM wParam, LPARAM lParam) const
    { ASSERT(::IsWindow(m_hWnd));
    return ::SendMessage(m_hWnd, message, wParam, lParam); }
    ※横に長いので適当に改行入れています。

    CWnd::SendMessage の実装自体は別スレッドからの呼び出し制限がある実装ではないと思っていますので、SendMessage 関数しか使っていないのであれば「原因ではない」と推測されます。(すでに書かれているような m_hWnd しか見ていない)
    もちろん、このバージョンの実装がそうであるだけであって、将来的な保障という観点では何もないと思われるので、CWnd クラスのメンバー関数をスレッド外から呼ぶ行為は避けた方が無難ですけどね。

    // 掲載されていないコードで CWnd のオブジェクトを
    // どうやって保持、取得しているかという点は何ともいえませんが。

    2012年7月6日 23:01
    モデレータ
  • Azulean 様から

    SendMessage 関数しか使っていないのであれば「原因ではない」と推測されます。

    もちろん、このバージョンの実装がそうであるだけであって、将来的な保障という観点では何もないと思われるので、CWnd クラスのメンバー関数をスレッド外から呼ぶ行為は避けた方が無難ですけどね。

    との御指摘があったので、「原因では?」と予想した経緯を記述しておきます。

    1. 別スレッドからの SendMessage が利用するメッセージキューはどのスレッドのものになる?
    2. SendMessage は応答を返すのでメッセージハンドラの実行スレッドが不定ではないか?
    3. 上記2 を考えるとメッセージループスレッド以外からの描画操作が起こるのでは?

    という事柄からの予想です。

    そういった理由から「SendMessage のメッセージループスレッド以外からの呼出は保証されない。」というのが自分の認識です。
    テスト処理などで SendMessage 書いても動作してる感じはしてたので、実体験でおかしくなったことがあるわけではありません。

    PostThreadMessage の説明文を参照してから「怖いから避けている」という程度なので「見当違い」の予想かもしれません。

    ----------------------------------------------------------------------------------------------------

    怖がって間違えていても恥ずかしいので SendMessage についての説明を調べると、別スレッドが作成したウインドウに対しての送信はポストして待つような記述がされていたので問題ないのでしょう・・・。

    今回の事象発生とは関係なさそうですが、同スレッドからの SendMessage はキューを介さず直接ウィンドウプロシジャーを呼ぶようなので別スレッドからの呼出しは通常とは動作が違うようです 。

    ということで完全に自分の「見当違い」な返信だったようで御迷惑おかけしました。
    • 編集済み kyano30 2012年7月7日 7:15 追記
    2012年7月7日 1:48
  • 本題とは関係ないのと、掲示板だとちょっとボリュームがあるので大きく割愛しますが。。。

    ウィンドウのメッセージ処理はそのウィンドウを作成したスレッド(具体的には、最終的にCreateWindowEx APIを呼び出したスレッド)で処理されるようにWindows自身が作られています。

    そのため、どこから送信(Send/Postの区別なく)したかにかかわりなく、必ずメッセージを処理するスレッドは同一となります。ただしスレッドが一緒であることとメッセージ処理中にほかのメッセージを処理しない(メッセージの再入)は別ですので、この点については混同しないようにする必要があります。

    難しい部分はざっくりカットオフしますが、Kyano30さんが懸念しているメッセージ処理部分については影響が出ることはないというところだけ書いておきます。

    ついでに、仲澤さんが懸念していたCWndのスレッド越えについても。

    こちらは、FromHandle(CWnd/CDC/CGdiObject)が、TLS(Thread Local Storage)にて管理されているため、これらで得たポインタ(MFCのオブジェクト)をスレッドをまたいで使う場合、意図しないタイミングで解放されてしまうことがあるので、使うな!というものです。

    なので、解放されないことを保証できる状態での使い方であれば、問題はありません。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/

    2012年7月7日 7:56
  • とっちゃん 様、見当違いでお恥ずかしい返信について的確なコメントありがとうございます。

    ドキュメントをチェックしていて、

    > The system only does marshalling for system messages (those in the range 0 to (WM_USER-1)). To send other messages (those >= WM_USER) to another process, you must do custom marshalling.

    という Remarks の部分が気になって WM_USER 以降はダメなのか?と調べようとしてましたが問題ないのですね・・・。
    キュー満杯の場合も再送してもらえるのかだけは気になりますが・・・。

    そうなると質問の現象の発生理由として考えられるのは送信されない条件として記述されている、

    • When a top-level, overlapped window is created with the WS_MAXIMIZE or WS_MINIMIZE style.
    • When the SW_SHOWNORMAL flag is specified in the call to the ShowWindow function.

    という条件が成立している状況でしょうか?

    SW_SHOWNORMAL (=1) 指定で、普通に送られているようですから AND 条件と考えると、

    「最大化 or 最小化 状態からの再表示」

    といった条件でずれが生じるといった事はないでしょうか?


    • 編集済み kyano30 2012年7月7日 9:01 誤字削除
    2012年7月7日 9:00
  • 引用してる英文のところは、プロセス越えの話の部分ではありませんか?

    システムメッセージは、マーシャリングするが、WM_USER以上のカスタムメッセージを別プロセスに送る場合は、カスタムマーシャリングが必要になる。というようなことが書かれているように読み取れますが。

    ちなみに、HWNDさえわかれば、別プロセスあてでもメッセージを送ることはできます。

    ちなみに、キューが満タンだったなど(Postの場合はメモリがパンクするまでなので、おそらく1千万単位でメッセージをため込む必要がありそう)場合、再送せず、エラーで帰ります(PostMessage)。SendMessageも待機できない状態になればエラーで帰ります。このあたりリファレンスに書いてあったはずです。

    WM_SHOWWINDOWが来ない理由がメッセージの送信失敗かどうかはわかりませんので何とも言えません。

    WM_SHOWWINDOW をトリガーとすることについては、私もあまりお勧めできるものではないというかな。

    ウィンドウは、プロセス外部からも表示非表示の切り替えができます。そのため、意図しないタイミングで非表示にされてしまう場合があります。

    ですので、何かをするために非表示にするのはありだと思いますが、非表示になったら何かをするというのはあまりお勧めできる手段ではないといわざるを得ません。

    非同期処理の処理待ちなどは、Windowsアプリケーションで「処理中」を表現する の後編でいろいろ書いているので、参考にできると思います。

    MFCを使わない書き方していますが、MFCの場合でもやり方の基本は一緒です。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/

    2012年7月7日 10:34
  • とっちゃん 様

    引用してる英文のところは、プロセス越えの話の部分ではありませんか?

    たしかに HWND_BROADCAST 直後なのでプロセス越えの話みたいです、引用元は SendMessage function です。

    ちなみに、キューが満タンだったなど(Postの場合はメモリがパンクするまでなので、おそらく1千万単位でメッセージをため込む必要がありそう)場合、再送せず、エラーで帰ります(PostMessage)。SendMessageも待機できない状態になればエラーで帰ります。このあたりリファレンスに書いてあったはずです。

    貴重な情報ありがとうございます。

    PostMessage の戻り値をチェックしてエラーが発生したなら送り直すようにという感じの文章をみたから気になったのですが、現実的に WM_SHOWWINDOW が送信失敗というのは考えにくいのですね。


    そうなるとメッセージが届かないというより通知しない条件に陥っていると考える方がよさそうですので、前回の送信されない条件の引用元ですが WM_SHOWWINDOW message の Remarks 部の記述からになりますが、他にも条件があるのかもしれませんね。

    しかしメッセージが予定通りに届いたとして「カメラデバイス切断処理」のトリガに使うというのは、お勧めできるものではありませんね・・・。

    2012年7月7日 11:23
  • とっちゃん さん
    仲澤@失業者 さん
    kyano30 さん
    Azulean さん

    さまざまな議論と情報ありがとうございます。

    何処かで調べたときに、別スレッドから所定の操作をしたい場合は、ユーザー定義メッセージを作成してSendMessageでキューに送ることで、本来のウインドウスレッドからからコールバックされる関数で処理できる。というのを情報を目にしたのでそういう実装しています。MSDNだったかな。出典を思い出せなくて申し訳ないです。
    検証プログラムを作って OnUpdateWindowをコールバックするためのユーザー定義メッセージはしっかり飛んできていることは確認しています。

    いやはや、ダイアログウインドウの表示・非表示を繰り返すプログラムで、キューにメッセージを投入する間隔をスリープをいれなかったところ、キューに大量のメッセージがたまり、メモリを食いつぶしてWindowsOSが不安定になり強制電源断しなければなりませんでしたw ブルースクリーンは出ないので、Windowsすごいなと思いましたw

    // 掲載されていないコードで CWnd のオブジェクトを
    // どうやって保持、取得しているかという点は何ともいえませんが。

    これも重要な情報でした、載せていなくて申し訳ありません。
    CDialogEx または CDiaglog の派生でダイアログクラスを構成しています。

    ShowWindow()は、ウインドウの表示・非表示処理中はブロックされる。さらに表示・非表示を繰り返した場合は、必ずWM_SHOWWINDOW  がキューされる。このことが保障されないのであれば、別の手で行くのがよさそうですね。

    一番楽かなと思ってコーディングしていましたが、 必ずしも WM_SHOWWINDOW のメッセージ処理で カメラデバイスの接続・切断処理をする必要はないので。

    でも  WM_SHOWWINDOW が ShowWindow(SW_HIDE) でキューされない場合がある条件は、興味あります。

    機会を作って、単一スレッドでこの症状が起きるか確認してみます。

    2012年7月8日 14:31
  • >ダイアログウインドウの表示・非表示を繰り返すプログラムで、キューにメッセージを投入する間隔をスリープをいれなかったところ、キューに大量のメッセージがたまり、メモリを食いつぶして

    これが原因ではないかと思います。メッセージでやり取りを前提とするなら、プロシージャからリターンするまでの間隔はおおむね0.1秒以下程度にまとめるようにするのが1.0以来のWindowsのお作法です。

    これに言及している文章はもうありません。旧WindowsSDK(3.0時代のものなので現行のものではない)にはあったはずですが。。。

    ま、それはともかく、Sleepをはさむとうまくいくという場合、たいていはシステムから見て無駄に時間を経過している(1処理が長すぎる)ことが原因です。

    長い時間がかかる処理はワーカースレッドで行い、UIスレッド(メインスレッド)に負荷をかけないようにするのがよいと思います。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/

    2012年7月8日 14:43
  • 自分の発言のせいで議論がやや妙な方向に行ってしまいました。すみません。
    まず、タイマーによる定期的な画像の取得をが眼目であると仮定すると、
     1.画像取得はタイマーのタイミングで行うべきである(主処理)。
     2.そのときウインドウの表示が必要ならば、そうする(付随的処理)。
    ということが、言いたかったわけです。なぜなら、
     3.原理的にプログラマはあるウインドウの表示/非表示を完全には制御できない。
     4.従って「DLGの表示」と「画像の取得」との間は「本来因果関係があってはならない」
    からですね。
    「実装上は可能」であることが「意味的に正しい」こととはならないわけです。

    さて、スレッド越しのSendMessage()は可能です。このとき注意が必要なのは、
    SendMessage()の呼び出し元のスレッドは、関数が完了するまで「停止」
    させられている点ですね。なので、ビッグジョブをやらせてはいけないわけです。

    次に、あるスレッドで構築したCWndを別のスレッドに渡し、そのスレッドでCWndの
    メンバ関数を利用する試みは多くの失敗を覚悟しなければなりません。
    わかってやっている場合でさえ、効率的でも便利でもありませんので、
    一般に検討の余地はありません。
    自分の懸念は、shingenn1さんの「別のスレッドから呼び出してます」の内容の
    範囲から、最悪の条件を想定したもので、当たり前ですが、
    「呼び出す方法」によっては回避可能です。

    最後に、ShowWindow()とWM_SHOWWINDOWについて興味をもたれるのは良いことですが、
    その解析結果がPCのコンディションや将来のバージョンでは役に立たないケースが
    ありえることを覚悟してやりましょう。
    「観測結果」を頼りにしなければならないほど難しい仕様の場合はやむをえませんが。

    • 回答としてマーク shingenn1 2012年8月3日 0:45
    2012年7月9日 1:37
  • 追いかけていて気になった事を少々。

    Windowsのようにイベント駆動型の実装になっている場合、画面周りの処理とかOS側で処理する部分を
    まともに動作させる為には基本的にイベントハンドラを終了させてOSに制御を返す必要があると思います。
    いわゆる、メッセージループに戻るという事ですね。
    メッセージループに戻す事でアプリケーション側のコードからOS側のコードに制御を戻すことになり、
    このタイミングでOS側の処理が実行されると理解しています。

    強制画面更新の関数も存在はしますが、基本はイベントハンドラ内の処理を速やかに終わらせて
    OSへ制御を返す事でスムーズな動作を実現できると思うのでイベントハンドラ内でループしっ放しの状態は
    望ましくないと思います。望ましくは表示/非表示の切り替え毎にOSに制御を返すのが無難な実装でしょう。
    また、ループ内に独自のメッセージループを作成してしまうのも個人的にはお勧めしない実装です。
    元の実装がメッセージループは一箇所しかない前提の実装になっているのでメッセージループが複数個所にあると
    メッセージの処理順番が想定外の状態になるケースもありえます。
    自前のメッセージループを作成するなら、そのメッセージループ内で処理してよいメッセージかどうかを
    全て把握した上で処理する必要がありますから。


    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。

    2012年7月10日 5:00
  • shingenn1 様

    間の抜けた返信しちゃって申し訳なかったですが、PATIO 様の返信をみて気になることが一つできたので返信します。

    これも重要な情報でした、載せていなくて申し訳ありません。

    CDialogEx または CDiaglog の派生でダイアログクラスを構成しています。

    いままで特に気にしたことはないのですけど CDialog 系の場合はダイアログとして使う予定のせいかウィンドウプロシジャーがハンドルしないメッセージを DefWindowProc ではなく DefDlgProc を呼ぶようになってたような気がするのですが、この辺りに問題が発生する可能性ってありませんか?

    今回も記憶だよりなので前回のように見当違いな気もするのですけど気になったので・・・・。

    2012年7月10日 12:43
  • とっちゃん さん
    仲澤@失業者 さん
    PATIO さん
    kyano30 さん

    貴重な助言ありがとうございます。
    ちょっとバタバタしてて、なかなかフォーラムをのぞきに来られませんでした。

    >>ダイアログウインドウの表示・非表示を繰り返すプログラムで、キューにメッセージを投入する間隔をスリープをいれなかったところ、キューに大量のメッセージがたまり、メモリを食いつぶして
    > これが原因ではないかと思います。

    書き込んだ情報が不足していました。申し訳ありません。キューに大量のメッセージ・・・のプログラムでは、今回問題視にした現象は見られませんでした。というか、見られる状態にはできませんでした。
    現象が出るまで待つより前に、リソースを食いつぶしてOSの挙動が不安定になり、電源ボタンを長押しして強制シャットダウンしました。

    現在、検証しているプログラムでは SetTimerで、非表示・表示を繰り返したり、人為的なボタンクリックで非表示・表示をしてみたりしています。

    皆様、本当にありがとうございます。
    とりあえず現在の実装を変更する事を考え、現象を回避する方法を模索します。

    現在のOnShowWindow()を 便利に使うのではなく、ちゃんと自分で処理させようと考えてみます。

    ちょっと検証に時間がかかるので、解決までもう少しお時間ください。
    kyano30 さんの情報も調べてみます。

    # フォーラム運用的に、これいで良いんですかね。それとも方向性が決まった時点で解決ですか。

    2012年7月11日 5:36
  • shingenn1 様

    とりあえず現在の実装を変更する事を考え、現象を回避する方法を模索します。

    現在のOnShowWindow()を 便利に使うのではなく、ちゃんと自分で処理させようと考えてみます。

    ちょっと検証に時間がかかるので、解決までもう少しお時間ください。
    kyano30 さんの情報も調べてみます。

    解決するようなら、自分の良く考えてない情報をわざわざ調べる必要はないですよ。
    ※メッセージの流れが微妙に違ってたようなあやふやな記憶が元ですから・・・。

    もし余裕があって調べた結果情報を報告してくれると非常にありがたいですけど。

    # フォーラム運用的に、これいで良いんですかね。それとも方向性が決まった時点で解決ですか。

    解決の回答マークをつけるタイミングの指針をみた記憶はないので自由なタイミングで問題ないのじゃないでしょうか?

    2012年7月11日 13:19
  • 情報をくださった皆さんへ。

    有用な情報を色々ありがとうございました。コードの修正をしようと考えていた矢先に、階段から転落するという大失態をやらかし、なかなか検証できませんでした。

    確実に受け取れ塚解らない ShowWindow()と WM_SHOWINDOWを組み合わせて処理させるのは止めました。

    ユーザー定義メッセージは確実に受け取れているので 、こちらで処理させます。

    検証コードを24時間駆動させていますが、問題なく動かせています。

    kyan30 さん

    > DefWindowProc ではなく DefDlgProc を呼ぶようになってたような気がするのですが、この辺りに問題が発生する可能性ってありませんか?

    調べてみましたが、あまり関係ないようですね。

    いろいろありがとうございました。

    2012年8月3日 0:53