xref: /reactos/win32ss/user/user32/windows/hook.c (revision ede7a20a)
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /*
20  *
21  * PROJECT:         ReactOS user32.dll
22  * FILE:            win32ss/user/user32/windows/hook.c
23  * PURPOSE:         Hooks
24  * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
25  * UPDATE HISTORY:
26  *      09-05-2001  CSH  Created
27  */
28 
29 #include <user32.h>
30 
31 WINE_DEFAULT_DEBUG_CHANNEL(user32);
32 
33 typedef struct _NOTIFYEVENT
34 {
35    DWORD event;
36    LONG  idObject;
37    LONG  idChild;
38    DWORD flags;
39 } NOTIFYEVENT, *PNOTIFYEVENT;
40 
41 /* PRIVATE FUNCTIONS *********************************************************/
42 
43 static
44 DWORD
45 FASTCALL
46 GetMaskFromEvent(DWORD Event)
47 {
48   DWORD Ret = 0;
49 
50   if ( Event > EVENT_OBJECT_STATECHANGE )
51   {
52     if ( Event == EVENT_OBJECT_LOCATIONCHANGE ) return SRV_EVENT_LOCATIONCHANGE;
53     if ( Event == EVENT_OBJECT_NAMECHANGE )     return SRV_EVENT_NAMECHANGE;
54     if ( Event == EVENT_OBJECT_VALUECHANGE )    return SRV_EVENT_VALUECHANGE;
55     return SRV_EVENT_CREATE;
56   }
57 
58   if ( Event == EVENT_OBJECT_STATECHANGE ) return SRV_EVENT_STATECHANGE;
59 
60   Ret = SRV_EVENT_RUNNING;
61 
62   if ( Event < EVENT_SYSTEM_MENUSTART )    return SRV_EVENT_CREATE;
63 
64   if ( Event <= EVENT_SYSTEM_MENUPOPUPEND )
65   {
66     Ret = SRV_EVENT_MENU;
67   }
68   else
69   {
70     if ( Event <= EVENT_CONSOLE_CARET-1 )         return SRV_EVENT_CREATE;
71     if ( Event <= EVENT_CONSOLE_END_APPLICATION ) return SRV_EVENT_END_APPLICATION;
72     if ( Event != EVENT_OBJECT_FOCUS )            return SRV_EVENT_CREATE;
73   }
74   return Ret;
75 }
76 
77 static
78 HHOOK
79 FASTCALL
80 IntSetWindowsHook(
81     int idHook,
82     HOOKPROC lpfn,
83     HINSTANCE hMod,
84     DWORD dwThreadId,
85     BOOL bAnsi)
86 {
87   WCHAR ModuleName[MAX_PATH];
88   UNICODE_STRING USModuleName;
89 
90   if (NULL != hMod)
91     {
92       if (0 == GetModuleFileNameW(hMod, ModuleName, MAX_PATH))
93         {
94           return NULL;
95         }
96       RtlInitUnicodeString(&USModuleName, ModuleName);
97     }
98   else
99     {
100       RtlInitUnicodeString(&USModuleName, NULL);
101     }
102 
103   return NtUserSetWindowsHookEx(hMod, &USModuleName, dwThreadId, idHook, lpfn, bAnsi);
104 }
105 
106 /*
107    Since ReactOS uses User32 as the main message source this was needed.
108    Base on the funny rules from the wine tests it left it with this option.
109    8^(
110  */
111 VOID
112 FASTCALL
113 IntNotifyWinEvent(
114                  DWORD event,
115                  HWND  hwnd,
116                  LONG  idObject,
117                  LONG  idChild,
118                  DWORD flags
119                  )
120 {
121   NOTIFYEVENT ne;
122   ne.event    = event;
123   ne.idObject = idObject;
124   ne.idChild  = idChild;
125   ne.flags    = flags;
126   if (gpsi->dwInstalledEventHooks & GetMaskFromEvent(event))
127   NtUserxNotifyWinEvent(hwnd, &ne);
128 }
129 
130 /* FUNCTIONS *****************************************************************/
131 
132 #if 0
133 BOOL
134 WINAPI
135 CallMsgFilter(
136   LPMSG lpMsg,
137   int nCode)
138 {
139   UNIMPLEMENTED;
140   return FALSE;
141 }
142 #endif
143 
144 /*
145  * @implemented
146  */
147 BOOL
148 WINAPI
149 CallMsgFilterA(
150   LPMSG lpMsg,
151   int nCode)
152 {
153   MSG Msg;
154   if ( NtCurrentTeb()->Win32ThreadInfo &&
155       (ISITHOOKED(WH_MSGFILTER) || ISITHOOKED(WH_SYSMSGFILTER)) )
156   {
157      if ( lpMsg->message & ~WM_MAXIMUM )
158      {
159         SetLastError(ERROR_INVALID_PARAMETER);
160         return FALSE;
161      }
162      RtlCopyMemory(&Msg, lpMsg, sizeof(MSG));
163      return NtUserCallMsgFilter( &Msg, nCode);
164   }
165   return FALSE;
166 }
167 
168 
169 /*
170  * @implemented
171  */
172 BOOL
173 WINAPI
174 CallMsgFilterW(
175   LPMSG lpMsg,
176   int nCode)
177 {
178   MSG Msg;
179   if ( NtCurrentTeb()->Win32ThreadInfo &&
180       (ISITHOOKED(WH_MSGFILTER) || ISITHOOKED(WH_SYSMSGFILTER)) )
181   {
182      if ( lpMsg->message & ~WM_MAXIMUM )
183      {
184         SetLastError(ERROR_INVALID_PARAMETER);
185         return FALSE;
186      }
187      RtlCopyMemory(&Msg, lpMsg, sizeof(MSG));
188      return  NtUserCallMsgFilter( &Msg, nCode);
189   }
190   return FALSE;
191 }
192 
193 
194 /*
195  * @implemented
196  */
197 LRESULT
198 WINAPI
199 CallNextHookEx(
200   HHOOK Hook,  // Windows NT/XP/2003: Ignored.
201   int Code,
202   WPARAM wParam,
203   LPARAM lParam)
204 {
205   PCLIENTINFO ClientInfo;
206   DWORD Flags, Save;
207   PHOOK pHook, phkNext;
208   LRESULT lResult = 0;
209 
210   ClientInfo = GetWin32ClientInfo();
211 
212   if (!ClientInfo->phkCurrent) return 0;
213 
214   pHook = DesktopPtrToUser(ClientInfo->phkCurrent);
215 
216   if (!pHook->phkNext) return 0; // Nothing to do....
217 
218   phkNext = DesktopPtrToUser(pHook->phkNext);
219 
220   if ( phkNext->HookId == WH_CALLWNDPROC ||
221        phkNext->HookId == WH_CALLWNDPROCRET)
222   {
223      Save = ClientInfo->dwHookData;
224      Flags = ClientInfo->CI_flags & CI_CURTHPRHOOK;
225 // wParam: If the message was sent by the current thread/process, it is
226 // nonzero; otherwise, it is zero.
227      if (wParam) ClientInfo->CI_flags |= CI_CURTHPRHOOK;
228      else        ClientInfo->CI_flags &= ~CI_CURTHPRHOOK;
229 
230      if (phkNext->HookId == WH_CALLWNDPROC)
231      {
232         PCWPSTRUCT pCWP = (PCWPSTRUCT)lParam;
233 
234         NtUserMessageCall( pCWP->hwnd,
235                            pCWP->message,
236                            pCWP->wParam,
237                            pCWP->lParam,
238                           (ULONG_PTR)&lResult,
239                            FNID_CALLWNDPROC,
240                            phkNext->Ansi);
241      }
242      else
243      {
244         PCWPRETSTRUCT pCWPR = (PCWPRETSTRUCT)lParam;
245 
246         ClientInfo->dwHookData = pCWPR->lResult;
247 
248         NtUserMessageCall( pCWPR->hwnd,
249                            pCWPR->message,
250                            pCWPR->wParam,
251                            pCWPR->lParam,
252                           (ULONG_PTR)&lResult,
253                            FNID_CALLWNDPROCRET,
254                            phkNext->Ansi);
255      }
256      ClientInfo->CI_flags ^= ((ClientInfo->CI_flags ^ Flags) & CI_CURTHPRHOOK);
257      ClientInfo->dwHookData = Save;
258   }
259   else
260      lResult = NtUserCallNextHookEx(Code, wParam, lParam, pHook->Ansi);
261 
262   return lResult;
263 }
264 
265 
266 /*
267  * @implemented
268  */
269 HHOOK
270 WINAPI
271 SetWindowsHookW(int idHook, HOOKPROC lpfn)
272 {
273   DWORD ThreadId = PtrToUint(NtCurrentTeb()->ClientId.UniqueThread);
274   return IntSetWindowsHook(idHook, lpfn, NULL, ThreadId, FALSE);
275 //  return NtUserSetWindowsHookAW(idHook, lpfn, FALSE);
276 }
277 
278 /*
279  * @implemented
280  */
281 HHOOK
282 WINAPI
283 SetWindowsHookA(int idHook, HOOKPROC lpfn)
284 {
285   DWORD ThreadId = PtrToUint(NtCurrentTeb()->ClientId.UniqueThread);
286   return IntSetWindowsHook(idHook, lpfn, NULL, ThreadId, TRUE);
287 //  return NtUserSetWindowsHookAW(idHook, lpfn, TRUE);
288 }
289 
290 /*
291  * @unimplemented
292  */
293 BOOL
294 WINAPI
295 DeregisterShellHookWindow(HWND hWnd)
296 {
297   return NtUserxDeregisterShellHookWindow(hWnd);
298 }
299 
300 /*
301  * @unimplemented
302  */
303 BOOL
304 WINAPI
305 RegisterShellHookWindow(HWND hWnd)
306 {
307   return NtUserxRegisterShellHookWindow(hWnd);
308 }
309 
310 /*
311  * @implemented
312  */
313 BOOL
314 WINAPI
315 UnhookWindowsHook ( int nCode, HOOKPROC pfnFilterProc )
316 {
317   return NtUserxUnhookWindowsHook(nCode, pfnFilterProc);
318 }
319 
320 /*
321  * @implemented
322  */
323 VOID
324 WINAPI
325 NotifyWinEvent(
326 	       DWORD event,
327 	       HWND  hwnd,
328 	       LONG  idObject,
329 	       LONG  idChild
330 	       )
331 {
332 // "Servers call NotifyWinEvent to announce the event to the system after the
333 // event has occurred; they must never notify the system of an event before
334 // the event has occurred." msdn on NotifyWinEvent.
335   if (gpsi->dwInstalledEventHooks & GetMaskFromEvent(event)) // Check to see.
336       NtUserNotifyWinEvent(event, hwnd, idObject, idChild);
337 }
338 
339 /*
340  * @implemented
341  */
342 HWINEVENTHOOK
343 WINAPI
344 SetWinEventHook(
345 		UINT         eventMin,
346 		UINT         eventMax,
347 		HMODULE      hmodWinEventProc,
348 		WINEVENTPROC pfnWinEventProc,
349 		DWORD        idProcess,
350 		DWORD        idThread,
351 		UINT         dwFlags
352 		)
353 {
354   WCHAR ModuleName[MAX_PATH];
355   UNICODE_STRING USModuleName;
356   PUNICODE_STRING pusmodName;
357 
358   RtlInitUnicodeString(&USModuleName, NULL);
359 
360   if ((hmodWinEventProc != NULL) && (dwFlags & WINEVENT_INCONTEXT))
361   {
362       if (0 == GetModuleFileNameW(hmodWinEventProc, ModuleName, MAX_PATH))
363       {
364           return NULL;
365       }
366       RtlInitUnicodeString(&USModuleName, ModuleName);
367       pusmodName = &USModuleName;
368   }
369   else
370   {
371       pusmodName = NULL;
372   }
373 
374   return NtUserSetWinEventHook(eventMin,
375                                eventMax,
376                        hmodWinEventProc,
377                              pusmodName,
378                         pfnWinEventProc,
379                               idProcess,
380                                idThread,
381                                 dwFlags);
382 }
383 
384 /*
385  * @implemented
386  */
387 BOOL
388 WINAPI
389 IsWinEventHookInstalled(
390     DWORD event)
391 {
392   if ((PTHREADINFO)NtCurrentTeb()->Win32ThreadInfo)
393   {
394      return (gpsi->dwInstalledEventHooks & GetMaskFromEvent(event)) != 0;
395   }
396   return FALSE;
397 }
398 
399 /*
400  * @implemented
401  */
402 HHOOK
403 WINAPI
404 SetWindowsHookExA(
405     int idHook,
406     HOOKPROC lpfn,
407     HINSTANCE hMod,
408     DWORD dwThreadId)
409 {
410   return IntSetWindowsHook(idHook, lpfn, hMod, dwThreadId, TRUE);
411 }
412 
413 
414 /*
415  * @implemented
416  */
417 HHOOK
418 WINAPI
419 SetWindowsHookExW(
420     int idHook,
421     HOOKPROC lpfn,
422     HINSTANCE hMod,
423     DWORD dwThreadId)
424 {
425   return IntSetWindowsHook(idHook, lpfn, hMod, dwThreadId, FALSE);
426 }
427 
428 static
429 BOOL
430 ClientLoadLibrary(
431     PUNICODE_STRING pstrLibName,
432     PUNICODE_STRING pstrInitFunc,
433     BOOL bUnload,
434     BOOL bApiHook)
435 {
436     HINSTANCE hLibrary;
437     PVOID pInitFunction;
438     NTSTATUS Status;
439     ANSI_STRING InitFuncName;
440     BOOL bResult = FALSE;
441 
442     TRACE("ClientLoadLibrary: pid: %d, strLibraryName: %S, "
443           "strInitFuncName: %S, bUnload: %d, bApiHook:%d\n",
444           GetCurrentProcessId(),
445           pstrLibName->Buffer,
446           pstrInitFunc->Buffer,
447           bUnload,
448           bApiHook);
449 
450     /* Check if we have to load the module */
451     if (bUnload == FALSE)
452     {
453         ASSERT(pstrLibName->Buffer != NULL);
454 
455         /* Load it */
456         hLibrary = LoadLibrary(pstrLibName->Buffer);
457         if (hLibrary == 0)
458         {
459             return FALSE;
460         }
461 
462         if (!bApiHook)
463         {
464             /* There is nothing more to do for a global hook*/
465             return TRUE;
466         }
467 
468         /* Initialize the user api hook */
469         ASSERT(pstrInitFunc->Buffer);
470         Status = RtlUnicodeStringToAnsiString(&InitFuncName,
471                                               pstrInitFunc,
472                                               TRUE);
473         if (!NT_SUCCESS(Status))
474         {
475             FreeLibrary(hLibrary);
476             return FALSE;
477         }
478 
479         /* Get the address of the initialization routine */
480         pInitFunction = GetProcAddress(hLibrary, InitFuncName.Buffer);
481         if (pInitFunction)
482         {
483             /* Call the initialization routine */
484             bResult = InitUserApiHook(hLibrary, (USERAPIHOOKPROC)pInitFunction);
485         }
486 
487         RtlFreeAnsiString(&InitFuncName);
488 
489         /* In case of error unload the library */
490         if (bResult == FALSE)
491         {
492             FreeLibrary(hLibrary);
493         }
494     }
495     else
496     {
497         /* Cleanup user api hook before unloading */
498         if (bApiHook)
499         {
500             hLibrary = ghmodUserApiHook;
501             bResult = ClearUserApiHook(ghmodUserApiHook);
502 
503             /* Check if we can we unload it now */
504             if (!bResult)
505             {
506                 /* Return success because we are going to free
507                    the library in EndUserApiHook*/
508                 return TRUE;
509             }
510         }
511         else
512         {
513             /* Get the library handle from the name */
514             hLibrary = GetModuleHandle(pstrLibName->Buffer);
515             if (hLibrary == NULL)
516             {
517                 return FALSE;
518             }
519         }
520 
521         bResult = FreeLibrary(hLibrary);
522     }
523 
524     return bResult;
525 }
526 
527 NTSTATUS WINAPI
528 User32CallClientLoadLibraryFromKernel(PVOID Arguments, ULONG ArgumentLength)
529 {
530     BOOL bResult;
531     PCLIENT_LOAD_LIBRARY_ARGUMENTS Argument;
532 
533     /* Retireve the callback parameters */
534     Argument = (PCLIENT_LOAD_LIBRARY_ARGUMENTS)Arguments;
535     if(Argument->strLibraryName.Buffer != NULL)
536     {
537         Argument->strLibraryName.Buffer = (PWCHAR)((ULONG_PTR)Argument->strLibraryName.Buffer + (ULONG_PTR)Argument);
538     }
539     if(Argument->strInitFuncName.Buffer != NULL)
540     {
541         Argument->strInitFuncName.Buffer = (PWCHAR)((ULONG_PTR)Argument->strInitFuncName.Buffer + (ULONG_PTR)Argument);
542     }
543 
544     /* Call the implementation of the callback */
545     bResult = ClientLoadLibrary(&Argument->strLibraryName,
546                                 &Argument->strInitFuncName,
547                                 Argument->Unload,
548                                 Argument->ApiHook);
549 
550     return ZwCallbackReturn(&bResult, sizeof(HINSTANCE), STATUS_SUCCESS);
551 }
552 
553 NTSTATUS WINAPI
554 User32CallHookProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
555 {
556   PHOOKPROC_CALLBACK_ARGUMENTS Common;
557   CREATESTRUCTW *pCsw = NULL;
558   CBT_CREATEWNDW *pCbtCreatewndw = NULL;
559   PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra = NULL;
560   KBDLLHOOKSTRUCT KeyboardLlData, *pKeyboardLlData;
561   MSLLHOOKSTRUCT MouseLlData, *pMouseLlData;
562   MSG *pcMsg, *pMsg;
563   PMOUSEHOOKSTRUCT pMHook;
564   CWPSTRUCT *pCWP;
565   CWPRETSTRUCT *pCWPR;
566   PRECTL prl;
567   LPCBTACTIVATESTRUCT pcbtas;
568   HOOKPROC Proc;
569   WPARAM wParam = 0;
570   LPARAM lParam = 0;
571   LRESULT Result = 0;
572   BOOL Hit = FALSE, Loaded = FALSE;
573   HMODULE mod = NULL;
574   NTSTATUS Status = STATUS_SUCCESS;
575 
576   Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Arguments;
577 
578   Proc = Common->Proc;
579   // HookProc Justin Case module is from another process.
580   if (Common->offPfn && Common->Mod)
581   {
582      if (!(mod = GetModuleHandleW((LPCWSTR)Common->ModuleName)))
583      {
584         TRACE("Reloading Hook Module.\n");
585         if (!(mod = LoadLibraryExW((LPCWSTR)Common->ModuleName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)))
586         {
587            ERR("Failed to load Hook Module.\n");
588         }
589         else
590         {
591            Loaded = TRUE; // Free it only when loaded.
592         }
593      }
594      if (mod)
595      {
596         TRACE("Loading Hook Module. %S\n",Common->ModuleName);
597         Proc = (HOOKPROC)((char *)mod + Common->offPfn);
598      }
599   }
600 
601   switch(Common->HookId)
602   {
603     case WH_CBT:
604     {
605       //ERR("WH_CBT: Code %d\n", Common->Code);
606       switch(Common->Code)
607       {
608         case HCBT_CREATEWND:
609           CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS)
610                               ((PCHAR) Common + Common->lParam);
611 
612           pCbtCreatewndw = (CBT_CREATEWNDW*)HeapAlloc(GetProcessHeap(), 0, sizeof(CBT_CREATEWNDW));
613           RtlCopyMemory(pCbtCreatewndw, CbtCreatewndExtra, sizeof(CBT_CREATEWNDW));
614 
615           pCsw = (CREATESTRUCTW*)HeapAlloc(GetProcessHeap(), 0, sizeof(CREATESTRUCTW));
616           RtlCopyMemory(pCsw, &CbtCreatewndExtra->Cs, sizeof(CREATESTRUCTW));
617 
618           pCbtCreatewndw->lpcs = pCsw;
619           pCbtCreatewndw->hwndInsertAfter = CbtCreatewndExtra->WndInsertAfter;
620           wParam = Common->wParam;
621           lParam = (LPARAM) pCbtCreatewndw;
622           //ERR("HCBT_CREATEWND: hWnd %p Csw %p Name %p Class %p\n", Common->wParam, pCsw, pCsw->lpszName, pCsw->lpszClass);
623           break;
624         case HCBT_CLICKSKIPPED:
625             pMHook = (PMOUSEHOOKSTRUCT)((PCHAR) Common + Common->lParam);
626             lParam = (LPARAM) pMHook;
627             wParam = Common->wParam;
628             break;
629         case HCBT_MOVESIZE:
630             prl = (PRECTL)((PCHAR) Common + Common->lParam);
631             lParam = (LPARAM) prl;
632             wParam = Common->wParam;
633             break;
634         case HCBT_ACTIVATE:
635             //ERR("HCBT_ACTIVATE: hwnd %p\n",Common->wParam);
636             pcbtas = (LPCBTACTIVATESTRUCT)((PCHAR) Common + Common->lParam);
637             lParam = (LPARAM) pcbtas;
638             wParam = Common->wParam;
639             break;
640         case HCBT_KEYSKIPPED: /* The rest SEH support */
641         case HCBT_MINMAX:
642         case HCBT_SETFOCUS:
643         case HCBT_SYSCOMMAND:
644         case HCBT_DESTROYWND:
645         case HCBT_QS:
646             wParam = Common->wParam;
647             lParam = Common->lParam;
648             break;
649         default:
650           if (Loaded) FreeLibrary(mod);
651           ERR("HCBT_ not supported = %d\n", Common->Code);
652           return ZwCallbackReturn(NULL, 0, STATUS_NOT_SUPPORTED);
653       }
654 
655       if (Proc)
656       {
657          _SEH2_TRY
658          {
659             Result = Proc(Common->Code, wParam, lParam);
660          }
661          _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
662          {
663             Hit = TRUE;
664          }
665          _SEH2_END;
666       }
667       else
668       {
669          ERR("Null Proc! Common = 0x%x, Proc = 0x%x\n",Common,Proc);
670       }
671       switch(Common->Code)
672       {
673         case HCBT_CREATEWND:
674           CbtCreatewndExtra->WndInsertAfter = pCbtCreatewndw->hwndInsertAfter;
675           CbtCreatewndExtra->Cs.x  = pCbtCreatewndw->lpcs->x;
676           CbtCreatewndExtra->Cs.y  = pCbtCreatewndw->lpcs->y;
677           CbtCreatewndExtra->Cs.cx = pCbtCreatewndw->lpcs->cx;
678           CbtCreatewndExtra->Cs.cy = pCbtCreatewndw->lpcs->cy;
679           HeapFree(GetProcessHeap(), 0, pCsw);
680           HeapFree(GetProcessHeap(), 0, pCbtCreatewndw);
681           break;
682       }
683       break;
684     }
685     case WH_KEYBOARD_LL:
686       //ERR("WH_KEYBOARD_LL: Code %d, wParam %d\n",Common->Code,Common->wParam);
687       pKeyboardLlData = (PKBDLLHOOKSTRUCT)((PCHAR) Common + Common->lParam);
688       RtlCopyMemory(&KeyboardLlData, pKeyboardLlData, sizeof(KBDLLHOOKSTRUCT));
689       Result = Proc(Common->Code, Common->wParam, (LPARAM) &KeyboardLlData);
690       break;
691     case WH_MOUSE_LL:
692       //ERR("WH_MOUSE_LL: Code %d, wParam %d\n",Common->Code,Common->wParam);
693       pMouseLlData = (PMSLLHOOKSTRUCT)((PCHAR) Common + Common->lParam);
694       RtlCopyMemory(&MouseLlData, pMouseLlData, sizeof(MSLLHOOKSTRUCT));
695       Result = Proc(Common->Code, Common->wParam, (LPARAM) &MouseLlData);
696       break;
697     case WH_MOUSE: /* SEH support */
698       pMHook = (PMOUSEHOOKSTRUCT)((PCHAR) Common + Common->lParam);
699       _SEH2_TRY
700       {
701          Result = Proc(Common->Code, Common->wParam, (LPARAM) pMHook);
702       }
703       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
704       {
705          Hit = TRUE;
706       }
707       _SEH2_END;
708       break;
709     case WH_CALLWNDPROC:
710     {
711       PCWP_Struct pcwps = (PCWP_Struct)Common;
712       CWPSTRUCT *pCWPT = &pcwps->cwps;
713       pCWP = HeapAlloc(GetProcessHeap(), 0, Common->lParamSize + sizeof(CWPSTRUCT));
714       RtlCopyMemory(pCWP, pCWPT, sizeof(CWPSTRUCT));
715 //      ERR("WH_CALLWNDPROC: Code %d, wParam %d msg %d\n",Common->Code,Common->wParam,pCWP->message);
716       /* If more memory is reserved, then lParam is a pointer.
717        * Size of the buffer is stocked in the lParam member, and its content
718        * is at the end of the argument buffer */
719       if ( Common->lParamSize )
720       {
721          pCWP->lParam = (LPARAM)((PCHAR)pCWP + sizeof(CWPSTRUCT));
722          RtlCopyMemory( (PCHAR)pCWP + sizeof(CWPSTRUCT), &pcwps->Extra, Common->lParamSize );
723       }
724       Result = Proc(Common->Code, Common->wParam, (LPARAM) pCWP);
725       HeapFree(GetProcessHeap(), 0, pCWP);
726     }
727       break;
728     case WH_CALLWNDPROCRET:
729       /* Almost the same as WH_CALLWNDPROC */
730     {
731       PCWPR_Struct pcwprs = (PCWPR_Struct)Common;
732       CWPRETSTRUCT *pCWPRT = &pcwprs->cwprs;
733       pCWPR = HeapAlloc(GetProcessHeap(), 0, Common->lParamSize + sizeof(CWPRETSTRUCT));
734       RtlCopyMemory(pCWPR, pCWPRT, sizeof(CWPSTRUCT));
735       if ( Common->lParamSize )
736       {
737          pCWPR->lParam = (LPARAM)((PCHAR)pCWPR + sizeof(CWPRETSTRUCT));
738          RtlCopyMemory( (PCHAR)pCWPR + sizeof(CWPRETSTRUCT), &pcwprs->Extra, Common->lParamSize );
739       }
740       Result = Proc(Common->Code, Common->wParam, (LPARAM) pCWPR);
741       HeapFree(GetProcessHeap(), 0, pCWPR);
742     }
743       break;
744     case WH_MSGFILTER: /* All SEH support */
745     case WH_SYSMSGFILTER:
746     case WH_GETMESSAGE:
747       pMsg = (PMSG)((PCHAR) Common + Common->lParam);
748       pcMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MSG));
749       RtlCopyMemory(pcMsg, pMsg, sizeof(MSG));
750 //      ERR("pMsg %d  pcMsg %d\n",pMsg->message, pcMsg->message);
751       _SEH2_TRY
752       {
753          Result = Proc(Common->Code, Common->wParam, (LPARAM) pcMsg);
754       }
755       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
756       {
757          Hit = TRUE;
758       }
759       _SEH2_END;
760       if (!Hit && Common->HookId == WH_GETMESSAGE)
761          RtlCopyMemory(pMsg, pcMsg, sizeof(MSG));
762       HeapFree( GetProcessHeap(), 0, pcMsg );
763       break;
764     case WH_KEYBOARD:
765     case WH_SHELL:
766       Result = Proc(Common->Code, Common->wParam, Common->lParam);
767       break;
768     case WH_FOREGROUNDIDLE: /* <-- SEH support */
769       _SEH2_TRY
770       {
771          Result = Proc(Common->Code, Common->wParam, Common->lParam);
772       }
773       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
774       {
775          Hit = TRUE;
776       }
777       _SEH2_END;
778       break;
779     default:
780       if (Loaded) FreeLibrary(mod);
781       ERR("WH_ not supported = %d\n", Common->HookId);
782       return ZwCallbackReturn(NULL, 0, STATUS_NOT_SUPPORTED);
783   }
784   if (Hit)
785   {
786      ERR("Hook Exception! Id: %d, Code %d, Proc 0x%x\n",Common->HookId,Common->Code,Proc);
787      Status = STATUS_UNSUCCESSFUL;
788   }
789   if (Loaded) FreeLibrary(mod);
790   Common->Result = Result;
791   return ZwCallbackReturn(Arguments, ArgumentLength, Status);
792 }
793 
794 NTSTATUS WINAPI
795 User32CallEventProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
796 {
797   PEVENTPROC_CALLBACK_ARGUMENTS Common;
798   WINEVENTPROC Proc;
799   WCHAR module[MAX_PATH];
800   DWORD len;
801   HMODULE mod = NULL;
802   BOOL Loaded = FALSE;
803 
804   Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Arguments;
805 
806   Proc = Common->Proc;
807 
808   if (Common->offPfn && Common->Mod)
809   {  // Validate the module again.
810      if (!(len = GetModuleFileNameW((HINSTANCE)Common->Mod, module, MAX_PATH)) || len >= MAX_PATH)
811      {
812         ERR("Error check for module!\n");
813         Common->Mod = 0;
814      }
815 
816      if (Common->Mod && !(mod = GetModuleHandleW(module)))
817      {
818         TRACE("Reloading Event Module.\n");
819         if (!(mod = LoadLibraryExW(module, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)))
820         {
821            ERR("Failed to load Event Module.\n");
822         }
823         else
824         {
825            Loaded = TRUE; // Free it only when loaded.
826         }
827      }
828 
829      if (mod)
830      {
831         TRACE("Loading Event Module. %S\n",module);
832         Proc = (WINEVENTPROC)((char *)mod + Common->offPfn);
833      }
834   }
835 
836   Proc(Common->hook,
837        Common->event,
838        Common->hwnd,
839        Common->idObject,
840        Common->idChild,
841        Common->dwEventThread,
842        Common->dwmsEventTime);
843 
844   if (Loaded) FreeLibrary(mod);
845 
846   return ZwCallbackReturn(NULL, 0, STATUS_SUCCESS);
847 }
848 
849 
850 
851