views:

339

answers:

1

I have implemented custom tooltips for a couple of controls in my application (MFC) but I would like to make it general for all the controls.

Right now I am calling TrackMouseEvent in WM_MOUSEMOVE and then catching WM_MOUSEHOVER (both in the overwritten function WindowProc of the control). But this way I have to duplicate code for every control. So my intention was to set a global hook for mouse events and there ask the control for the message to display in the tooltip.

The problem is that I am not able to catch WM_MOUSEHOVER in a global hook. This is the code:

hMouseHook = SetWindowsHookEx( WH_MOUSE, 
        CallWndMouseProc, 
        NULL,
        AfxGetThread()->m_nThreadID);
hMainHook = SetWindowsHookEx( WH_CALLWNDPROC, 
        CallWndProc, 
        NULL,
        AfxGetThread()->m_nThreadID);

 LRESULT CALLBACK CallWndMouseProc( int nCode, 
            WPARAM wParam, 
            LPARAM lParam )
{
    if(nCode == HC_ACTION) 
    {
     MOUSEHOOKSTRUCT* pwp = (MOUSEHOOKSTRUCT*)lParam;
     TRACE( _T("message: %x hwnd: %x x: %d y: %d\n"),
        wParam,
        pwp->hwnd,
        pwp->pt.x,
        pwp->pt.y);

     TRACKMOUSEEVENT eventTrack;

     eventTrack.cbSize      = sizeof(TRACKMOUSEEVENT);
     eventTrack.dwFlags     = TME_HOVER;
     eventTrack.dwHoverTime = HOVER_DEFAULT;
     eventTrack.hwndTrack   = pwp->hwnd;

     _TrackMouseEvent(&eventTrack);

     if(wParam == WM_MOUSEHOVER)
     {
      AfxMessageBox(_T("CallWndMouseProc: WM_MOUSEHOVER"));
     }
    } 

    // let the  messages through to the next hook 
    return CallNextHookEx( hMouseHook, 
          nCode, 
          wParam, 
          lParam); 
}

LRESULT CALLBACK CallWndProc(   int nCode, 
           WPARAM wParam, 
           LPARAM lParam )
{
    if(nCode == HC_ACTION) 
    {
     CWPSTRUCT *pData = (CWPSTRUCT*)lParam;
     if(pData->message == WM_MOUSEHOVER)
     {
      AfxMessageBox(_T("CallWndProc: WM_MOUSEHOVER"));
     }
    } 

    // let the  messages through to the next hook 
    return CallNextHookEx( hMainHook, 
          nCode, 
          wParam, 
          lParam); 
}

Both hooks are being call for the rest of messages and I am sure WM_MOUSEHOVER is being sent because it's capture in the WindowProc function. For instance this is the WindowProc function for a custom CListBox:

LRESULT CMyListBox::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
    if(message == WM_MOUSEHOVER)
    {
     AfxMessageBox(_T("WindowProc: WM_MOUSEHOVER"));
    }
    return CListBox::WindowProc(message, wParam, lParam);
}

Ok. So what I am missing? It's just not possible to capture this message in a global hook? Is there other way to make this without having to put the same code in every single control?

Thanks.

Javier

+1  A: 

WM_MOUSEHOVER is posted to the thread's message queue, so you won't see it with WH_CALLWNDPROC (that's for sent messages). WH_MOUSE does get posted messages, so I find it a little strange that you aren't seeing it... Perhaps the hook only gets low level mouse input messages? Try a WH_GETMESSAGE hook.

Peter Ruderman
Yes, you're right. I just tried WH_GETMESSAGE and it works.Thanks!
Javier De Pedro