xref: /reactos/win32ss/user/user32/windows/hook.c (revision 177ae91b)
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 Csw;
558   CBT_CREATEWNDW CbtCreatewndw;
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           RtlCopyMemory(&Csw, &CbtCreatewndExtra->Cs, sizeof(CREATESTRUCTW));
612           CbtCreatewndw.lpcs = &Csw;
613           CbtCreatewndw.hwndInsertAfter = CbtCreatewndExtra->WndInsertAfter;
614           wParam = Common->wParam;
615           lParam = (LPARAM) &CbtCreatewndw;
616           //ERR("HCBT_CREATEWND: hWnd 0x%x Name 0x%x Class 0x%x\n", Common->wParam, Csw.lpszName, Csw.lpszClass);
617           break;
618         case HCBT_CLICKSKIPPED:
619             pMHook = (PMOUSEHOOKSTRUCT)((PCHAR) Common + Common->lParam);
620             lParam = (LPARAM) pMHook;
621             wParam = Common->wParam;
622             break;
623         case HCBT_MOVESIZE:
624             prl = (PRECTL)((PCHAR) Common + Common->lParam);
625             lParam = (LPARAM) prl;
626             wParam = Common->wParam;
627             break;
628         case HCBT_ACTIVATE:
629             //ERR("HCBT_ACTIVATE: hwnd %p\n",Common->wParam);
630             pcbtas = (LPCBTACTIVATESTRUCT)((PCHAR) Common + Common->lParam);
631             lParam = (LPARAM) pcbtas;
632             wParam = Common->wParam;
633             break;
634         case HCBT_KEYSKIPPED: /* The rest SEH support */
635         case HCBT_MINMAX:
636         case HCBT_SETFOCUS:
637         case HCBT_SYSCOMMAND:
638         case HCBT_DESTROYWND:
639         case HCBT_QS:
640             wParam = Common->wParam;
641             lParam = Common->lParam;
642             break;
643         default:
644           if (Loaded) FreeLibrary(mod);
645           ERR("HCBT_ not supported = %d\n", Common->Code);
646           return ZwCallbackReturn(NULL, 0, STATUS_NOT_SUPPORTED);
647       }
648 
649       if (Proc)
650       {
651          _SEH2_TRY
652          {
653             Result = Proc(Common->Code, wParam, lParam);
654          }
655          _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
656          {
657             Hit = TRUE;
658          }
659          _SEH2_END;
660       }
661       else
662       {
663          ERR("Null Proc! Common = 0x%x, Proc = 0x%x\n",Common,Proc);
664       }
665       switch(Common->Code)
666       {
667         case HCBT_CREATEWND:
668           CbtCreatewndExtra->WndInsertAfter = CbtCreatewndw.hwndInsertAfter;
669           CbtCreatewndExtra->Cs.x = CbtCreatewndw.lpcs->x;
670           CbtCreatewndExtra->Cs.y = CbtCreatewndw.lpcs->y;
671           CbtCreatewndExtra->Cs.cx = CbtCreatewndw.lpcs->cx;
672           CbtCreatewndExtra->Cs.cy = CbtCreatewndw.lpcs->cy;
673           break;
674       }
675       break;
676     }
677     case WH_KEYBOARD_LL:
678       //ERR("WH_KEYBOARD_LL: Code %d, wParam %d\n",Common->Code,Common->wParam);
679       pKeyboardLlData = (PKBDLLHOOKSTRUCT)((PCHAR) Common + Common->lParam);
680       RtlCopyMemory(&KeyboardLlData, pKeyboardLlData, sizeof(KBDLLHOOKSTRUCT));
681       Result = Proc(Common->Code, Common->wParam, (LPARAM) &KeyboardLlData);
682       break;
683     case WH_MOUSE_LL:
684       //ERR("WH_MOUSE_LL: Code %d, wParam %d\n",Common->Code,Common->wParam);
685       pMouseLlData = (PMSLLHOOKSTRUCT)((PCHAR) Common + Common->lParam);
686       RtlCopyMemory(&MouseLlData, pMouseLlData, sizeof(MSLLHOOKSTRUCT));
687       Result = Proc(Common->Code, Common->wParam, (LPARAM) &MouseLlData);
688       break;
689     case WH_MOUSE: /* SEH support */
690       pMHook = (PMOUSEHOOKSTRUCT)((PCHAR) Common + Common->lParam);
691       _SEH2_TRY
692       {
693          Result = Proc(Common->Code, Common->wParam, (LPARAM) pMHook);
694       }
695       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
696       {
697          Hit = TRUE;
698       }
699       _SEH2_END;
700       break;
701     case WH_CALLWNDPROC:
702     {
703       PCWP_Struct pcwps = (PCWP_Struct)Common;
704       CWPSTRUCT *pCWPT = &pcwps->cwps;
705       pCWP = HeapAlloc(GetProcessHeap(), 0, Common->lParamSize + sizeof(CWPSTRUCT));
706       RtlCopyMemory(pCWP, pCWPT, sizeof(CWPSTRUCT));
707 //      ERR("WH_CALLWNDPROC: Code %d, wParam %d msg %d\n",Common->Code,Common->wParam,pCWP->message);
708       /* If more memory is reserved, then lParam is a pointer.
709        * Size of the buffer is stocked in the lParam member, and its content
710        * is at the end of the argument buffer */
711       if ( Common->lParamSize )
712       {
713          pCWP->lParam = (LPARAM)((PCHAR)pCWP + sizeof(CWPSTRUCT));
714          RtlCopyMemory( (PCHAR)pCWP + sizeof(CWPSTRUCT), &pcwps->Extra, Common->lParamSize );
715       }
716       Result = Proc(Common->Code, Common->wParam, (LPARAM) pCWP);
717       HeapFree(GetProcessHeap(), 0, pCWP);
718     }
719       break;
720     case WH_CALLWNDPROCRET:
721       /* Almost the same as WH_CALLWNDPROC */
722     {
723       PCWPR_Struct pcwprs = (PCWPR_Struct)Common;
724       CWPRETSTRUCT *pCWPRT = &pcwprs->cwprs;
725       pCWPR = HeapAlloc(GetProcessHeap(), 0, Common->lParamSize + sizeof(CWPRETSTRUCT));
726       RtlCopyMemory(pCWPR, pCWPRT, sizeof(CWPSTRUCT));
727       if ( Common->lParamSize )
728       {
729          pCWPR->lParam = (LPARAM)((PCHAR)pCWPR + sizeof(CWPRETSTRUCT));
730          RtlCopyMemory( (PCHAR)pCWPR + sizeof(CWPRETSTRUCT), &pcwprs->Extra, Common->lParamSize );
731       }
732       Result = Proc(Common->Code, Common->wParam, (LPARAM) pCWPR);
733       HeapFree(GetProcessHeap(), 0, pCWPR);
734     }
735       break;
736     case WH_MSGFILTER: /* All SEH support */
737     case WH_SYSMSGFILTER:
738     case WH_GETMESSAGE:
739       pMsg = (PMSG)((PCHAR) Common + Common->lParam);
740       pcMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MSG));
741       RtlCopyMemory(pcMsg, pMsg, sizeof(MSG));
742 //      ERR("pMsg %d  pcMsg %d\n",pMsg->message, pcMsg->message);
743       _SEH2_TRY
744       {
745          Result = Proc(Common->Code, Common->wParam, (LPARAM) pcMsg);
746       }
747       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
748       {
749          Hit = TRUE;
750       }
751       _SEH2_END;
752       if (!Hit && Common->HookId == WH_GETMESSAGE)
753          RtlCopyMemory(pMsg, pcMsg, sizeof(MSG));
754       HeapFree( GetProcessHeap(), 0, pcMsg );
755       break;
756     case WH_KEYBOARD:
757     case WH_SHELL:
758       Result = Proc(Common->Code, Common->wParam, Common->lParam);
759       break;
760     case WH_FOREGROUNDIDLE: /* <-- SEH support */
761       _SEH2_TRY
762       {
763          Result = Proc(Common->Code, Common->wParam, Common->lParam);
764       }
765       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
766       {
767          Hit = TRUE;
768       }
769       _SEH2_END;
770       break;
771     default:
772       if (Loaded) FreeLibrary(mod);
773       ERR("WH_ not supported = %d\n", Common->HookId);
774       return ZwCallbackReturn(NULL, 0, STATUS_NOT_SUPPORTED);
775   }
776   if (Hit)
777   {
778      ERR("Hook Exception! Id: %d, Code %d, Proc 0x%x\n",Common->HookId,Common->Code,Proc);
779      Status = STATUS_UNSUCCESSFUL;
780   }
781   if (Loaded) FreeLibrary(mod);
782   Common->Result = Result;
783   return ZwCallbackReturn(Arguments, ArgumentLength, Status);
784 }
785 
786 NTSTATUS WINAPI
787 User32CallEventProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
788 {
789   PEVENTPROC_CALLBACK_ARGUMENTS Common;
790   WINEVENTPROC Proc;
791   WCHAR module[MAX_PATH];
792   DWORD len;
793   HMODULE mod = NULL;
794   BOOL Loaded = FALSE;
795 
796   Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Arguments;
797 
798   Proc = Common->Proc;
799 
800   if (Common->offPfn && Common->Mod)
801   {  // Validate the module again.
802      if (!(len = GetModuleFileNameW((HINSTANCE)Common->Mod, module, MAX_PATH)) || len >= MAX_PATH)
803      {
804         ERR("Error check for module!\n");
805         Common->Mod = 0;
806      }
807 
808      if (Common->Mod && !(mod = GetModuleHandleW(module)))
809      {
810         TRACE("Reloading Event Module.\n");
811         if (!(mod = LoadLibraryExW(module, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)))
812         {
813            ERR("Failed to load Event Module.\n");
814         }
815         else
816         {
817            Loaded = TRUE; // Free it only when loaded.
818         }
819      }
820 
821      if (mod)
822      {
823         TRACE("Loading Event Module. %S\n",module);
824         Proc = (WINEVENTPROC)((char *)mod + Common->offPfn);
825      }
826   }
827 
828   Proc(Common->hook,
829        Common->event,
830        Common->hwnd,
831        Common->idObject,
832        Common->idChild,
833        Common->dwEventThread,
834        Common->dwmsEventTime);
835 
836   if (Loaded) FreeLibrary(mod);
837 
838   return ZwCallbackReturn(NULL, 0, STATUS_SUCCESS);
839 }
840 
841 
842 
843