- 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 563875f..d0ff498 100644 (file)
@@ -1,27 +1,8 @@
 /*
- *  ReactOS W32 Subsystem
- *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/* $Id$
- *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * PURPOSE:          Window hooks
- * FILE:             subsys/win32k/ntuser/hook.c
+ * FILE:             subsystem/win32/win32k/ntuser/hook.c
  * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
  * REVISION HISTORY:
  *       06-06-2001  CSH  Created
 #define NDEBUG
 #include <debug.h>
 
-#define HOOKID_TO_INDEX(HookId) (HookId - WH_MINHOOK)
-#define HOOKID_TO_FLAG(HookId) (1 << ((HookId) + 1))
-
 static PHOOKTABLE GlobalHooks;
 
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+
 /* create a new hook table */
 static PHOOKTABLE
 IntAllocHookTable(void)
@@ -90,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)
@@ -108,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);
       }
    }
 
@@ -122,11 +104,14 @@ IntAddHook(PETHREAD Thread, int HookId, BOOLEAN Global, PWINSTATION_OBJECT WinSt
    Hook->Thread = Thread;
    Hook->HookId = HookId;
 
-   W32Thread = ((PW32THREAD)Thread->Tcb.Win32Thread);
-   ASSERT(W32Thread != NULL);
-   W32Thread->Hooks |= HOOKID_TO_FLAG(HookId);
-   if (W32Thread->ThreadInfo != NULL)
-       W32Thread->ThreadInfo->Hooks = W32Thread->Hooks;
+   if (Thread)
+   {
+      W32Thread = ((PTHREADINFO)Thread->Tcb.Win32Thread);
+      ASSERT(W32Thread != NULL);
+      W32Thread->Hooks |= HOOKID_TO_FLAG(HookId);
+      if (W32Thread->ThreadInfo != NULL)
+          W32Thread->ThreadInfo->Hooks = W32Thread->Hooks;
+   }
 
    RtlInitUnicodeString(&Hook->ModuleName, NULL);
 
@@ -145,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 */
@@ -176,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);
@@ -222,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);
@@ -231,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)
@@ -281,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;
@@ -306,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)))
@@ -326,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())
+   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)]++;
@@ -345,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,
@@ -359,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);
    }
@@ -409,20 +411,482 @@ HOOK_DestroyThreadHooks(PETHREAD Thread)
                break;
          }
       }
+   }
+}
 
-      ObDereferenceObject(WinStaObj);
+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
-STDCALL
-NtUserCallNextHookEx(
-   HHOOK Hook,
+FASTCALL
+IntCallDebugHook(
+   PHOOK Hook,
    int Code,
    WPARAM wParam,
    LPARAM lParam)
+{
+   LRESULT lResult = 0;
+   ULONG Size;
+   DEBUGHOOKINFO Debug;
+   PVOID HooklParam = NULL;
+   BOOL BadChk = FALSE;
+
+   if (lParam)
+   {
+      _SEH2_TRY
+      {
+          ProbeForRead((PVOID)lParam,
+                       sizeof(DEBUGHOOKINFO),
+                                   1);
+          RtlCopyMemory( &Debug,
+                  (PVOID)lParam,
+                  sizeof(DEBUGHOOKINFO));
+      }
+      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+      {
+          BadChk = TRUE;
+      }
+      _SEH2_END;
+      if (BadChk)
+      {
+          DPRINT1("HOOK WH_DEBUG read from lParam ERROR!\n");
+          return lResult;
+      }
+   }
+   else
+      return lResult; // Need lParam!
+
+   switch (wParam)
+   {
+      case WH_CBT:
+      {
+         switch (Debug.code)
+         {
+            case HCBT_CLICKSKIPPED:
+               Size = sizeof(MOUSEHOOKSTRUCTEX);
+               break;
+            case HCBT_MOVESIZE:
+               Size = sizeof(RECT);
+               break;
+            case HCBT_ACTIVATE:
+               Size = sizeof(CBTACTIVATESTRUCT); 
+               break;
+            case HCBT_CREATEWND: // Handle Ansi?
+               Size = sizeof(CBT_CREATEWND);
+               // What shall we do? Size += sizeof(CREATESTRUCTEX);
+               break;
+            default:
+               Size = sizeof(LPARAM);
+         }
+      }
+      break;
+
+      case WH_MOUSE_LL:
+         Size = sizeof(MSLLHOOKSTRUCT);
+      break;
+
+      case WH_KEYBOARD_LL:
+         Size = sizeof(KBDLLHOOKSTRUCT);
+      break;
+
+      case WH_MSGFILTER:
+      case WH_SYSMSGFILTER:
+      case WH_GETMESSAGE:
+         Size = sizeof(MSG);
+      break;
+
+      case WH_JOURNALPLAYBACK:
+      case WH_JOURNALRECORD:
+         Size = sizeof(EVENTMSG);
+      break;
+
+      case WH_FOREGROUNDIDLE:
+      case WH_KEYBOARD:
+      case WH_SHELL:
+      default:
+         Size = sizeof(LPARAM);
+   }
+
+   if (Size > sizeof(LPARAM))
+      HooklParam = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_HOOK);
+
+   if (HooklParam)
+   {
+      _SEH2_TRY
+      {
+          ProbeForRead((PVOID)Debug.lParam,
+                                      Size,
+                                         1);
+          RtlCopyMemory( HooklParam,
+                (PVOID)Debug.lParam,
+                               Size);
+      }
+      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+      {
+          BadChk = TRUE;
+      }
+      _SEH2_END;
+      if (BadChk)
+      {
+          DPRINT1("HOOK WH_DEBUG read from Debug.lParam ERROR!\n");
+          ExFreePool(HooklParam);
+          return lResult;
+      }
+   }
+
+   if (HooklParam) Debug.lParam = (LPARAM)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(
+   PHOOK Hook,
+   int Code,
+   WPARAM wParam,
+   LPARAM lParam,
+   BOOL Ansi)
+{
+  LRESULT lResult = 0;
+  BOOL BadChk = FALSE;
+
+// Handle this one first.
+  if ((Hook->HookId == WH_MOUSE) ||
+      (Hook->HookId == WH_CBT && Code == HCBT_CLICKSKIPPED))
+  {
+     MOUSEHOOKSTRUCTEX Mouse;
+     if (lParam)
+     {
+        _SEH2_TRY
+        {
+           ProbeForRead((PVOID)lParam,
+                        sizeof(MOUSEHOOKSTRUCTEX),
+                                    1);
+           RtlCopyMemory( &Mouse,
+                   (PVOID)lParam,
+                   sizeof(MOUSEHOOKSTRUCTEX));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+           BadChk = TRUE;
+        }
+        _SEH2_END;
+        if (BadChk)
+        {
+            DPRINT1("HOOK WH_MOUSE read from lParam ERROR!\n");
+        }
+     }
+     if (!BadChk)
+     {
+        lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Mouse);
+     }
+     return lResult;
+  }
+
+  switch(Hook->HookId)
+  {
+      case WH_MOUSE_LL:
+      {
+         MSLLHOOKSTRUCT Mouse;
+         if (lParam)
+         {
+            _SEH2_TRY
+            {
+                ProbeForRead((PVOID)lParam,
+                             sizeof(MSLLHOOKSTRUCT),
+                                         1);
+                RtlCopyMemory( &Mouse,
+                        (PVOID)lParam,
+                        sizeof(MSLLHOOKSTRUCT));
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+               BadChk = TRUE;
+            }
+            _SEH2_END;
+            if (BadChk)
+            {
+                DPRINT1("HOOK WH_MOUSE_LL read from lParam ERROR!\n");
+            }
+         }
+         if (!BadChk)
+         {
+            lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Mouse);
+         }
+         break;
+      }
+
+      case WH_KEYBOARD_LL:
+      {
+         KBDLLHOOKSTRUCT Keyboard;
+         if (lParam)
+         {
+            _SEH2_TRY
+            {
+                ProbeForRead((PVOID)lParam,
+                             sizeof(KBDLLHOOKSTRUCT),
+                                         1);
+                RtlCopyMemory( &Keyboard,
+                        (PVOID)lParam,
+                        sizeof(KBDLLHOOKSTRUCT));
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+               BadChk = TRUE;
+            }
+            _SEH2_END;
+            if (BadChk)
+            {
+                DPRINT1("HOOK WH_KEYBORD_LL read from lParam ERROR!\n");
+            }
+         }
+         if (!BadChk)
+         {
+            lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Keyboard);
+         }
+         break;
+      }
+
+      case WH_MSGFILTER:
+      case WH_SYSMSGFILTER:
+      case WH_GETMESSAGE:
+      {
+         MSG Msg;
+         if (lParam)
+         {
+            _SEH2_TRY
+            {
+               ProbeForRead((PVOID)lParam,
+                               sizeof(MSG),
+                                         1);
+               RtlCopyMemory( &Msg,
+                     (PVOID)lParam,
+                       sizeof(MSG));
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+              BadChk = TRUE;
+            }
+            _SEH2_END;
+            if (BadChk)
+            {
+               DPRINT1("HOOK WH_XMESSAGEX read from lParam ERROR!\n");
+            }
+         }
+         if (!BadChk)
+         {
+            lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Msg);
+            if (lParam && (Hook->HookId == WH_GETMESSAGE))
+            {
+               _SEH2_TRY
+               {
+                  ProbeForWrite((PVOID)lParam,
+                                  sizeof(MSG),
+                                            1);
+                  RtlCopyMemory((PVOID)lParam,
+                                         &Msg,
+                                  sizeof(MSG));
+               }
+               _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+               {
+                 BadChk = TRUE;
+               }
+               _SEH2_END;
+               if (BadChk)
+               {
+                  DPRINT1("HOOK WH_GETMESSAGE write to lParam ERROR!\n");
+               }
+            }
+         }
+         break;
+      }
+
+      case WH_CBT:
+         DPRINT1("HOOK WH_CBT!\n");
+         switch (Code)
+         {
+            case HCBT_CREATEWND: // Use Ansi.
+               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)
+               {
+                  _SEH2_TRY
+                  {
+                      ProbeForRead((PVOID)lParam,
+                                    sizeof(RECT),
+                                              1);
+                      RtlCopyMemory( &rt,
+                           (PVOID)lParam,
+                            sizeof(RECT));
+                  }
+                  _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                  {
+                     BadChk = TRUE;
+                  }
+                  _SEH2_END;
+                  if (BadChk)
+                  {
+                      DPRINT1("HOOK HCBT_MOVESIZE read from lParam ERROR!\n");
+                   }
+               }
+               if (!BadChk)
+               {
+                   lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&rt);
+               }
+               break;
+            }
+
+            case HCBT_ACTIVATE:
+            {
+               CBTACTIVATESTRUCT CbAs;
+               DPRINT1("HOOK HCBT_ACTIVATE\n");
+               if (lParam)
+               {
+                  _SEH2_TRY
+                  {
+                      ProbeForRead((PVOID)lParam,
+                                   sizeof(CBTACTIVATESTRUCT),
+                                              1);
+                      RtlCopyMemory( &CbAs,
+                             (PVOID)lParam,
+                             sizeof(CBTACTIVATESTRUCT));
+                  }
+                  _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                  {
+                     BadChk = TRUE;
+                  }
+                  _SEH2_END;
+                  if (BadChk)
+                  {
+                      DPRINT1("HOOK HCBT_ACTIVATE read from lParam ERROR!\n");
+                   }
+               }
+               if (!BadChk)
+               {
+                   lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&CbAs);
+               }
+               break;
+            }
+            /*
+                The rest just use default.
+             */
+            default:
+               DPRINT1("HOOK HCBT_ %d\n",Code);
+               lResult = co_HOOK_CallHookNext(Hook, Code, wParam, lParam);
+               break;
+         }
+         break;
+
+      case WH_JOURNALPLAYBACK:
+      case WH_JOURNALRECORD:
+      {
+         EVENTMSG EventMsg;
+         if (lParam)
+         {
+            _SEH2_TRY
+            {
+                ProbeForRead((PVOID)lParam,
+                             sizeof(EVENTMSG),
+                                         1);
+                RtlCopyMemory( &EventMsg,
+                        (PVOID)lParam,
+                        sizeof(EVENTMSG));
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+               BadChk = TRUE;
+            }
+            _SEH2_END;
+            if (BadChk)
+            {
+                DPRINT1("HOOK WH_JOURNAL read from lParam ERROR!\n");
+            }
+         }
+         if (!BadChk) 
+         {               
+            lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)(lParam ? &EventMsg : NULL));
+            if (lParam)
+            {
+               _SEH2_TRY
+               {
+                  ProbeForWrite((PVOID)lParam,
+                                  sizeof(EVENTMSG),
+                                            1);
+                  RtlCopyMemory((PVOID)lParam,
+                                         &EventMsg,
+                                  sizeof(EVENTMSG));
+               }
+               _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+               {
+                 BadChk = TRUE;
+               }
+               _SEH2_END;
+               if (BadChk)
+               {
+                  DPRINT1("HOOK WH_JOURNAL write to lParam ERROR!\n");
+               }
+            }
+         }
+         break;
+      }
+
+      case WH_DEBUG:
+         lResult = IntCallDebugHook(Hook, Code, wParam, lParam);
+         break;
+/*
+    Default the rest like, WH_FOREGROUNDIDLE, WH_KEYBOARD and WH_SHELL.
+ */
+      case WH_FOREGROUNDIDLE:
+      case WH_KEYBOARD:
+      case WH_SHELL:
+         lResult = co_HOOK_CallHookNext(Hook, Code, wParam, lParam);      
+         break;
+
+      default:
+         DPRINT1("Unsupported HOOK Id -> %d\n",Hook->HookId);
+         break;
+  }
+  return lResult; 
+}
+
+LRESULT
+APIENTRY
+NtUserCallNextHookEx(
+   int Code,
+   WPARAM wParam,
+   LPARAM lParam,
+   BOOL Ansi)
 {
    PHOOK HookObj, NextObj;
+   PCLIENTINFO ClientInfo;
    PWINSTATION_OBJECT WinStaObj;
    NTSTATUS Status;
    DECLARE_RETURN(LRESULT);
@@ -434,30 +898,25 @@ NtUserCallNextHookEx(
                                            KernelMode,
                                            0,
                                            &WinStaObj);
-
-   if (! NT_SUCCESS(Status))
+   if (!NT_SUCCESS(Status))
    {
       SetLastNtError(Status);
-      RETURN( FALSE);
+      RETURN( 0);
    }
 
-   //Status = UserReferenceObjectByHandle(gHandleTable, Hook,
-   //                             otHookProc, (PVOID *) &HookObj);
    ObDereferenceObject(WinStaObj);
 
-   //  if (! NT_SUCCESS(Status))
-   //    {
-   //      DPRINT1("Invalid handle passed to NtUserCallNextHookEx\n");
-   //      SetLastNtError(Status);
-   //      RETURN( 0);
-   //    }
+   ClientInfo = GetWin32ClientInfo();
 
-   if (!(HookObj = IntGetHookObject(Hook)))
-   {
-      RETURN(0);
-   }
+   if (!ClientInfo) RETURN( 0);
 
-   ASSERT(Hook == HookObj->Self);
+   HookObj = ClientInfo->phkCurrent;
+
+   if (!HookObj) RETURN( 0);
+
+   UserReferenceObject(HookObj);
+
+   Ansi = HookObj->Ansi;
 
    if (NULL != HookObj->Thread && (HookObj->Thread != PsGetCurrentThread()))
    {
@@ -466,18 +925,13 @@ NtUserCallNextHookEx(
       SetLastWin32Error(ERROR_INVALID_HANDLE);
       RETURN( 0);
    }
-
+   
    NextObj = IntGetNextHook(HookObj);
+   ClientInfo->phkCurrent = NextObj; // Preset next hook from list.
+   UserCallNextHookEx( HookObj, Code, wParam, lParam, Ansi);
    UserDereferenceObject(HookObj);
-   if (NULL != NextObj)
-   {
-      DPRINT1("Calling next hook not implemented\n");
-      UNIMPLEMENTED
-      SetLastWin32Error(ERROR_NOT_SUPPORTED);
-      RETURN( 0);
-   }
 
-   RETURN( 0);
+   RETURN( (LRESULT)NextObj);
 
 CLEANUP:
    DPRINT("Leave NtUserCallNextHookEx, ret=%i\n",_ret_);
@@ -485,20 +939,20 @@ CLEANUP:
    END_CLEANUP;
 }
 
-DWORD
-STDCALL
+HHOOK
+APIENTRY
 NtUserSetWindowsHookAW(
-   DWORD Unknown0,
-   DWORD Unknown1,
-   DWORD Unknown2)
+   int idHook, 
+   HOOKPROC lpfn,
+   BOOL Ansi)
 {
-   UNIMPLEMENTED
-
-   return 0;
+   UNICODE_STRING USModuleName;
+   RtlInitUnicodeString(&USModuleName, NULL);
+   return NtUserSetWindowsHookEx(NULL, &USModuleName, 0, idHook, lpfn, Ansi);
 }
 
 HHOOK
-STDCALL
+APIENTRY
 NtUserSetWindowsHookEx(
    HINSTANCE Mod,
    PUNICODE_STRING UnsafeModuleName,
@@ -508,6 +962,7 @@ NtUserSetWindowsHookEx(
    BOOL Ansi)
 {
    PWINSTATION_OBJECT WinStaObj;
+   PCLIENTINFO ClientInfo;
    BOOLEAN Global;
    PETHREAD Thread;
    PHOOK Hook;
@@ -519,12 +974,20 @@ 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 */
    {
       if (HookId == WH_JOURNALRECORD ||
@@ -572,7 +1035,7 @@ NtUserSetWindowsHookEx(
       }
       else if (NULL ==  Mod)
       {
-         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD);
          RETURN( NULL);
       }
       else
@@ -582,10 +1045,10 @@ NtUserSetWindowsHookEx(
       Global = TRUE;
    }
 
-   /* We only (partially) support local WH_CBT hooks and
-    * WH_KEYBOARD_LL/WH_MOUSE_LL hooks for now */
-   if ((WH_CBT != HookId || Global)
-         && WH_KEYBOARD_LL != HookId && WH_MOUSE_LL != HookId)
+   if ( ( Global && (HookId != WH_KEYBOARD_LL || HookId != WH_MOUSE_LL) ) ||
+        WH_DEBUG == HookId ||
+        WH_JOURNALPLAYBACK == HookId ||
+        WH_JOURNALRECORD == HookId)
    {
 #if 0 /* Removed to get winEmbed working again */
       UNIMPLEMENTED
@@ -668,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)
@@ -680,13 +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;
 
+// Clear the client threads next hook.
+   ClientInfo->phkCurrent = 0;
+   
    UserDereferenceObject(Hook);
+
+   if (NULL != Thread)
+   {
+      ObDereferenceObject(Thread);
+   }
    ObDereferenceObject(WinStaObj);
 
    RETURN( Handle);
@@ -697,25 +1171,9 @@ CLEANUP:
    END_CLEANUP;
 }
 
-DWORD
-STDCALL
-NtUserSetWinEventHook(
-   UINT eventMin,
-   UINT eventMax,
-   HMODULE hmodWinEventProc,
-   PUNICODE_STRING puString,
-   WINEVENTPROC lpfnWinEventProc,
-   DWORD idProcess,
-   DWORD idThread,
-   UINT dwflags)
-{
-   UNIMPLEMENTED
-
-   return 0;
-}
 
 BOOL
-STDCALL
+APIENTRY
 NtUserUnhookWindowsHookEx(
    HHOOK Hook)
 {
@@ -761,15 +1219,5 @@ CLEANUP:
    UserLeave();
    END_CLEANUP;
 }
-
-DWORD
-STDCALL
-NtUserUnhookWinEvent(
-   DWORD Unknown0)
-{
-   UNIMPLEMENTED
-
-   return 0;
-}
-
 /* EOF */