none
WM_CLOSEをキャンセルしたい。 RRS feed

  • 質問

  • グローバルフックを勉強中です。

    とりあえず、メモ帳を閉じれなくしてみようと思いコードを書いてみましたが
    WM_CLOSEのメッセージ自体は取得できているのですが肝心のキャンセルができません。
    書いたコードでどこか間違いがあるのでしょうか?

    どなたか教えてください。

    // フックを組み込む
    bool CALLBACK SetCloseCancel(HWND HandleofTarget)
    {
     //WndProc Hook
     if(hdllProc == NULL) return false;

     hTarget = HandleofTarget;
     hHookWnd = SetWindowsHookEx(WH_CALLWNDPROC,(HOOKPROC)CallWndProc, hdllProc, 0);

     if(hHookWnd == NULL)
     {
      return false;
     }

     return true;
    }

    LRESULT CALLBACK CallWndProc(int nCode,WPARAM wParam,LPARAM lParam)
    {
     //イベント発生順番?
     //WM_COMMAND
     //X (閉じる)=> WM_CLOSE => WM_DESTROY => WM_QUIT => 終了

     CWPSTRUCT *pcwp;

     if (nCode >= 0)
     {
      if (nCode == HC_ACTION)
      {
       //if (wParam == NULL)
       //{
       pcwp = (CWPSTRUCT *)lParam;

       if (pcwp->message == WM_CLOSE && wParam == 0)
       {
        if(pcwp->hwnd == hTarget)
        {
         MessageBoxW((HWND)wParam,TEXT("WM_CLOSE?"),TEXT("abc"),0);

         //ここのWM_CLOSEをキャンセルしたいのですが・・・
         //メモ帳を閉じた際に上のメッセージボックスが表示されるので
         //ここの処理まで来ていると思うのですが・・・・
         return 0;
        }
       }
       //}
      }
     }
     return CallNextHookEx(hHookWnd, nCode, wParam, lParam);
    }

    2010年12月10日 1:32

回答

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

    書いたコードに問題がないようなので解決とさせていただきたいと思います。

    Hongliangさんありがとうございました。

    • 回答としてマーク おれおれ 2010年12月13日 4:59
    2010年12月13日 1:31

すべての返信

  • CallWndProc フックプロシージャはメッセージを調べることはできますが、変更することはできません。フックプロシージャがシステムに制御を返した後、このメッセージはウィンドウプロシージャへ渡されます。

    と MSDN の CallWndProc 関数の解説にあるとおり、WH_CALLWNDPROC のフックプロシージャで何をしようが WindowProc は呼び出され実行されます。

    WH_GETMESSAGE であればフックプロシージャ内でメッセージの内容の変更が可能ですが、一般に WM_CLOSE は直接 WindowProc を呼び出して渡されるため、GetMessage に対するフックでは無力ですね。

    代案として、WH_CBT で WM_SYSCOMMAND の SC_CLOSE をキャンセルするなどが思いつきますが……。あるいは、サブクラス化でどうにかするとか(できるかどうかは知りませんが)。

    2010年12月10日 3:45
  • 代案として、WH_CBT で WM_SYSCOMMAND の SC_CLOSE をキャンセルするなどが思いつきますが……。あるいは、サブクラス化でどうにかするとか(できるかどうかは知りませんが)。


    http://cboard.cprogramming.com/windows-programming/55038-intercept-close-message.html

    を参考にして書いてみましたがそもそも、WM_SYSCOMMANDが取れません。

    WH_CBT で WM_SYSCOMMAND の SC_CLOSE をキャンセルの方法を説明しているHPを教えていただけませんか?

    参考に書いたコードです。

    LRESULT CALLBACK CallWndProc(int nCode,WPARAM wParam,LPARAM lParam)
    {
     //イベント発生順番
     //WM_COMMAND
     //X (閉じる)=> WM_CLOSE => WM_DESTROY => WM_QUIT => 終了

     MSG *msg;
     if(nCode >=0 )
     //if(nCode >=0 && nCode == HC_ACTION)
     {  
      msg = (MSG*)lParam;
      switch (msg->message)
      {
       case WM_SYSCOMMAND:
       {
        MessageBoxW((HWND)wParam,TEXT("WM_SYSCOMMAND?"),TEXT("abc"),0);  //ここのMsgBoxが表示されない・・・。
        //if (LOWORD(msg->wParam) == SC_CLOSE)
        if((msg->wParam & 0xFFF0) == SC_CLOSE)

        {
         MessageBoxW((HWND)wParam,TEXT("HWND?"),TEXT("abc"),0);
         if(msg->hwnd == hTarget)
         {
          return 1;
         }
        }
       }
       break;
      }
     }

     return CallNextHookEx(hHookWnd, nCode, wParam, lParam);
    }

    2010年12月10日 6:01
  • まず MSDN を参照するようにしましょう。CBTProc は日本語版もありますし。

    さて、これによると HCBT_SYSCOMMAND の場合、wParam にはコマンドの値、lParam にはマウス座標が格納されるみたいです。メッセージが送られたウィンドウのハンドルは渡されないみたいですね…特定のウィンドウを処理するには向かなさそうです。

    2010年12月10日 6:37
  • 提示していたHPにそれっぽいメッセージがあったので試しにやってみました所

    メモ帳ではフックが成功しましたが、なぜか試しにやってみたExcel2010では

    Excelが強制終了されてしまいました。

    SPY++で見た感じではメモ帳ではWM_CLOSEは見えていますがWM_DESTROYは見えません

    一方のEXCEL2010ではWM_DESTROYが記録されています。

    ここら辺の違いが関係していると思うのですが、アプリケーションによって

    このような差は出る物なのでしょうか?

    書いたコード

    LRESULT CALLBACK CallWndProc(int nCode,WPARAM wParam,LPARAM lParam)
    {
     if (nCode >= 0)
     {
      if(nCode==HCBT_DESTROYWND)
      {
       if((HWND)wParam==hTarget)
       {
        //提示していただいたHPでは「未定義であり、0 に設定しなければなりません。」と
        //記載されているが0だと閉じれる。1なら閉じれない。
        return 1;
       }
      }
     }

     return CallNextHookEx(hHookWnd, nCode, wParam, lParam); //次のフックを呼ぶ
    }

    2010年12月10日 8:22
  •     //提示していただいたHPでは「未定義であり、0 に設定しなければなりません。」と
        //記載されているが0だと閉じれる。1なら閉じれない。

    MSDN の CBTProc の解説ですか? 未定義となっているのは lParam の値ですよ。返値についてはその表の上に「拒否する場合は 1 を返せ」と記述されています。

    どうやら HCBT_DESTROYWND は WM_CLOSE で DefWindowProc が呼び出されたときにフックプロシージャが呼び出されるようなので、その前に(WM_CLOSE で)独自の終了処理を行っているアプリケーションであれば普通に問題が発生するでしょう。

    2010年12月10日 10:43
  • 回答ありがとうございます。

    書いたコードに問題がないようなので解決とさせていただきたいと思います。

    Hongliangさんありがとうございました。

    • 回答としてマーク おれおれ 2010年12月13日 4:59
    2010年12月13日 1:31