VC获取鼠标hook时的做法

来源:互联网 发布:软件开发人员职位 编辑:程序博客网 时间:2024/04/29 05:46

//NCButtonUpHelper.h

#pragma  once

extern HHOOK hMouseHook;
extern bool bNcLButtonDown;

LRESULT CALLBACK MouseHookProc(int nCode,WPARAM wParam, LPARAM lParam);

 

 

//NCButtonUpHelper.cpp

#include "stdafx.h"

HHOOK hMouseHook = NULL;
bool bNcLButtonDown = false;

LRESULT CALLBACK MouseHookProc(int nCode,WPARAM wParam, LPARAM lParam)
{
 if (nCode == HC_ACTION)
 {
  PMOUSEHOOKSTRUCT mhs = (PMOUSEHOOKSTRUCT)lParam;
   CWnd   *pWnd   =   AfxGetMainWnd();
  switch (wParam)
  {
  case WM_NCLBUTTONDOWN:
   {
    if (HTCAPTION == mhs->wHitTestCode && mhs->hwnd == pWnd->GetSafeHwnd())
    {
     SendMessage(mhs->hwnd,WM_NCLBUTTONDOWN,HTCAPTION,MAKELONG(mhs->pt.x,mhs->pt.y));
     bNcLButtonDown = true;
    }
   }
   break;
  case WM_NCLBUTTONUP:
   {
    bNcLButtonDown = false;
   }
   break;
  case WM_LBUTTONUP:
   {
    if (true == bNcLButtonDown && mhs->hwnd == pWnd->GetSafeHwnd())
    {
     PostMessage(mhs->hwnd,WM_NCLBUTTONUP,HTCAPTION,MAKELONG(mhs->pt.x,mhs->pt.y));
     bNcLButtonDown = false;
    }
   }
   break;
  }
 }

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

 

//例子加入,鼠标点击客户区外(对话框标题栏、非设备区)

#include "NCButtonUpHelper.h"

在OnInitDialog()初始化对话框里加入

hMouseHook = SetWindowsHookEx(WH_MOUSE,
  (HOOKPROC)MouseHookProc,
  (HINSTANCE)AfxGetInstanceHandle(),
  AfxGetThread()->m_nThreadID);

 

在OnDestroy()消息里添加卸载钩子

if (hMouseHook != NULL)
 {
       UnhookWindowsHookEx(hMouseHook);
 }

 

接下来就能用对话框里的各类非工作区或非客户区的消息了

OnNcMouseMove(UINT nHitTest, CPoint point)、OnNcLButtonDown(UINT nHitTest, CPoint point)、OnNcLButtonUp(UINT nHitTest, CPoint point)、OnNcHitTest(CPoint point)

相关用法可以参考例子

 

关于SetWindowsHookEx情况MSDN,我这里引入了一个论坛上的内容,请耐心阅读

********************************************************************************

This   article   was   contributed   by   Robert   Wiejak.  
  Environment:   MFC,   Windows   95,   98,   Me,   NT   3.51,   4.0,   5.0  

If   you   spend   time   investigating   what   happens   when   you   click   and   release   the   left   button   over   the   title   bar,   you   will   find   out   that   instead   of   getting   "non-client   left   button   up "   message,   you   just   get   "left   button   up ".   One   could   actually   work   with   it,   if   the   message   found   it 's   way   into   the   application.   It   does   not.

I   was   in   a   middle   of   writing   an   application   when   I   discovered   this.   I   looked   all   over   the   internet   for   articles   regarding   WM_NCLBUTTONUP   problem,   but   the   only   thing   I   could   find   were   questions   about   the   problem.   After   some   more   investigating   I   have   come   up   with   a   patch   that   could   be   adopted   by   each   application   requiring   such   notification.

The   patch   consists   of   installing   a   "windows   hook "   that   will   intercept   all   mouse   messages   for   this   application   before   they   enter   into   the   message   pump.   To   do   that   you   need   to   call   SetWindowsHookEx(...)   function,   soon   after   the   main   window   is   created.   Here   is   the   call:  

hMHook   =   SetWindowsHookEx(  
                                          //   hook   type:  
                                WH_MOUSE,
                                          //   hook   procedure:  
                                (HOOKPROC)   MouseHookProc,
                                          //   handle   to   application   instance:  
                                AfxGetInstanceHandle(),
                                          //   thread   identifier:  
                                AfxGetThread()-> m_nThreadID
                        );
It   is   very   important   that   you   supply   handle   to   application   instance   and   thread   identifier,   otherwise   every   application   running   on   your   computer   will   attempt   to   hook   it 's   mouse   messages   through   your   program   and   it   could   be   disastrous.   By   supplying   these   two   parameters   you   will   insure   that   only   messages   from   your   application   will   end   up   in   your   callback   function.  

Equally   important   is   a   call   to   remove   the   hook   before   your   application   terminates.   The   UnhookWindowsHookEx(...)   function   removes   a   hook   procedure   installed   in   a   hook   chain.   Most   likely   you   will   call   it   somewhere   in   OnDestroy(),   like   this:  

      if(hMHook   !=   NULL)
            UnhookWindowsHookEx(hMHook);
The   callback   function   is   where   you   will   receive   WM_NCLBUTTONDOWN   message   and   the   next   time   you   receive   WM_LBUTTONUP   message   you   will   post   WM_NCLBUTTONUP   directly   into   the   application   message   pump.   Therefore,   no   special   handling   will   be   required   to   service   these   messages.   You   will   simply   write   your   code   inside   of   OnNcLButtonUp(...),   just   like   you   would   for   any   other   message.  

Here   is   the   callback   code:  

//   ////////////////////////////////////////////////////
//   handle   to   the   mouse   hook
HHOOK   hMHook   =   NULL;

//   status   of   non-client   left   button   down
BOOL   bNcLButtonDown   =   FALSE;    

//   /////////////////////////////////////////////////////
//   Mouse   hook   process

LRESULT   CALLBACK   MouseHookProc(   int   nCode,  
                                                                WPARAM   wParam,
                                                                LPARAM   lParam)  
{  
    if(nCode   ==   HC_ACTION)  
    {  
        //   get   a   pointer   to   the   mouse   hook   struct.  
        PMOUSEHOOKSTRUCT   mhs   =   (PMOUSEHOOKSTRUCT)   lParam;  
       
        //   intercept   messages   for   left   button   down   and   up
        switch(wParam)  
        {  
                case   WM_NCLBUTTONDOWN:  
                  {
                          //   get   the   pointer   to   the   main   window  
                          CWnd   *pWnd   =     AfxGetMainWnd();  

                          //   if   the   message   is   from   your   window   and  
                          //   the   hit   test   indicates   title   bar  
                          if((mhs-> hwnd   ==   pWnd-> GetSafeHwnd())  
                                  &&   (mhs-> wHitTestCode   ==   HTCAPTION))
                          {  
                                  //   then   indicate   non-client   left   button   down  
                                  bNcLButtonDown   =   TRUE;  
                               
                                //     there   is   no   problem   with   this   message  
                                //   so   you   don 't   have   to   do   anything   else  
                          }  
                }  
                break;  
               
                case   WM_NCLBUTTONUP:  
                        //   you   will   get   this   message   if   you   double-click  
                        //           on   the   title   bar  
                        //   reset   the   status  
                        bNcLButtonDown   =   FALSE;    
                        break;

                case   WM_LBUTTONUP:  
                    {
                            //     get   the   pointer   to   the   main   window  
                            CWnd   *pWnd   =   AfxGetMainWnd();  

                            //   if   the   message   is   from   your   window   and  
                            //   non-client   left   button   is   down
                            if((mhs-> hwnd   ==   pWnd-> GetSafeHwnd())  
                                    &&   (bNcLButtonDown   ==   TRUE))  
                            {
                                  //   then   post   WM_NCLBUTTONUP   message   directly  
                                  //   into   your   window   message   pump  
                                  //   Note:   I 'm   hardcoding   HTCAPTION   because   the  
                                  //   left   button   was   down,   and   while   it   is   down,
                                  //   the   mouse   does   not   move   in   respect   to   the  
                                  //   window,   but   it   does   in   respect   to   the   screen,
                                  //   so   the   mouse   should   still   be   over   the   caption
                                  //   bar   of   your   window   when   you   release   the   button.
                                  pWnd-> PostMessage(WM_NCLBUTTONUP,   HTCAPTION,  
                                                                MAKELONG(mhs-> pt.x,mhs-> pt.y));

                                  //   reset   non-client   left   button   down  
                                  bNcLButtonDown   =   FALSE;
                            }
                    }  
                    break;  

                default:  
                        break;  
        }  
    }  
    //   let   the   messages   through   to   the   next   hook  
  return   CallNextHookEx(hMHook,   nCode,   wParam,   lParam);  
}

I   am   including   two   sample   projects.   The   "nclbxExample "   is   technical,   and   the   "AlphaDialogExample "   is   more   practical.   The   "nclbxExample "   is   better   documented   so   you   can   see   how   and   were   I   have   implemented   the   code.  

NOTE:   If   you   are   going   to   use   mousepatch.cpp   the   way   I 'm   using   it,   DO   NOT   add   it   to   your   project.

 

********************************************************************************************

 

原创粉丝点击