◀ANSI版開発トップへ
  • 3014 ファイルの更新不具合
    • 3016 Re:ファイルの更新不具合
      • 3017 Re2:ファイルの更新不具合
        • 3019 Re3:ファイルの更新不具合
      • 3018 Re2:ファイルの更新不具合
        • 3020 Re3:ファイルの更新不具合
          • 3021 Re4:ファイルの更新不具合
            • 3022 Re5:ファイルの更新不具合
            • 3023 Re5:ファイルの更新不具合
              • 3024 Re6:ファイルの更新不具合
                • 3025 Re7:ファイルの更新不具合
      • 3026 Re2:ファイルの更新不具合
        • 3027 Re3:ファイルの更新不具合
        • 3031 Re3:ファイルの更新不具合
          • 3033 Re4:ファイルの更新不具合
            • 3035 Re5:ファイルの更新不具合
              • 3036 Re6:ファイルの更新不具合
                • 3037 Re7:ファイルの更新不具合
          • 3038 Re4:ファイルの更新不具合
            • 3091 Re5:ファイルの更新不具合
  • [3014] ファイルの更新不具合 wmlhq 2003年08月17日 12:45

    更新の後、選択状態になる不具合は、m_bDragModeがどこかでセットされるためかと思われます。おそらくCEditWnd::OnLButtonDown中のSetCaptionがWM_SETFOCUSのsenderになっているために、WM_LBUTTONDOWNがWM_SETFOCUSを呼ぶためと思われます。

    原因分析のため、次のテストを実施してください。

    ☆テスト1
    Spyを使ってCEditWndのWM_LBUTTONDOWNが他のメッセージのsenderになっていないか調べる。

    ☆テスト2
    static BOOL fBug343Check = FALSE; //
    ...

    case WM_SETFOCUS:
    MYASSERT(!fBug343Check); //
    ...

    LRESULT CEditWnd::OnLButtonDown( WPARAM wParam, LPARAM lParam )
    {
    ...
    fBug343Check = TRUE; // break 1
    SetCapture( m_hWnd ); // Check point (sender?)
    fBug343Check = FALSE; // break 2
    m_bDragMode = TRUE;
    return 0;
    }

    なお、更新通知ダイアログはわかりづらいようなので、次のようにしてください。

    ----------------------------------------
    <!> このファイルは別のプログラムによって変更されました。

    読み直しますか?
    ----------------------------------------
    [ ]今後、ステータスバーに通知する
    [ ]今後、通知しない
    ----------------------------------------
    [はい] [いいえ]
    ----------------------------------------

    また、長いファイル名が折り返されるようにスタイルを設定してください。

    //追記。ファイルの「更新」じゃなくて、「変更」になる?
    • [3016] Re:ファイルの更新不具合 ryoji 2003年08月18日 21:30

      ▼ wmlhqさん
      > 更新の後、選択状態になる不具合は、m_bDragModeがどこかでセットされるためかと思われます。おそらくCEditWnd::OnLButtonDown中のSetCaptionがWM_SETFOCUSのsenderになっているために、WM_LBUTTONDOWNがWM_SETFOCUSを呼ぶためと思われます。

      WM_SETFOCUS時のダイアログ表示後に、遅れてCEditViewにWM_LBUTTONDOWNが届いている模様。
      #対応するWM_LBUTTONUPは届かない。

      よくわかりませんが(^^;、ここは多少遅れてもタイマーでの更新検出に任せたほうが無難な気がします。
      • [3017] Re2:ファイルの更新不具合 ryoji 2003年08月19日 00:21

        > よくわかりませんが(^^;、ここは多少遅れてもタイマーでの更新検出に任せたほうが無難な気がします。

        上記の部分は撤回しておきます。
        #タイマーなら問題無いとまでは断言できない σ(^^; ので。
        • [3019] Re3:ファイルの更新不具合 ryoji 2003年08月19日 11:16

          > #タイマーなら問題無いとまでは断言できない σ(^^; ので。

          嫌~~な予感がしたので試してみました。環境はWin2K。

          タイマーで更新検出された場合
          編集領域でマウスが押されているときに更新ダイアログが出ると、ダイアログを閉じた後も選択状態が継続する(マウスを放しているのにドラッグ中のような状態)。
          また、選択テキストを他の場所にドラッグしている最中に更新ダイアログが出ると、ダイアログ表示状態でストールする。

          モーダルダイアログ表示中は編集領域がdisableになるため、その間のマウスイベントが途切れてしまうのが原因でしょうか?
      • [3018] Re2:ファイルの更新不具合 wmlhq 2003年08月19日 10:53

        ▼ ryojiさん
        > WM_SETFOCUS時のダイアログ表示後に、遅れてCEditViewにWM_LBUTTONDOWNが届いている模様。
        ありがとうございます。#デバッグトレースできないのですか?
        やはり、SetCaptureが原因のようです。SetCaptureが内部で同期的にWM_SETFOCUSを送るのでしょう。

        CEditWnd::DispatchEvent, WM_LBUTTONDOWN
        >SetCapture
        >>(SetCapture内部) SendMessage CEditWnd, WM_SETFOCUS
        >>>CEditWnd::DispatchEvent, WM_SETFOCUS
        >>>>CEditDoc::CheckFileTimeStamp
        >>>>>init
        >>>return lRes; // WM_SETFOCUSを受け取る
        >m_bDragMode = TRUE;
        >return 0; // WM_LBUTTONDOWNを受け取る

        呼び出し順を変えてみても大丈夫かな。

        m_bDragMode = TRUE;
        SetCapture( m_hWnd ); // Sends WM_SETFOCUS
        return 0;

        > #対応するWM_LBUTTONUPは届かない。
        メッセージボックスに食われるからでしょう。
        Init();とInitAllView();はReleaseCaptionしませんね。更新されるときには、ドラッグをキャンセルするのが普通かと思われますが。
        こちらも修正しましょう。
        • [3020] Re3:ファイルの更新不具合 ryoji 2003年08月19日 11:35

          ▼ wmlhqさん
          > ありがとうございます。#デバッグトレースできないのですか?
          > やはり、SetCaptureが原因のようです。SetCaptureが内部で同期的にWM_SETFOCUSを送るのでしょう。

          現象が起きるとき、そのSetCapture部分はまったく通過してないようですが...???
          • [3021] Re4:ファイルの更新不具合 wmlhq 2003年08月19日 13:33

            ▼ ryojiさん
            > 現象が起きるとき、そのSetCapture部分はまったく通過してないようですが..

            私の勘違いでしょうか。ということは、CEditViewのcase WM_LBUTTONDOWN:が有力か。これもSetCaptureを呼んでるし。

            #CheckFileTimeStampが二回連続で呼ばれても大丈夫?
            • [3022] Re5:ファイルの更新不具合 ryoji 2003年08月19日 14:20

              ▼ wmlhqさん
              > 私の勘違いでしょうか。ということは、CEditViewのcase WM_LBUTTONDOWN:が有力か。これもSetCaptureを呼んでるし。

              あの、ですね...簡単なサンプルプログラムで確認したところ、
              「SetCapture APIが内部的にWM_SETFOCUSを送る???」ということはないみたいです。
              また、SetCapture後にモーダルダイアログを表示するとReleaseCaptureしなくてもキャプチャーは自動的に解除されるようです。
              #ダイアログを開いた時点からGetCaptureがNULLを返すようになる。
            • [3023] Re5:ファイルの更新不具合 ryoji 2003年08月19日 14:41

              ▼ wmlhqさん

              最初に<3016>で言ったとおりですが...
              ダイアログを閉じたあとで遅れてCEditViewにWM_LBUTTONDOWNが届くからでしょう。
              そこでm_bBeginSelectがTRUEにセットされる。
              で、キャプチャが解除されていてもエディットウィンドウ上でマウスが動くと
              WM_MOUSEMOVE処理で選択が始まる。

              #ソースコードを初めて見てからまだ1ヶ月くらいしか経ってないので、
              #あんまり自信は無いですけど。(^^;;;
              • [3024] Re6:ファイルの更新不具合 ryoji 2003年08月19日 14:57

                > で、キャプチャが解除されていてもエディットウィンドウ上でマウスが動くと
                > WM_MOUSEMOVE処理で選択が始まる。

                すいません。このパターンではキャプチャは解除されてないですね。
                #CEditView の外でも CEditWnd の範囲内ならどこでも CEditViewに
                #すべてのWM_MOUSEMOVEが届いている。
                • [3025] Re7:ファイルの更新不具合 ryoji 2003年08月19日 15:13

                  補足。
                  > > で、キャプチャが解除されていてもエディットウィンドウ上でマウスが動くと
                  > > WM_MOUSEMOVE処理で選択が始まる。
                  >
                  > すいません。このパターンではキャプチャは解除されてないですね。
                  > #CEditView の外でも CEditWnd の範囲内ならどこでも CEditViewに
                  > #すべてのWM_MOUSEMOVEが届いている。

                  <3019>の「編集領域でマウスが押されているときに更新ダイアログが出ると...」のパターンではキャプチャが解除されていてCEditView上でのみWM_MOUSEMOVEがCEditViewに送られてきます。
      • [3026] Re2:ファイルの更新不具合 ryoji 2003年08月19日 16:45

        > WM_SETFOCUS時のダイアログ表示後に、遅れてCEditViewにWM_LBUTTONDOWNが届いている模様。
        > #対応するWM_LBUTTONUPは届かない。
        >
        > よくわかりませんが(^^;、ここは多少遅れてもタイマーでの更新検出に任せたほうが無難な気がします。

        とりあえずCEditWndのWM_SETFOCUSでのファイルのタイムスタンプチェック処理をやめて、
        タイマー(CEditWnd::OnTimer)でのチェック処理を、

        if (GetCapture() != NULL){
        /* 恐らく自スレッドでマウスドラッグ中である */
        nLoopCount = 10;
        }else{
        if( nLoopCount == 0){
        /* ファイルのタイムスタンプのチェック処理 */
        m_cEditDoc.CheckFileTimeStamp() ;
        }
        }

        とでもしておけば、この一連のスレッドで挙げられた問題は回避できそうかなぁ。
        ...などと、ちょっとわかったようなことをつぶやいてみる。(^^;;;
        • [3027] Re3:ファイルの更新不具合 ryoji 2003年08月19日 18:22

          > if (GetCapture() != NULL){
          > /* 恐らく自スレッドでマウスドラッグ中である */
          > nLoopCount = 10;
          > }else{

          えっと、不要かもしれませんが、いちおう簡単に説明を入れときますね。(^^)
          上記では、ユーザーが何らかのマウスドラッグ操作をしていないかチェックして、
          ドラッグ中ならタイムスタンプチェックを先延ばしにするものです。

          エディット画面でのマウスでの範囲選択中
          選択範囲のドラッグ中
          の他に、
          タイトルバーをドラッグ中
          スクロールバーをドラッグ中

          でもタイムスタンプチェックは先延ばしになります。
          不意にダイアログをボコッと表示してドラッグ操作の邪魔をしちゃ駄目でしょう?、
          という意味合いも込められています。
        • [3031] Re3:ファイルの更新不具合 ryoji 2003年08月19日 23:32

          > とりあえずCEditWndのWM_SETFOCUSでのファイルのタイムスタンプチェック処理をやめて、
          > タイマー(CEditWnd::OnTimer)でのチェック処理を、
          >
          > if (GetCapture() != NULL){
          > /* 恐らく自スレッドでマウスドラッグ中である */
          > nLoopCount = 10;
          > }else{
          > if( nLoopCount == 0){
          > /* ファイルのタイムスタンプのチェック処理 */
          > m_cEditDoc.CheckFileTimeStamp() ;
          > }
          > }
          >
          > とでもしておけば、この一連のスレッドで挙げられた問題は回避できそうかなぁ。

          ちまちまと書き込んでしまって申し訳ないですが、m(__)m 上記修正の方向が適切と判断されるようであれば、nLoopCountをCEditWndのメンバ変数にでもしてWM_SETFOCUS時に最大値をセットするようにしていただければ、と思います。
          #ウィンドウアクティブ化時の更新チェックが従来と遜色なく即時に行われるように
          • [3033] Re4:ファイルの更新不具合 wmlhq(管理者による再投稿) 2003年08月28日 16:22

            ▼ ryojiさん
            > ここは多少遅れてもタイマーでの更新検出に任せたほうが無難な気がします。

            絶対反対! ここは、m_bBeginSelectの信頼性にかかわるので、直すべきです。

            > ダイアログを閉じたあとで遅れてCEditViewにWM_LBUTTONDOWNが届くからでしょう。
            > そこでm_bBeginSelectがTRUEにセットされる。

            m_bBeginSelectは正解です。でも、次のSetFocusが悪さをしないか心配になります(他力本願モード)。

            case WM_LBUTTONDOWN:
            //case WM_RBUTTONDOWN:
            ::SetFocus( ::GetParent( m_hwndParent ) ); // これはWM_SETFOCUSを速達するんじゃないの?

            if( m_nMyIndex != m_pcEditDoc->GetActivePane() ){
            /* アクティブなペインを設定 */
            m_pcEditDoc->SetActivePane( m_nMyIndex );
            }
            // MYTRACE( " WM_LBUTTONDOWN wParam=%08xh, x=%d y=%d\n", wParam, LOWORD( lParam ), HIWORD( lParam ) );
            OnLBUTTONDOWN( wParam, (short)LOWORD( lParam ), (short)HIWORD( lParam ) ); // SetFocusの後でこれが呼ばれる。
            return 0L;

            そしてCEditWndの中で
            case WM_SETFOCUS:
            // MYTRACE( "WM_SETFOCUS\n" );

            /* ファイルのタイムスタンプのチェック処理 */
            m_cEditDoc.CheckFileTimeStamp();

            /* 編集ウィンドウリストへの登録 */
            CShareData::getInstance()->AddEditWndL
            ist( m_hWnd );
            /* メッセージの配送 */
            lRes = m_cEditDoc.DispatchEvent( hwnd, uMsg, wParam, lParam );

            ここでCheckFileTimeStampが呼ばれます。CheckFileTimeStampはダイアログをモーダルにしてスレッドを停止してしまいます。憶測では、ダイアログが閉じた後、スレッドはcase WM_LBUTTONDOWNのSetFocusの直後に戻り、OnLBUTTONDOWNを呼び、m_bBeginSelectをセットする。
            ややこしい仕様なので、WM_LBUTTONDOWNとOnLBUTTONDOWNは区別して考えてください。
            • [3035] Re5:ファイルの更新不具合 ryoji(管理者による再投稿) 2003年08月29日 08:29

              ▼ wmlhqさん
              > 絶対反対! ここは、m_bBeginSelectの信頼性にかかわるので、直すべきです。

              はぁ、そうですかぁ...
              ”m_bBeginSelectの信頼性”というのが抽象的でよくわかりません。(泣)
              ”絶対”とは、どんな確証で仰られているのでしょうか。う~ん...、ごめんなさい。

              変更を加える際、
              ・確認されている不具合が修正されること
              ・以前の機能が失われないこと
              ・新たな不具合を誘発しないこと
              ・以後の保守を困難にしないこと
              あたりに気をつけないといけないと思いますが、いずれか問題ありますか?
              複数箇所にあった処理を必須個所一本にまとめ、必須個所の問題も改善されていると思うのですが。確証はありませんけど。

              ふりだしに戻って、<3016>の話をもう少し詳しく説明します。
              クライアント領域に子画面を持つシンプルなアプリでは、子画面をクリックしてアクティブ化する場合、大雑把に言って次のような順序でメッセージが届けられます。

              【通常】

              WM_ACTIVATEAPP - Parent
              WM_ACTIVATE - Parent (Activated)
              * WM_SETFOCUS - Parent
              * WM_LBUTTONDOWN - Child
              WM_LBUTTONUP - Child

              これはウィンドウプロシージャで採取したトレース情報です。
              親/子とも、WM_ACTIVATEAPP/WM_ACTIVATE/WM_SETFOCUS/WM_KILLFOCUS/WM_LBUTTONDOWN/WM_LBUTTONUPのどれかが来れば採取するように設定しましたが、実際に来たのはこれだけです。
              アクティブ化の際、WindowsがWM_SETFOCUSまでの一連のメッセージを親に送りつけた後で、子画面がWM_LBUTTONDOWNを拾っているのがわかると思います。

              #長くなってきたので次の発言に続けます
              • [3036] Re6:ファイルの更新不具合 ryoji(管理者による再投稿) 2003年08月29日 08:30

                > #長くなってきたので次の発言に続けます

                次に、同様な状況でWM_SETFOCUS処理内でモーダルダイアログ/メッセージボックスを表示した場合です。

                【WM_SETFOCUSでダイアログ表示】

                WM_ACTIVATEAPP - Parent
                WM_ACTIVATE - Parent (Activated)
                * WM_SETFOCUS - Parent
                WM_KILLFOCUS - Parent
                WM_ACTIVATE - Parent (Deactivated)
                ・この間ダイアログ表示
                WM_ACTIVATE - Parent (Activated)
                WM_SETFOCUS - Parent
                * WM_LBUTTONDOWN - Child

                ダイアログを閉じたあとで2回目のWM_ACTIVATE/WM_SETFOCUSペアの後に子画面がWM_LBUTTONDOWNを拾っています。
                このWM_LBUTTONDOWNのパラメータはアクティブ化の際に子ウィンドウをクリックした、まさにその場所を指していました。
                WM_LBUTTONUPは来ません。
                画面構成はもう少し複雑ですが、sakuraでもこれと同様なことが起きています。
                更新ダイアログを出しているWM_SETFOCUSはWM_LBUTTONDOWNをかすりもせずにアクティブ化の一環としてWindowsから直接呼ばれたものです。
                WM_SETFOCUS内でダイアログを表示しなくても同等の機能が得られるなら、それが良い方法だとは思われないでしょうか?
                今のところタイマー処理への一本化でsakura初心者の私が知る限りの画面的な不具合は解消していると思いますが、他にどなたかから名案が出れば、異存はありません。

                なお、ツールで確認したところ、sakuraでは一旦親画面がフォーカスを得ると編集操作中でも親画面がフォーカスを持ち続けていますね。
                フォーカスが常に親にあるので、キー入力は親から編集画面に転送される仕組みになっています。
                何のためにWM_LBUTTONDOWNで子(というより孫?)が親をSetFocus()しているのかは知りませんが、Windowsは、既にフォーカスを持っているウィンドウにSetFocus()しても何もしない(WM_SETFOCUSを送らない)ようです。

                > m_bBeginSelectは正解です。でも、次のSetFocusが悪さをしないか心配になります(他力本願モード)。
                >
                > case WM_LBUTTONDOWN:
                > //case WM_RBUTTONDOWN:
                > ::SetFocus( ::GetParent( m_hwndParent ) ); // これはWM_SETFOCUSを速達するんじゃないの?

                で、WM_SETFOCUS からモーダルダイアログ表示を除去する案に積極的に反対する理由は何ですか?
                • [3037] Re7:ファイルの更新不具合 wmlhq(管理者による再投稿) 2003年08月29日 08:33

                  チェックなし。
                  # CEditWnd_h.diff
                  202c202,203
                  <
                  ---
                  > int m_nTimerCount; // OnTimer用。wmlhq
                  >
                  # CEditWnd_cpp.diff
                  460a461
                  > m_nTimerCount = 0;
                  1101,1103c1102,1104
                  < /* ファイルのタイムスタンプのチェック処理 */
                  < m_cEditDoc.CheckFileTimeStamp();
                  <
                  ---
                  > ///* ファイルのタイムスタンプのチェック処理 */
                  > //m_cEditDoc.CheckFileTimeStamp(); // OnTimer に以降。wmlhq
                  > m_nTimerCount = 9;
                  2547c2548
                  < static int nLoopCount = 0;
                  ---
                  > //static int nLoopCount = 0; // Replaced by m_nTimerCount;
                  2551,2552c2552,2553
                  < if( 10 < nLoopCount ){
                  < nLoopCount = 0;
                  ---
                  > if( 10 < m_nTimerCount && GetCapture() == NULL){
                  > m_nTimerCount = 0;
                  2572c2573
                  < if( nLoopCount == 0 ){
                  ---
                  > if( m_nTimerCount == 0 ){
          • [3038] Re4:ファイルの更新不具合 wmlhq(管理者による再投稿) 2003年08月29日 08:34

            diffかいた。こっちに飛んで。

            http://www.kmkz.jp/mtm/roro/rorobbs.cgi?num=142&cfg=_config_&md=write
            • [3091] Re5:ファイルの更新不具合 げんた 2003年09月07日 13:23

              >http://www.kmkz.jp/mtm/roro/rorobbs.cgi?num=142&cfg=_config_&md=write
              何ですかこの掲示板? 妙なところにuuencodeで貼り付けたものですな(^^).