- NtUserSetWindowsHookEx: Don't leak a thread reference in case we are passed a Thread Id
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / hook.c
index a667ba5..d0ff498 100644 (file)
@@ -72,9 +72,9 @@ PHOOK FASTCALL IntGetHookObject(HHOOK hHook)
 static PHOOK
 IntAddHook(PETHREAD Thread, int HookId, BOOLEAN Global, PWINSTATION_OBJECT WinStaObj)
 {
-   PW32THREAD W32Thread;
+   PTHREADINFO W32Thread;
    PHOOK Hook;
-   PHOOKTABLE Table = Global ? GlobalHooks : MsqGetHooks(((PW32THREAD)Thread->Tcb.Win32Thread)->MessageQueue);
+   PHOOKTABLE Table = Global ? GlobalHooks : MsqGetHooks(((PTHREADINFO)Thread->Tcb.Win32Thread)->MessageQueue);
    HANDLE Handle;
 
    if (NULL == Table)
@@ -90,7 +90,7 @@ IntAddHook(PETHREAD Thread, int HookId, BOOLEAN Global, PWINSTATION_OBJECT WinSt
       }
       else
       {
-         MsqSetHooks(((PW32THREAD)Thread->Tcb.Win32Thread)->MessageQueue, Table);
+         MsqSetHooks(((PTHREADINFO)Thread->Tcb.Win32Thread)->MessageQueue, Table);
       }
    }
 
@@ -106,7 +106,7 @@ IntAddHook(PETHREAD Thread, int HookId, BOOLEAN Global, PWINSTATION_OBJECT WinSt
 
    if (Thread)
    {
-      W32Thread = ((PW32THREAD)Thread->Tcb.Win32Thread);
+      W32Thread = ((PTHREADINFO)Thread->Tcb.Win32Thread);
       ASSERT(W32Thread != NULL);
       W32Thread->Hooks |= HOOKID_TO_FLAG(HookId);
       if (W32Thread->ThreadInfo != NULL)
@@ -130,7 +130,7 @@ IntGetTable(PHOOK Hook)
       return GlobalHooks;
    }
 
-   return MsqGetHooks(((PW32THREAD)Hook->Thread->Tcb.Win32Thread)->MessageQueue);
+   return MsqGetHooks(((PTHREADINFO)Hook->Thread->Tcb.Win32Thread)->MessageQueue);
 }
 
 /* get the first hook in the chain */
@@ -161,7 +161,8 @@ IntGetFirstValidHook(PHOOKTABLE Table, int HookId)
 }
 
 /* find the next hook in the chain, skipping the deleted ones */
-static PHOOK FASTCALL
+PHOOK
+FASTCALL
 IntGetNextHook(PHOOK Hook)
 {
    PHOOKTABLE Table = IntGetTable(Hook);
@@ -207,7 +208,7 @@ IntFreeHook(PHOOKTABLE Table, PHOOK Hook, PWINSTATION_OBJECT WinStaObj)
 static VOID
 IntRemoveHook(PHOOK Hook, PWINSTATION_OBJECT WinStaObj, BOOL TableAlreadyLocked)
 {
-   PW32THREAD W32Thread;
+   PTHREADINFO W32Thread;
    PHOOKTABLE Table = IntGetTable(Hook);
 
    ASSERT(NULL != Table);
@@ -216,7 +217,7 @@ IntRemoveHook(PHOOK Hook, PWINSTATION_OBJECT WinStaObj, BOOL TableAlreadyLocked)
       return;
    }
 
-   W32Thread = ((PW32THREAD)Hook->Thread->Tcb.Win32Thread);
+   W32Thread = ((PTHREADINFO)Hook->Thread->Tcb.Win32Thread);
    ASSERT(W32Thread != NULL);
    W32Thread->Hooks &= ~HOOKID_TO_FLAG(Hook->HookId);
    if (W32Thread->ThreadInfo != NULL)
@@ -266,24 +267,36 @@ IntReleaseHookChain(PHOOKTABLE Table, int HookId, PWINSTATION_OBJECT WinStaObj)
 }
 
 static LRESULT FASTCALL
-IntCallLowLevelHook(INT HookId, INT Code, WPARAM wParam, LPARAM lParam, PHOOK Hook)
+IntCallLowLevelHook(PHOOK Hook, INT Code, WPARAM wParam, LPARAM lParam)
 {
    NTSTATUS Status;
    ULONG_PTR uResult;
 
    /* FIXME should get timeout from
     * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
-   Status = co_MsqSendMessage(((PW32THREAD)Hook->Thread->Tcb.Win32Thread)->MessageQueue, (HWND) Code, HookId,
-                              wParam, lParam, 5000, TRUE, TRUE, &uResult);
+   Status = co_MsqSendMessage(((PTHREADINFO)Hook->Thread->Tcb.Win32Thread)->MessageQueue,
+                                    (HWND) Code,
+                                   Hook->HookId,
+                                         wParam,
+                                         lParam,
+                                           5000,
+                                           TRUE,
+                                     MSQ_ISHOOK,
+                                       &uResult);
 
    return NT_SUCCESS(Status) ? uResult : 0;
 }
 
-LRESULT FASTCALL
+/*
+  Called from inside kernel space.
+ */
+LRESULT
+FASTCALL
 co_HOOK_CallHooks(INT HookId, INT Code, WPARAM wParam, LPARAM lParam)
 {
-   PHOOK Hook;
-   PW32THREAD Win32Thread;
+   PHOOK Hook, SaveHook;
+   PTHREADINFO pti;
+   PCLIENTINFO ClientInfo;
    PHOOKTABLE Table;
    LRESULT Result;
    PWINSTATION_OBJECT WinStaObj;
@@ -291,14 +304,14 @@ co_HOOK_CallHooks(INT HookId, INT Code, WPARAM wParam, LPARAM lParam)
 
    ASSERT(WH_MINHOOK <= HookId && HookId <= WH_MAXHOOK);
 
-   Win32Thread = PsGetCurrentThreadWin32Thread();
-   if (NULL == Win32Thread)
+   pti = PsGetCurrentThreadWin32Thread();
+   if (!pti)
    {
       Table = NULL;
    }
    else
    {
-      Table = MsqGetHooks(Win32Thread->MessageQueue);
+      Table = MsqGetHooks(pti->MessageQueue);
    }
 
    if (NULL == Table || ! (Hook = IntGetFirstValidHook(Table, HookId)))
@@ -311,17 +324,10 @@ co_HOOK_CallHooks(INT HookId, INT Code, WPARAM wParam, LPARAM lParam)
       }
    }
 
-   if (Hook->Thread != PsGetCurrentThread()
-         && (WH_KEYBOARD_LL == HookId || WH_MOUSE_LL == HookId))
-   {
-      DPRINT("Calling hook in owning thread\n");
-      return IntCallLowLevelHook(HookId, Code, wParam, lParam, Hook);
-   }
-
    if ((Hook->Thread != PsGetCurrentThread()) && (Hook->Thread != NULL))
    {
-      DPRINT1("Calling hooks in other threads not implemented yet");
-      return 0;
+      // Post it in message queue.
+      return IntCallLowLevelHook(Hook, Code, wParam, lParam);
    }
 
    Table->Counts[HOOKID_TO_INDEX(HookId)]++;
@@ -330,8 +336,19 @@ co_HOOK_CallHooks(INT HookId, INT Code, WPARAM wParam, LPARAM lParam)
       GlobalHooks->Counts[HOOKID_TO_INDEX(HookId)]++;
    }
 
-   Result = co_IntCallHookProc(HookId, Code, wParam, lParam, Hook->Proc,
-                               Hook->Ansi, &Hook->ModuleName);
+   ClientInfo = GetWin32ClientInfo();
+   SaveHook = ClientInfo->phkCurrent;
+   ClientInfo->phkCurrent = Hook;     // Load the call.
+
+   Result = co_IntCallHookProc( HookId,
+                                  Code,
+                                wParam,
+                                lParam,
+                            Hook->Proc,
+                            Hook->Ansi,
+                     &Hook->ModuleName);
+
+   ClientInfo->phkCurrent = SaveHook;
 
    Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
                                            KernelMode,
@@ -344,7 +361,7 @@ co_HOOK_CallHooks(INT HookId, INT Code, WPARAM wParam, LPARAM lParam)
    }
    else
    {
-      IntReleaseHookChain(MsqGetHooks(PsGetCurrentThreadWin32Thread()->MessageQueue), HookId, WinStaObj);
+      IntReleaseHookChain(MsqGetHooks(pti->MessageQueue), HookId, WinStaObj);
       IntReleaseHookChain(GlobalHooks, HookId, WinStaObj);
       ObDereferenceObject(WinStaObj);
    }
@@ -397,9 +414,30 @@ HOOK_DestroyThreadHooks(PETHREAD Thread)
    }
 }
 
+static LRESULT
+FASTCALL
+co_HOOK_CallHookNext(PHOOK Hook, INT Code, WPARAM wParam, LPARAM lParam)
+{
+   if ((Hook->Thread != PsGetCurrentThread()) && (Hook->Thread != NULL))
+   {
+      DPRINT1("CALLING HOOK from another Thread. %d\n",Hook->HookId);
+      return IntCallLowLevelHook(Hook, Code, wParam, lParam);
+   }
+   DPRINT("CALLING HOOK %d\n",Hook->HookId);
+   return co_IntCallHookProc(Hook->HookId,
+                                     Code,
+                                   wParam,
+                                   lParam,
+                               Hook->Proc,
+                               Hook->Ansi,
+                        &Hook->ModuleName);
+}
+
+
 LRESULT
 FASTCALL
 IntCallDebugHook(
+   PHOOK Hook,
    int Code,
    WPARAM wParam,
    LPARAM lParam)
@@ -412,7 +450,7 @@ IntCallDebugHook(
 
    if (lParam)
    {
-      _SEH_TRY
+      _SEH2_TRY
       {
           ProbeForRead((PVOID)lParam,
                        sizeof(DEBUGHOOKINFO),
@@ -421,11 +459,11 @@ IntCallDebugHook(
                   (PVOID)lParam,
                   sizeof(DEBUGHOOKINFO));
       }
-      _SEH_HANDLE
+      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
       {
           BadChk = TRUE;
       }
-      _SEH_END;
+      _SEH2_END;
       if (BadChk)
       {
           DPRINT1("HOOK WH_DEBUG read from lParam ERROR!\n");
@@ -491,7 +529,7 @@ IntCallDebugHook(
 
    if (HooklParam)
    {
-      _SEH_TRY
+      _SEH2_TRY
       {
           ProbeForRead((PVOID)Debug.lParam,
                                       Size,
@@ -500,11 +538,11 @@ IntCallDebugHook(
                 (PVOID)Debug.lParam,
                                Size);
       }
-      _SEH_HANDLE
+      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
       {
           BadChk = TRUE;
       }
-      _SEH_END;
+      _SEH2_END;
       if (BadChk)
       {
           DPRINT1("HOOK WH_DEBUG read from Debug.lParam ERROR!\n");
@@ -514,15 +552,18 @@ IntCallDebugHook(
    }
 
    if (HooklParam) Debug.lParam = (LPARAM)HooklParam;
-   lResult = co_HOOK_CallHooks(WH_DEBUG, Code, wParam, (LPARAM)&Debug);
-   if (HooklParam) ExFreePool(HooklParam);
+   lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Debug);
+   if (HooklParam) ExFreePoolWithTag(HooklParam, TAG_HOOK);
    return lResult;
 }
 
+/*
+   Called from user space via CallNextHook.
+ */
 LRESULT
 FASTCALL
 UserCallNextHookEx(
-   int HookId,
+   PHOOK Hook,
    int Code,
    WPARAM wParam,
    LPARAM lParam,
@@ -532,12 +573,13 @@ UserCallNextHookEx(
   BOOL BadChk = FALSE;
 
 // Handle this one first.
-  if ((HookId == WH_MOUSE) || (HookId == WH_CBT && Code == HCBT_CLICKSKIPPED))
+  if ((Hook->HookId == WH_MOUSE) ||
+      (Hook->HookId == WH_CBT && Code == HCBT_CLICKSKIPPED))
   {
      MOUSEHOOKSTRUCTEX Mouse;
      if (lParam)
      {
-        _SEH_TRY
+        _SEH2_TRY
         {
            ProbeForRead((PVOID)lParam,
                         sizeof(MOUSEHOOKSTRUCTEX),
@@ -546,11 +588,11 @@ UserCallNextHookEx(
                    (PVOID)lParam,
                    sizeof(MOUSEHOOKSTRUCTEX));
         }
-        _SEH_HANDLE
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
            BadChk = TRUE;
         }
-        _SEH_END;
+        _SEH2_END;
         if (BadChk)
         {
             DPRINT1("HOOK WH_MOUSE read from lParam ERROR!\n");
@@ -558,19 +600,19 @@ UserCallNextHookEx(
      }
      if (!BadChk)
      {
-        lResult = co_HOOK_CallHooks(HookId, Code, wParam, (LPARAM)&Mouse);
+        lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Mouse);
      }
      return lResult;
   }
 
-  switch(HookId)
+  switch(Hook->HookId)
   {
       case WH_MOUSE_LL:
       {
          MSLLHOOKSTRUCT Mouse;
          if (lParam)
          {
-            _SEH_TRY
+            _SEH2_TRY
             {
                 ProbeForRead((PVOID)lParam,
                              sizeof(MSLLHOOKSTRUCT),
@@ -579,11 +621,11 @@ UserCallNextHookEx(
                         (PVOID)lParam,
                         sizeof(MSLLHOOKSTRUCT));
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                BadChk = TRUE;
             }
-            _SEH_END;
+            _SEH2_END;
             if (BadChk)
             {
                 DPRINT1("HOOK WH_MOUSE_LL read from lParam ERROR!\n");
@@ -591,7 +633,7 @@ UserCallNextHookEx(
          }
          if (!BadChk)
          {
-            lResult = co_HOOK_CallHooks(HookId, Code, wParam, (LPARAM)&Mouse);
+            lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Mouse);
          }
          break;
       }
@@ -601,7 +643,7 @@ UserCallNextHookEx(
          KBDLLHOOKSTRUCT Keyboard;
          if (lParam)
          {
-            _SEH_TRY
+            _SEH2_TRY
             {
                 ProbeForRead((PVOID)lParam,
                              sizeof(KBDLLHOOKSTRUCT),
@@ -610,11 +652,11 @@ UserCallNextHookEx(
                         (PVOID)lParam,
                         sizeof(KBDLLHOOKSTRUCT));
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                BadChk = TRUE;
             }
-            _SEH_END;
+            _SEH2_END;
             if (BadChk)
             {
                 DPRINT1("HOOK WH_KEYBORD_LL read from lParam ERROR!\n");
@@ -622,7 +664,7 @@ UserCallNextHookEx(
          }
          if (!BadChk)
          {
-            lResult = co_HOOK_CallHooks(HookId, Code, wParam, (LPARAM)&Keyboard);
+            lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Keyboard);
          }
          break;
       }
@@ -634,7 +676,7 @@ UserCallNextHookEx(
          MSG Msg;
          if (lParam)
          {
-            _SEH_TRY
+            _SEH2_TRY
             {
                ProbeForRead((PVOID)lParam,
                                sizeof(MSG),
@@ -643,11 +685,11 @@ UserCallNextHookEx(
                      (PVOID)lParam,
                        sizeof(MSG));
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
               BadChk = TRUE;
             }
-            _SEH_END;
+            _SEH2_END;
             if (BadChk)
             {
                DPRINT1("HOOK WH_XMESSAGEX read from lParam ERROR!\n");
@@ -655,10 +697,10 @@ UserCallNextHookEx(
          }
          if (!BadChk)
          {
-            lResult = co_HOOK_CallHooks(HookId, Code, wParam, (LPARAM)&Msg);
-            if (lParam && (HookId == WH_GETMESSAGE))
+            lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Msg);
+            if (lParam && (Hook->HookId == WH_GETMESSAGE))
             {
-               _SEH_TRY
+               _SEH2_TRY
                {
                   ProbeForWrite((PVOID)lParam,
                                   sizeof(MSG),
@@ -667,11 +709,11 @@ UserCallNextHookEx(
                                          &Msg,
                                   sizeof(MSG));
                }
-               _SEH_HANDLE
+               _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                {
                  BadChk = TRUE;
                }
-               _SEH_END;
+               _SEH2_END;
                if (BadChk)
                {
                   DPRINT1("HOOK WH_GETMESSAGE write to lParam ERROR!\n");
@@ -682,19 +724,21 @@ UserCallNextHookEx(
       }
 
       case WH_CBT:
+         DPRINT1("HOOK WH_CBT!\n");
          switch (Code)
          {
             case HCBT_CREATEWND: // Use Ansi.
-               lResult = co_HOOK_CallHooks(HookId, Code, wParam, lParam);
+               DPRINT1("HOOK HCBT_CREATEWND\n");
+//               lResult = co_HOOK_CallHookNext(Hook, Code, wParam, lParam);
                break;
 
             case HCBT_MOVESIZE:
             {
                RECT rt;
-
+               DPRINT1("HOOK HCBT_MOVESIZE\n");
                if (lParam)
                {
-                  _SEH_TRY
+                  _SEH2_TRY
                   {
                       ProbeForRead((PVOID)lParam,
                                     sizeof(RECT),
@@ -703,11 +747,11 @@ UserCallNextHookEx(
                            (PVOID)lParam,
                             sizeof(RECT));
                   }
-                  _SEH_HANDLE
+                  _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                   {
                      BadChk = TRUE;
                   }
-                  _SEH_END;
+                  _SEH2_END;
                   if (BadChk)
                   {
                       DPRINT1("HOOK HCBT_MOVESIZE read from lParam ERROR!\n");
@@ -715,7 +759,7 @@ UserCallNextHookEx(
                }
                if (!BadChk)
                {
-                   lResult = co_HOOK_CallHooks(HookId, Code, wParam, (LPARAM)&rt);
+                   lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&rt);
                }
                break;
             }
@@ -723,10 +767,10 @@ UserCallNextHookEx(
             case HCBT_ACTIVATE:
             {
                CBTACTIVATESTRUCT CbAs;
-
+               DPRINT1("HOOK HCBT_ACTIVATE\n");
                if (lParam)
                {
-                  _SEH_TRY
+                  _SEH2_TRY
                   {
                       ProbeForRead((PVOID)lParam,
                                    sizeof(CBTACTIVATESTRUCT),
@@ -735,11 +779,11 @@ UserCallNextHookEx(
                              (PVOID)lParam,
                              sizeof(CBTACTIVATESTRUCT));
                   }
-                  _SEH_HANDLE
+                  _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                   {
                      BadChk = TRUE;
                   }
-                  _SEH_END;
+                  _SEH2_END;
                   if (BadChk)
                   {
                       DPRINT1("HOOK HCBT_ACTIVATE read from lParam ERROR!\n");
@@ -747,7 +791,7 @@ UserCallNextHookEx(
                }
                if (!BadChk)
                {
-                   lResult = co_HOOK_CallHooks(HookId, Code, wParam, (LPARAM)&CbAs);
+                   lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&CbAs);
                }
                break;
             }
@@ -755,7 +799,8 @@ UserCallNextHookEx(
                 The rest just use default.
              */
             default:
-               lResult = co_HOOK_CallHooks(HookId, Code, wParam, lParam);
+               DPRINT1("HOOK HCBT_ %d\n",Code);
+               lResult = co_HOOK_CallHookNext(Hook, Code, wParam, lParam);
                break;
          }
          break;
@@ -766,7 +811,7 @@ UserCallNextHookEx(
          EVENTMSG EventMsg;
          if (lParam)
          {
-            _SEH_TRY
+            _SEH2_TRY
             {
                 ProbeForRead((PVOID)lParam,
                              sizeof(EVENTMSG),
@@ -775,11 +820,11 @@ UserCallNextHookEx(
                         (PVOID)lParam,
                         sizeof(EVENTMSG));
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                BadChk = TRUE;
             }
-            _SEH_END;
+            _SEH2_END;
             if (BadChk)
             {
                 DPRINT1("HOOK WH_JOURNAL read from lParam ERROR!\n");
@@ -787,10 +832,10 @@ UserCallNextHookEx(
          }
          if (!BadChk) 
          {               
-            lResult = co_HOOK_CallHooks(HookId, Code, wParam, (LPARAM)(lParam ? &EventMsg : NULL));
+            lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)(lParam ? &EventMsg : NULL));
             if (lParam)
             {
-               _SEH_TRY
+               _SEH2_TRY
                {
                   ProbeForWrite((PVOID)lParam,
                                   sizeof(EVENTMSG),
@@ -799,11 +844,11 @@ UserCallNextHookEx(
                                          &EventMsg,
                                   sizeof(EVENTMSG));
                }
-               _SEH_HANDLE
+               _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                {
                  BadChk = TRUE;
                }
-               _SEH_END;
+               _SEH2_END;
                if (BadChk)
                {
                   DPRINT1("HOOK WH_JOURNAL write to lParam ERROR!\n");
@@ -814,7 +859,7 @@ UserCallNextHookEx(
       }
 
       case WH_DEBUG:
-         lResult = IntCallDebugHook( Code, wParam, lParam);
+         lResult = IntCallDebugHook(Hook, Code, wParam, lParam);
          break;
 /*
     Default the rest like, WH_FOREGROUNDIDLE, WH_KEYBOARD and WH_SHELL.
@@ -822,18 +867,18 @@ UserCallNextHookEx(
       case WH_FOREGROUNDIDLE:
       case WH_KEYBOARD:
       case WH_SHELL:
-         lResult = co_HOOK_CallHooks(HookId, Code, wParam, lParam);      
+         lResult = co_HOOK_CallHookNext(Hook, Code, wParam, lParam);      
          break;
 
       default:
-         DPRINT1("Unsupported HOOK Id -> %d\n",HookId);
+         DPRINT1("Unsupported HOOK Id -> %d\n",Hook->HookId);
          break;
   }
   return lResult; 
 }
 
 LRESULT
-STDCALL
+APIENTRY
 NtUserCallNextHookEx(
    int Code,
    WPARAM wParam,
@@ -841,11 +886,9 @@ NtUserCallNextHookEx(
    BOOL Ansi)
 {
    PHOOK HookObj, NextObj;
-   PW32CLIENTINFO ClientInfo;
+   PCLIENTINFO ClientInfo;
    PWINSTATION_OBJECT WinStaObj;
    NTSTATUS Status;
-   LRESULT lResult;
-   INT HookId;
    DECLARE_RETURN(LRESULT);
 
    DPRINT("Enter NtUserCallNextHookEx\n");
@@ -855,7 +898,6 @@ NtUserCallNextHookEx(
                                            KernelMode,
                                            0,
                                            &WinStaObj);
-
    if (!NT_SUCCESS(Status))
    {
       SetLastNtError(Status);
@@ -866,9 +908,14 @@ NtUserCallNextHookEx(
 
    ClientInfo = GetWin32ClientInfo();
 
-   HookObj = ClientInfo->phkCurrent; // Use this one set from SetWindowHook.
+   if (!ClientInfo) RETURN( 0);
+
+   HookObj = ClientInfo->phkCurrent;
+
+   if (!HookObj) RETURN( 0);
+
+   UserReferenceObject(HookObj);
 
-   HookId = HookObj->HookId;
    Ansi = HookObj->Ansi;
 
    if (NULL != HookObj->Thread && (HookObj->Thread != PsGetCurrentThread()))
@@ -880,19 +927,11 @@ NtUserCallNextHookEx(
    }
    
    NextObj = IntGetNextHook(HookObj);
+   ClientInfo->phkCurrent = NextObj; // Preset next hook from list.
+   UserCallNextHookEx( HookObj, Code, wParam, lParam, Ansi);
    UserDereferenceObject(HookObj);
-   if (NULL != NextObj)
-   {
-      lResult = UserCallNextHookEx( HookId, Code, wParam, lParam, Ansi);
-
-      ClientInfo->phkCurrent = NextObj;
-
-      if (lResult == 0) RETURN( 0);
-      RETURN( (LRESULT)NextObj);
-   }
-   ClientInfo->phkCurrent = NextObj;
 
-   RETURN( 0);
+   RETURN( (LRESULT)NextObj);
 
 CLEANUP:
    DPRINT("Leave NtUserCallNextHookEx, ret=%i\n",_ret_);
@@ -901,7 +940,7 @@ CLEANUP:
 }
 
 HHOOK
-STDCALL
+APIENTRY
 NtUserSetWindowsHookAW(
    int idHook, 
    HOOKPROC lpfn,
@@ -913,7 +952,7 @@ NtUserSetWindowsHookAW(
 }
 
 HHOOK
-STDCALL
+APIENTRY
 NtUserSetWindowsHookEx(
    HINSTANCE Mod,
    PUNICODE_STRING UnsafeModuleName,
@@ -923,7 +962,7 @@ NtUserSetWindowsHookEx(
    BOOL Ansi)
 {
    PWINSTATION_OBJECT WinStaObj;
-   PW32CLIENTINFO ClientInfo;
+   PCLIENTINFO ClientInfo;
    BOOLEAN Global;
    PETHREAD Thread;
    PHOOK Hook;
@@ -935,12 +974,18 @@ NtUserSetWindowsHookEx(
    DPRINT("Enter NtUserSetWindowsHookEx\n");
    UserEnterExclusive();
 
-   if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId || NULL == HookProc)
+   if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId )
    {
       SetLastWin32Error(ERROR_INVALID_PARAMETER);
       RETURN( NULL);
    }
 
+   if (!HookProc)
+   {
+      SetLastWin32Error(ERROR_INVALID_FILTER_PROC);
+      RETURN( NULL);
+   }
+
    ClientInfo = GetWin32ClientInfo();
 
    if (ThreadId)  /* thread-local hook */
@@ -990,7 +1035,7 @@ NtUserSetWindowsHookEx(
       }
       else if (NULL ==  Mod)
       {
-         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD);
          RETURN( NULL);
       }
       else
@@ -1000,15 +1045,10 @@ NtUserSetWindowsHookEx(
       Global = TRUE;
    }
 
-   /* We only (partially) support local WH_CBT hooks and
-    * WH_KEYBOARD_LL, WH_MOUSE_LL and WH_GETMESSAGE hooks for now 
-    */
-   if  (Global ||
+   if ( ( Global && (HookId != WH_KEYBOARD_LL || HookId != WH_MOUSE_LL) ) ||
         WH_DEBUG == HookId ||
         WH_JOURNALPLAYBACK == HookId ||
-        WH_JOURNALRECORD == HookId ||
-        WH_FOREGROUNDIDLE == HookId ||
-        WH_SHELL == HookId)
+        WH_JOURNALRECORD == HookId)
    {
 #if 0 /* Removed to get winEmbed working again */
       UNIMPLEMENTED
@@ -1091,7 +1131,7 @@ NtUserSetWindowsHookEx(
                                 ModuleName.MaximumLength);
       if (! NT_SUCCESS(Status))
       {
-            ExFreePool(Hook->ModuleName.Buffer);
+         ExFreePoolWithTag(Hook->ModuleName.Buffer, TAG_HOOK);
          UserDereferenceObject(Hook);
          IntRemoveHook(Hook, WinStaObj, FALSE);
          if (NULL != Thread)
@@ -1103,16 +1143,24 @@ NtUserSetWindowsHookEx(
          RETURN( NULL);
       }
       Hook->ModuleName.Length = ModuleName.Length;
+      /* make proc relative to the module base */
+      Hook->Proc = (void *)((char *)HookProc - (char *)Mod);
    }
+   else
+     Hook->Proc = HookProc;
 
-   Hook->Proc = HookProc;
    Hook->Ansi = Ansi;
    Handle = Hook->Self;
 
-// Set the client threads next hook based on the hooks type.
-   ClientInfo->phkCurrent    = IntGetNextHook( Hook); 
+// Clear the client threads next hook.
+   ClientInfo->phkCurrent = 0;
    
    UserDereferenceObject(Hook);
+
+   if (NULL != Thread)
+   {
+      ObDereferenceObject(Thread);
+   }
    ObDereferenceObject(WinStaObj);
 
    RETURN( Handle);
@@ -1125,7 +1173,7 @@ CLEANUP:
 
 
 BOOL
-STDCALL
+APIENTRY
 NtUserUnhookWindowsHookEx(
    HHOOK Hook)
 {