Question

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

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top