views:

767

answers:

6

I defined a global hook on WM_MOUSE that works perfectly for some time. It post a message to a specific window each time the mouse move.

After some random time the hook stop sending messages. If I unregister and register the hook it works again. I suppose some specific thing happening in Windows cause the hook to stop, but I can't find what.

Any ideas ?

Edit: I attached a debugger to other processes when the hook is not active anymore, and I observed that the dll is not loaded anymore.

What could cause a hook dll to unload ?

Edit2 : I find out that a crash in MouseHookProc the dll in any process unload the hook dll from every process it's loaded in. I can't find a cause to a crash in my code. Might be some race condition or something ? Here is the hook dll code :

#include "stdafx.h"

// define a data segment
#pragma data_seg(".SHARED")
HWND  hwnd=0;
HHOOK hHook=0;
#pragma data_seg()

// tell the linker to share the segment
#pragma comment(linker, "/section:.SHARED,RWS")

#define WM_MOUSEHOOK            WM_USER+0x100

HINSTANCE hInstance=0;


// this allow to build a very small executable without any extra libraries
// (probably not the problem, the bug still occurs without this )
#ifndef _DEBUG
void *__cdecl operator new(unsigned int bytes)
{
    return HeapAlloc(GetProcessHeap(), 0, bytes);
}

void __cdecl operator delete(void *ptr)
{
    if(ptr) HeapFree(GetProcessHeap(), 0, ptr);
}

extern "C" int __cdecl __purecall(void)
{
    return 0;
}
#endif

BOOL APIENTRY DllMain( HINSTANCE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{    
    hInstance=hModule;
    return TRUE;
}

LRESULT CALLBACK MouseHookProc(int nCode, WORD wParam, DWORD lParam)
{
    if(nCode==HC_ACTION && (wParam==WM_MOUSEMOVE || wParam==WM_NCMOUSEMOVE))
    {            
        MSLLHOOKSTRUCT *mhs=(MSLLHOOKSTRUCT*)lParam;        
        PostMessage(hwnd, WM_MOUSEHOOK, wParam, 0);
    }
    return CallNextHookEx(hHook,nCode,wParam,lParam);
}

extern "C" __declspec(dllexport) HHOOK InitializeWindowsHook(char *title)
{
    hwnd=FindWindow(0, title);
    if(hwnd)
        hHook=SetWindowsHookEx(WH_MOUSE, (HOOKPROC)MouseHookProc, hInstance, 0);
    return hHook;
}

extern "C" __declspec(dllexport) BOOL DeinitializeWindowsHook()
{
    if(hHook) {
        BOOL b=UnhookWindowsHookEx(hHook);
        hHook=0;
        return b;
    }
    return FALSE;
}
A: 

Is the essential data for your hook in a shared segment? At a minimum this would be the HHOOK and the HWND of the target window that receives notification messages.

Bob Moore
Yes the hook works perfectly, over all windows and thread for sometimes, then it stops working.
Emmanuel Caradec
A: 

Try using WH_MOUSE_LL instead.

Edit: about LowLevelMouseProc Function

The hook procedure should process a message in less time than the data entry specified in the LowLevelHooksTimeout value in the following registry key:

HKEY_CURRENT_USER\Control Panel\Desktop

The value is in milliseconds. If the hook procedure does not return during this interval, the system will pass the message to the next hook.

Nick D
I tried it but it fire so often that it slow down all applications and would it solve anything ?
Emmanuel Caradec
@Emmanuel Caradec, you should not do *heavy* work inside the hook procedure (there is a time limit). Notify some other routine to do the job (perhaps through posting a message) and return immediately.
Nick D
Actually the only thing I do is sending a message to a already know hwnd. I didn't investigate a lot with wh_mouse_ll since wm_mouse worked for me. What's the problem with wh_mouse ?
Emmanuel Caradec
I tried to lock wm_mouse for a very long time, but it didn't unload the dll. It makes the PC run slowly but that's expected.
Emmanuel Caradec
+2  A: 

Did you check, if the hook is still installed when its not called any more (i.e. check the return value from BOOL UnhookWindowsHook)?

Possibly another hook is installed that does not preserve your hook, not calling CallNextHookEx().

RED SOFT ADAIR
As you can see I do a CallNextHookEx in every cases.UnhookWindowsHook is most likely to have return ok because I've some logs there is nothing was logged.
Emmanuel Caradec
*You* call CallNextHookEx, but my assumption was that somewhere else a different hook is installed, that does not call CallNextHookEx. I dont know if this is a large project, where you maybe collaborate within a team. If so, scan all code for SetWindowsHookEx.
RED SOFT ADAIR
+1  A: 

I assume that the hook function is implemented in a DLL? Maybe something decreased the reference count on that DLL, so Windows unloads it, which stops your hook function.

I suggest that the first thing you do inside your DLL is to call LoadLibrary on yourself, so that the reference count of the DLL which contains the hook function is increased by one. Make sure not to call FreeLibrary to test this theory.

Frerich Raabe
+1  A: 

You should CloseHandle your hook handle btw.

The only thing i can think of that would cause a crash is if your hook handle has been destroyed. Can you trap the exception? Have you tried break on exception to break when the exception that is occurring occurs? If you don't know what exception is occurring have you tried added a __try/__finally block around your code?

Goz
I'll add a __try/__finally block today. I suppose there is a crash because that would cause the exact same behavior. I tried dereferencing a null pointer and this cause the unloading of every loaded hook dll. Windows probably add a __try,__finally block around hooks to unload them if they behave badly.
Emmanuel Caradec
When should I do a closehandle ? After the unhookwindowsex ?
Emmanuel Caradec
Exactly. For every handle you "create" then you should close it. I'm pretty sure FindWindow only returns you a pre-existing handle so it doesn't need to be closed. I believe that confusion is why COM introduced the whole addref/release thing :)
Goz
A: 

Hello,

We encountered the same issue but with LL keyboard hook.

Did you find out solution for this issue?

sam
We've found something in the form that the values in the shared segment loaded in other processes wasn't the correct values. It was values from a precedent launch. It seems to be caused by the crash of our executable followed by it's immediate reload by the watchdog (the hook dll should be unloaded then reloaded but that doesn't happen. We're not sure why, but reload speed seems to be the culprit. )
Emmanuel Caradec