locked
Windows 7, SetWindowsHookEx, callback proc stops getting called after exceeding max time allowed RRS feed

  • Question

  • When setting a low level mouse hook using SetWindowsHookEx I am seeing a difference in operation between Vista and Windows 7 RC:

    If, for whatever reason - random peak in CPU usage, whatever - my registered mouse hook callback proc takes longer than the maximum allowed time, on Vista my hook function will still get called again, on Windows 7 RC my callback appears never to be called again.

    Can someone confirm that this is new, expected behavior for Windows 7?

    Thanks

    Ross
    Tuesday, July 28, 2009 10:29 PM

All replies

  • I can't confirm whether this is expected behavior for Windows 7, but I *can* confirm that this is *new* behavior in Windows 7.  Our app hooks WH_MOUSE_LL and WH_KEYBOARD_LL and until Windows 7 we never had any problems with our callbacks getting called.  Now we've started seeing what seems to be the behavior you describe with Windows 7 build 7100 and it looks like also with RTM.

    doh....
    Friday, August 14, 2009 11:10 PM
  • Hey Tim,

    Yep.  Same thing we are seeing with our app.  Doesn't seem like a change that should have been made given that there is no documented mechanism to check to see if your hook is still installed (so you can reinstall it if it's not), and the reason your hook proc took too long is likely something outside of your application's control.

    A timer polling for mouse position seems like a hack and it doesn't help with keyboard or mouse button events.

    Still looking for a sane solution.  Anyone got any good ideas?


    - Ross
    Friday, August 14, 2009 11:23 PM
  • I'm having the same problem.  I'm running Windows 7 RTM, so it hasn't been fixed since 7100.  Tried it in VC++ and VC#.  Never had this problem with XP/Vista.
    Monday, September 14, 2009 2:14 AM
  • We have just found this in our application. We added this DWORD to the registry and the problem went away.

    HKEY_CURRENT_USER\Control Panel\Desktop\

    LowLevelHooksTimeout=10000

    We set it to 10000 as a first attempt. I have seen this key on other images set to 5000.

    It must be set by default in the system to something lower on Win 7 than in Vista.

    Hope this helps you guys as we were really worried about this one.

    Thursday, September 17, 2009 12:37 PM
  • We have just found this in our application. We added this DWORD to the registry and the problem went away.

    HKEY_CURRENT_USER\Control Panel\Desktop\

    LowLevelHooksTimeout=10000

    We set it to 10000 as a first attempt. I have seen this key on other images set to 5000.

    It must be set by default in the system to something lower on Win 7 than in Vista.

    Hope this helps you guys as we were really worried about this one.


    If that works, I will hug you.  I have been trying all sorts of things to get it to work.  I can't believe the solution could be that simple.
    Sunday, September 20, 2009 5:13 PM
  • It's unfortunate that this has to be the fix - as it's not exactly ideal allowing up to 10 seconds for a low-level hook to return.  I don't know if the timeout value is necessarily lower for Windows 7, rather that you only get one chance to fail to do your processing in time - you fail once and you are kicked out of the callback chain.  Vista was more forgiving.  You would still get called again.
    Tuesday, September 22, 2009 7:34 PM
  • This really shows that the reason is the bug in Windows 7 : "No low level mouse hook calls will be made after any exceeding of
    the LowLevelHooksTimeout occurs. And it is true only for Windows7"


    Unfortunately, such solution could lead to system performance issues and not acceptable for the commercial programs.

    I have the following workaround:
    Create and start during initialization a separate thread which sets the mouse_ll hook and proceeds win message queue,
    like this:

    DWORD WINAPI mouseLLHookThreadProc(LPVOID lParam)
    {
        MSG msg;

        _hMouseLLHook = SetWindowsHookEx( WH_MOUSE_LL, .....);

        while(GetMessage(&msg, NULL, 0, 0) != FALSE)
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        return 0;
    }

    This will make your mouse_ll processing independent of main GUI thread of the application to avoid timeout exceeding.
    But, again, this is just workaround for Win7 bug behavior

    Anyway, I hope Zenexer will hug me. (Or hope not :-))
    • Proposed as answer by Zenexer Tuesday, October 13, 2009 9:39 PM
    Tuesday, September 22, 2009 9:22 PM
  • No hugs for alexkrav57, I'm afraid.  I've already tried this method without luck.  Heck, I had a fully optimized callback system with literally the minimal possible processing time--I tried it in every language I could think of, except assembly--without any luck whatsoever.
    Tuesday, October 13, 2009 9:39 PM
  • It's pity.
    I had the problem and it was 100% reproducible. 
    When I switched to separate queue thread - the problem gone. And now you scared me again...

    Just for recheck for your try: 
       - was this thread separated from GUI/app thread and assigned just for hook messages?
       - was SetWindosHookEX(...) called from inside of this new thread proc?

    I've also elevated priority for this thread.

    Thanks.
    • Proposed as answer by Alexis Monday, January 11, 2010 3:40 PM
    Wednesday, October 14, 2009 8:33 PM
  • Hi Zenexer,

     

    Have you ever found a solution for this issue? I'm having the same problems. 

     

    Tried the registry key, separate thread for a GetMessage() loop, separate DLL application that passes on the messages, but nothing seems to work.

    Sunday, June 20, 2010 10:37 AM
  • No, I never did.  It suddenly started working for me.  Maybe it was the fact that I upgraded to the final release of VS2010.  More likely, though, is that it was fixed in Windows 7 build 7600.  That is, hooks are now given more time to respond before they are dropped.  This timeframe can apparently be changed via a registry setting; I can't seem to recall if I ever tried it, though (sorry, bit of amnesia of that year for medical reasons).  If the registry key didn't fix it, who knows.  What build are you running?  Perhaps it was fixed in an update?  Or maybe I'm really confused, and I've only tested it on Windows Server 2008 R2 and not Windows 7.
    Thursday, June 24, 2010 6:03 AM
  •  

    I'd like to hear what's the status with this as I'm battling the same issue.

     

    Has it become more clear to zenexer why it's all working for you now? The bigger timeout works just fine for you?

     

    Wednesday, September 29, 2010 8:32 AM
  •    I am seeing something very similar in XP SP3. I'm using an injection DLL hook to trap LVM_INSERTITEMA in a ListView control in a native C++ app.

    The  HookProc copies the text from the ListView item to a shared memory mapped file(after obtaining a mutex) 

    and then calls ControlService(....) to notify a C# managed service via a service command. The C# service then calls

    a function in the injection DLL to copy the string into a StringBuilder object. 

    This all works fine for up to 100 iterations and then the HOOKPROC just stops being called without warning.

    No exceptions, etc.

    Any ideas are greatly appreciated.

    Tom Fisher

    Sunday, October 10, 2010 7:39 PM
  • No, I never did.  It suddenly started working for me.  Maybe it was the fact that I upgraded to the final release of VS2010.  More likely, though, is that it was fixed in Windows 7 build 7600.  That is, hooks are now given more time to respond before they are dropped.  This timeframe can apparently be changed via a registry setting; I can't seem to recall if I ever tried it, though (sorry, bit of amnesia of that year for medical reasons).  If the registry key didn't fix it, who knows.  What build are you running?  Perhaps it was fixed in an update?  Or maybe I'm really confused, and I've only tested it on Windows Server 2008 R2 and not Windows 7.

    No, alas Zenexer, I'm using build 7600 and the problem is very real. As described by everyone else, same symptom. A nightmare because I see no way of testing whether my hook is installed or not and so can't even autocorrect the problem. I just lose the hook for reasons beyond my app's control, and it seeems to get booted at some point in time without warning from when on no more hook ... Nightmare, as described by many above, and alive and real in build 7600. I am also using the final release of VS2010 (albeit express edition).

    Project Manager, Manager of Support, Quality Assurance and Documentation
    Thursday, November 4, 2010 11:47 AM
  •   Here's a good method to check the status of a hook in XP SP3. I used the concepts/code discussed to create a hook checking fn to monitor my hookproc. Works very well.

    http://zairon.wordpress.com/2006/12/06/any-application-defined-hook-procedure-on-my-machine/

    Hope this helps.

    TF

    Monday, December 27, 2010 11:50 PM
  • Does that work in Win7?  Would you consider posting source code to check the status of your Win7 mouse/kb hook here?
    Tuesday, January 4, 2011 2:23 PM
  •    I'm using it in XP SP3. Don't know about Win7. I modified the code and placed it in the following function in a DLL:

    extern __declspec(dllexport)
    ULONG __stdcall GetHookInfo( HANDLE hHook, int info_type)
    {
      NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
      PVOID ImageBase;
      ULONG DllCharacteristics = 0;
      PVOID User32InitializeImmEntryTable = NULL;
    	UNICODE_STRING DllName;
      ANSI_STRING ProcedureName;
      ULONG i;
      ULONG UserDelta = 0;
      ULONG HandleEntries = 0;
      SHARED_INFO *SharedInfo = NULL;
      HANDLE_ENTRY *UserHandleTable = NULL;
      HOOK *HookInfo = NULL;
    	RtlInitUnicodeString(&DllName, L"user32");
    	
    	NtStatus = LdrLoadDll(
    							NULL,        // DllPath
    							&DllCharacteristics, // DllCharacteristics
    							&DllName,      // DllName
    							&ImageBase);     // DllHandle
    		if(NtStatus == STATUS_SUCCESS)
    		{
    			RtlInitAnsiString(&ProcedureName,"User32InitializeImmEntryTable");
    			NtStatus = LdrGetProcedureAddress(
    											 ImageBase,                // DllHandle
    											 &ProcedureName,             // ProcedureName
    											 0,                    // ProcedureNumber OPTIONAL
    											 (PVOID*)&User32InitializeImmEntryTable); // ProcedureAddress
    			if(NtStatus == STATUS_SUCCESS)
    			{
    				__asm
    				{
    					mov esi, User32InitializeImmEntryTable
    					test esi, esi
    					jz __exit2
    					mov ecx, 0x80	
    				__loop:
    					dec ecx
    					test ecx, ecx
    					jz __exit1
    					lodsb
    					cmp al, 0x50
    					jnz __loop
    					lodsb
    					cmp al, 0x68
    					jnz __loop
    					lodsd
    					mov SharedInfo, eax
              jmp __exit2
    				__exit1:
    					mov SharedInfo, ecx
    				__exit2:
    					sub eax, eax
    					mov eax, fs:[eax+0x18]
    					lea eax, [eax+0x06CC]
    					mov eax, [eax+0x001C]
    					mov UserDelta, eax
    				}
            HandleEntries = *((ULONG *)((ULONG)SharedInfo->ServerInfo + 8));
            UserHandleTable = (HANDLE_ENTRY *)SharedInfo->HandleEntryList;
            for(i=0; i<HandleEntries; i++)
            {
              if(UserHandleTable[i].Type == TYPE_HOOK)
              {
                __try
                {
                  HookInfo = (HOOK *)((ULONG)UserHandleTable[i].Head - UserDelta);
    							
    							if(HookInfo->Handle == hHook) 
    								{
    								if(info_type == 0)
    									return HookInfo->Flags;
    								if(info_type==1)
    									return HookInfo->Hooked;
    								}
                }
                __except(EXCEPTION_EXECUTE_HANDLER) {}
              }
            }
          }
        }
    		return -1;
      }
    
    Tuesday, January 4, 2011 3:09 PM
  • I will try your proposed answer on win 7 and will tell if it is works. I also found this here: http://d.hatena.ne.jp/apollo440/20110312. Maybe interesting for people who need all these declarations for your function.

    Since your function looks quite complicate I would like to propose my more simple solution for an low level (keyboard) hook check:

    In some intervall you send some keycode to your LLKeyboard hook. This keycode needs to be swallowed because it is just for checking. The LLKeyboard hooks knows it needs  to be swallowed by some shared memory boolean value which needs to be set to true before sending this keycode for checking.

    The LLKeyboard hook does send then PostMessage(hWnd, WM_RECEIVED_KEY,...); and you know after a timeout of about 1 second after sending your keycode that the LLKeyboard hook is dead if you do not receive this Message.

    Simple but works.

     

    Friday, March 18, 2011 10:55 AM
  • Hi there!

    I had the same problem: hooks that perfectly works with Windows XP, not working on Windows 7. I have read already the most popular questions, e.g. this link, but didn't find the solution.

    Thanks,
    Max


    Tuesday, May 3, 2011 12:10 PM
  • One of two things are really needed:

    -A way to set a timeout specific to a hook you have installed - so you could allow for an obscenely high timeout of say 20 seconds on a hook you know you never want to lose messages to without having it alter the timeout behavior of all the other installed hooks which may actually require a low timeout for proper functionality and performance. THIS IS PREFERABLE so you won't lose the message that was being processed at the time of the timeout since we have determined that it's NOT the hook's fault causing this timeout issue in the first place.
    -A non-workaround way to determine if a hook times out and is uninstalled. A function you can use to poll it or a message sent to the thread the hook was installed on saying the hook has been forcefully uninstalled.

    Monday, May 9, 2011 9:53 PM
  •   I wouldn't hold my breath waiting for any help on this obvious problem. I'm sure that MS has noted this thread BUT no one from MS

    has even bothered to offer a solution or comment. Fortunately, the workaround that I posted works well enough that I don't have to worry about it.

    TF

     

    Tuesday, May 10, 2011 2:12 PM
  • I know I'm really really late to the gate in this thread and I imagine the original needs are no longer relevant, but here are my two cents for what they're worth, in case they're useful to someone....

     

     

    We have just found this in our application. We added this DWORD to the registry and the problem went away. HKEY_CURRENT_USER\Control Panel\Desktop\ LowLevelHooksTimeout=10000 We set it to 10000 as a first attempt. I have seen this key on other images set to 5000. It must be set by default in the system to something lower on Win 7 than in Vista. Hope this helps you guys as we were really worried about this one.

     

    This is a workaround for a single machine, and does not address the question, which concerns a difference in hook management - not timeout configuration - between Vista and Windows 7. Setting the timeout to 10 seconds on a user's machine would be pretty vile. (I would argue that the timeout should never ever enter the realm of values noticeable to the user. Low-level hooks are a privilege that should be used only for fly-on-the-wall observation, dispatching any resulting time-consuming actions to other threads.)

     

     

    No hugs for alexkrav57, I'm afraid. I've already tried this method without luck. Heck, I had a fully optimized callback system with literally the minimal possible processing time--I tried it in every language I could think of, except assembly--without any luck whatsoever.

     

    Have you verified that your message queue is not being hit with extraneous messages somehow? I notice alex's version does not peek + filter/prioritize. Have you tried posting the message to another thread rather than doing any real work in your hook routine? Stripping that routine down to bare bones may help since it's executed synchronously by DispatchMessage. (Obviously this would be unacceptable if you needed to block input while you were processing, but I really hope this is not the case).

     

    Have you tried checking for page faults (e.g. using Task Manager, Process Monitor, or Process Explorer)? The time taken for the memory manager to page your image, any memory you reference, or even system / kernel mode images back into RAM may be counted against the hooks. I wouldn't be surprised. Also, I've gotten the sense that page faults have to compete with ordinary disk transactions, so your situation could potentially be caused not only by a moderate-to-high system-wide memory burden but also by a heavy IO burden on the disk containing your page file. If you do find that page faults may be causing the problem, you can try

    • Setting the value of registry key DisablePagingExecutive to 1 on your own machine for diagnostic purposes, remembering to change it back afterward to stay in sync with your target users.
    • Locking your image memory and relevant allocations into RAM - i.e. preventing paging for the pages (can we go back to calling it swapping?) relevant to your hook routine. (At least, you can request the MM do this. It may not honor the request though.)
    • Not making any unnecessary synchronous calls into code external to the image containing your handler - i.e. any code loaded from another PE, including windows API exports.

    Hopefully Windows' memory management and its interaction with disk IO will be 'fixed' some day. I'm not holding my breath in the meantime.

     

    Also, for diagnostic s***s and giggles, if you're using a wireless and/or optical mouse (I guess most of us are these days), you might try replacing the batteries or using a wired/non-optical input device. I've gotten the terrible feeling lately that my mice are offloading some amount of processing, as my cursor often skips or hitches under heavy load conditions when the batteries aren't fresh. (I don't know the implementation details of these mice, and the real issue may simply be load-dependent near-field EM interference generated by the computer, but my rationale here is that more intensive driver-side processing could be required when the signal isn't pristine. I have no particular reason to think this would substantively affect low-level hook management, but you never know.)

     

    Hope some of this helps someone, some time.

    Jory

     





    • Edited by Jory M Thursday, December 15, 2011 12:02 AM
    Wednesday, December 14, 2011 11:39 PM
  •   I solved my problem by using Subclassing instead of SetWindowsHook.

    Very reliable now ;-))))

     

    TB

     

    Friday, December 23, 2011 5:49 PM