3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
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.
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.
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.
21 * PROJECT: ReactOS user32.dll
22 * FILE: win32ss/user/user32/windows/hook.c
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * 09-05-2001 CSH Created
29 /* INCLUDES ******************************************************************/
33 #include <wine/debug.h>
35 WINE_DEFAULT_DEBUG_CHANNEL(user32
);
37 typedef struct _NOTIFYEVENT
43 } NOTIFYEVENT
, *PNOTIFYEVENT
;
45 /* PRIVATE FUNCTIONS *********************************************************/
50 GetMaskFromEvent(DWORD Event
)
54 if ( Event
> EVENT_OBJECT_STATECHANGE
)
56 if ( Event
== EVENT_OBJECT_LOCATIONCHANGE
) return SRV_EVENT_LOCATIONCHANGE
;
57 if ( Event
== EVENT_OBJECT_NAMECHANGE
) return SRV_EVENT_NAMECHANGE
;
58 if ( Event
== EVENT_OBJECT_VALUECHANGE
) return SRV_EVENT_VALUECHANGE
;
59 return SRV_EVENT_CREATE
;
62 if ( Event
== EVENT_OBJECT_STATECHANGE
) return SRV_EVENT_STATECHANGE
;
64 Ret
= SRV_EVENT_RUNNING
;
66 if ( Event
< EVENT_SYSTEM_MENUSTART
) return SRV_EVENT_CREATE
;
68 if ( Event
<= EVENT_SYSTEM_MENUPOPUPEND
)
74 if ( Event
<= EVENT_CONSOLE_CARET
-1 ) return SRV_EVENT_CREATE
;
75 if ( Event
<= EVENT_CONSOLE_END_APPLICATION
) return SRV_EVENT_END_APPLICATION
;
76 if ( Event
!= EVENT_OBJECT_FOCUS
) return SRV_EVENT_CREATE
;
91 WCHAR ModuleName
[MAX_PATH
];
92 UNICODE_STRING USModuleName
;
96 if (0 == GetModuleFileNameW(hMod
, ModuleName
, MAX_PATH
))
100 RtlInitUnicodeString(&USModuleName
, ModuleName
);
104 RtlInitUnicodeString(&USModuleName
, NULL
);
107 return NtUserSetWindowsHookEx(hMod
, &USModuleName
, dwThreadId
, idHook
, lpfn
, bAnsi
);
111 Since ReactOS uses User32 as the main message source this was needed.
112 Base on the funny rules from the wine tests it left it with this option.
127 ne
.idObject
= idObject
;
128 ne
.idChild
= idChild
;
130 if (gpsi
->dwInstalledEventHooks
& GetMaskFromEvent(event
))
131 NtUserxNotifyWinEvent(hwnd
, &ne
);
134 /* FUNCTIONS *****************************************************************/
158 if ( NtCurrentTeb()->Win32ThreadInfo
&&
159 (ISITHOOKED(WH_MSGFILTER
) || ISITHOOKED(WH_SYSMSGFILTER
)) )
161 if ( lpMsg
->message
& ~WM_MAXIMUM
)
163 SetLastError(ERROR_INVALID_PARAMETER
);
166 RtlCopyMemory(&Msg
, lpMsg
, sizeof(MSG
));
167 return NtUserCallMsgFilter( &Msg
, nCode
);
183 if ( NtCurrentTeb()->Win32ThreadInfo
&&
184 (ISITHOOKED(WH_MSGFILTER
) || ISITHOOKED(WH_SYSMSGFILTER
)) )
186 if ( lpMsg
->message
& ~WM_MAXIMUM
)
188 SetLastError(ERROR_INVALID_PARAMETER
);
191 RtlCopyMemory(&Msg
, lpMsg
, sizeof(MSG
));
192 return NtUserCallMsgFilter( &Msg
, nCode
);
204 HHOOK Hook
, // Windows NT/XP/2003: Ignored.
209 PCLIENTINFO ClientInfo
;
211 PHOOK pHook
, phkNext
;
214 ClientInfo
= GetWin32ClientInfo();
216 if (!ClientInfo
->phkCurrent
) return 0;
218 pHook
= DesktopPtrToUser(ClientInfo
->phkCurrent
);
220 if (!pHook
->phkNext
) return 0; // Nothing to do....
222 phkNext
= DesktopPtrToUser(pHook
->phkNext
);
224 if ( phkNext
->HookId
== WH_CALLWNDPROC
||
225 phkNext
->HookId
== WH_CALLWNDPROCRET
)
227 Save
= ClientInfo
->dwHookData
;
228 Flags
= ClientInfo
->CI_flags
& CI_CURTHPRHOOK
;
229 // wParam: If the message was sent by the current thread/process, it is
230 // nonzero; otherwise, it is zero.
231 if (wParam
) ClientInfo
->CI_flags
|= CI_CURTHPRHOOK
;
232 else ClientInfo
->CI_flags
&= ~CI_CURTHPRHOOK
;
234 if (phkNext
->HookId
== WH_CALLWNDPROC
)
236 PCWPSTRUCT pCWP
= (PCWPSTRUCT
)lParam
;
238 NtUserMessageCall( pCWP
->hwnd
,
248 PCWPRETSTRUCT pCWPR
= (PCWPRETSTRUCT
)lParam
;
250 ClientInfo
->dwHookData
= pCWPR
->lResult
;
252 NtUserMessageCall( pCWPR
->hwnd
,
260 ClientInfo
->CI_flags
^= ((ClientInfo
->CI_flags
^ Flags
) & CI_CURTHPRHOOK
);
261 ClientInfo
->dwHookData
= Save
;
264 lResult
= NtUserCallNextHookEx(Code
, wParam
, lParam
, pHook
->Ansi
);
275 SetWindowsHookW(int idHook
, HOOKPROC lpfn
)
277 DWORD ThreadId
= PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
);
278 return IntSetWindowsHook(idHook
, lpfn
, NULL
, ThreadId
, FALSE
);
279 // return NtUserSetWindowsHookAW(idHook, lpfn, FALSE);
287 SetWindowsHookA(int idHook
, HOOKPROC lpfn
)
289 DWORD ThreadId
= PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
);
290 return IntSetWindowsHook(idHook
, lpfn
, NULL
, ThreadId
, TRUE
);
291 // return NtUserSetWindowsHookAW(idHook, lpfn, TRUE);
299 DeregisterShellHookWindow(HWND hWnd
)
301 return NtUserxDeregisterShellHookWindow(hWnd
);
309 RegisterShellHookWindow(HWND hWnd
)
311 return NtUserxRegisterShellHookWindow(hWnd
);
319 UnhookWindowsHook ( int nCode
, HOOKPROC pfnFilterProc
)
321 return NtUserxUnhookWindowsHook(nCode
, pfnFilterProc
);
336 // "Servers call NotifyWinEvent to announce the event to the system after the
337 // event has occurred; they must never notify the system of an event before
338 // the event has occurred." msdn on NotifyWinEvent.
339 if (gpsi
->dwInstalledEventHooks
& GetMaskFromEvent(event
)) // Check to see.
340 NtUserNotifyWinEvent(event
, hwnd
, idObject
, idChild
);
351 HMODULE hmodWinEventProc
,
352 WINEVENTPROC pfnWinEventProc
,
358 WCHAR ModuleName
[MAX_PATH
];
359 UNICODE_STRING USModuleName
;
360 PUNICODE_STRING pusmodName
;
362 RtlInitUnicodeString(&USModuleName
, NULL
);
364 if ((hmodWinEventProc
!= NULL
) && (dwFlags
& WINEVENT_INCONTEXT
))
366 if (0 == GetModuleFileNameW(hmodWinEventProc
, ModuleName
, MAX_PATH
))
370 RtlInitUnicodeString(&USModuleName
, ModuleName
);
371 pusmodName
= &USModuleName
;
378 return NtUserSetWinEventHook(eventMin
,
393 IsWinEventHookInstalled(
396 if ((PTHREADINFO
)NtCurrentTeb()->Win32ThreadInfo
)
398 return (gpsi
->dwInstalledEventHooks
& GetMaskFromEvent(event
)) != 0;
414 return IntSetWindowsHook(idHook
, lpfn
, hMod
, dwThreadId
, TRUE
);
429 return IntSetWindowsHook(idHook
, lpfn
, hMod
, dwThreadId
, FALSE
);
435 PUNICODE_STRING pstrLibName
,
436 PUNICODE_STRING pstrInitFunc
,
443 ANSI_STRING InitFuncName
;
444 BOOL bResult
= FALSE
;
446 TRACE("ClientLoadLibrary: pid: %d, strLibraryName: %S, "
447 "strInitFuncName: %S, bUnload: %d, bApiHook:%d\n",
448 GetCurrentProcessId(),
450 pstrInitFunc
->Buffer
,
454 /* Check if we have to load the module */
455 if (bUnload
== FALSE
)
457 ASSERT(pstrLibName
->Buffer
!= NULL
);
460 hLibrary
= LoadLibrary(pstrLibName
->Buffer
);
468 /* There is nothing more to do for a global hook*/
472 /* Initialize the user api hook */
473 ASSERT(pstrInitFunc
->Buffer
);
474 Status
= RtlUnicodeStringToAnsiString(&InitFuncName
,
477 if (!NT_SUCCESS(Status
))
479 FreeLibrary(hLibrary
);
483 /* Get the address of the initialization routine */
484 pInitFunction
= GetProcAddress(hLibrary
, InitFuncName
.Buffer
);
487 /* Call the initialization routine */
488 bResult
= InitUserApiHook(hLibrary
, (USERAPIHOOKPROC
)pInitFunction
);
491 RtlFreeAnsiString(&InitFuncName
);
493 /* In case of error unload the library */
494 if (bResult
== FALSE
)
496 FreeLibrary(hLibrary
);
501 /* Cleanup user api hook before unloading */
504 hLibrary
= ghmodUserApiHook
;
505 bResult
= ClearUserApiHook(ghmodUserApiHook
);
507 /* Check if we can we unload it now */
510 /* Return success because we are going to free
511 the library in EndUserApiHook*/
517 /* Get the library handle from the name */
518 hLibrary
= GetModuleHandle(pstrLibName
->Buffer
);
519 if (hLibrary
== NULL
)
525 bResult
= FreeLibrary(hLibrary
);
532 User32CallClientLoadLibraryFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
535 PCLIENT_LOAD_LIBRARY_ARGUMENTS Argument
;
537 /* Retireve the callback parameters */
538 Argument
= (PCLIENT_LOAD_LIBRARY_ARGUMENTS
)Arguments
;
539 if(Argument
->strLibraryName
.Buffer
!= NULL
)
541 Argument
->strLibraryName
.Buffer
= (PWCHAR
)((ULONG_PTR
)Argument
->strLibraryName
.Buffer
+ (ULONG_PTR
)Argument
);
543 if(Argument
->strInitFuncName
.Buffer
!= NULL
)
545 Argument
->strInitFuncName
.Buffer
= (PWCHAR
)((ULONG_PTR
)Argument
->strInitFuncName
.Buffer
+ (ULONG_PTR
)Argument
);
548 /* Call the implementation of the callback */
549 bResult
= ClientLoadLibrary(&Argument
->strLibraryName
,
550 &Argument
->strInitFuncName
,
554 return ZwCallbackReturn(&bResult
, sizeof(HINSTANCE
), STATUS_SUCCESS
);
558 User32CallHookProcFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
560 PHOOKPROC_CALLBACK_ARGUMENTS Common
;
562 CBT_CREATEWNDW CbtCreatewndw
;
563 PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra
= NULL
;
564 KBDLLHOOKSTRUCT KeyboardLlData
, *pKeyboardLlData
;
565 MSLLHOOKSTRUCT MouseLlData
, *pMouseLlData
;
567 PMOUSEHOOKSTRUCT pMHook
;
571 LPCBTACTIVATESTRUCT pcbtas
;
576 BOOL Hit
= FALSE
, Loaded
= FALSE
;
578 NTSTATUS Status
= STATUS_SUCCESS
;
580 Common
= (PHOOKPROC_CALLBACK_ARGUMENTS
) Arguments
;
583 // HookProc Justin Case module is from another process.
584 if (Common
->offPfn
&& Common
->Mod
)
586 if (!(mod
= GetModuleHandleW((LPCWSTR
)Common
->ModuleName
)))
588 TRACE("Reloading Hook Module.\n");
589 if (!(mod
= LoadLibraryExW((LPCWSTR
)Common
->ModuleName
, NULL
, LOAD_WITH_ALTERED_SEARCH_PATH
)))
591 ERR("Failed to load Hook Module.\n");
595 Loaded
= TRUE
; // Free it only when loaded.
600 TRACE("Loading Hook Module. %S\n",Common
->ModuleName
);
601 Proc
= (HOOKPROC
)((char *)mod
+ Common
->offPfn
);
605 switch(Common
->HookId
)
609 //ERR("WH_CBT: Code %d\n", Common->Code);
613 CbtCreatewndExtra
= (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS
)
614 ((PCHAR
) Common
+ Common
->lParam
);
615 RtlCopyMemory(&Csw
, &CbtCreatewndExtra
->Cs
, sizeof(CREATESTRUCTW
));
616 CbtCreatewndw
.lpcs
= &Csw
;
617 CbtCreatewndw
.hwndInsertAfter
= CbtCreatewndExtra
->WndInsertAfter
;
618 wParam
= Common
->wParam
;
619 lParam
= (LPARAM
) &CbtCreatewndw
;
620 //ERR("HCBT_CREATEWND: hWnd 0x%x Name 0x%x Class 0x%x\n", Common->wParam, Csw.lpszName, Csw.lpszClass);
622 case HCBT_CLICKSKIPPED
:
623 pMHook
= (PMOUSEHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
624 lParam
= (LPARAM
) pMHook
;
625 wParam
= Common
->wParam
;
628 prl
= (PRECTL
)((PCHAR
) Common
+ Common
->lParam
);
629 lParam
= (LPARAM
) prl
;
630 wParam
= Common
->wParam
;
633 //ERR("HCBT_ACTIVATE: hwnd %p\n",Common->wParam);
634 pcbtas
= (LPCBTACTIVATESTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
635 lParam
= (LPARAM
) pcbtas
;
636 wParam
= Common
->wParam
;
638 case HCBT_KEYSKIPPED
: /* The rest SEH support */
641 case HCBT_SYSCOMMAND
:
642 case HCBT_DESTROYWND
:
644 wParam
= Common
->wParam
;
645 lParam
= Common
->lParam
;
648 if (Loaded
) FreeLibrary(mod
);
649 ERR("HCBT_ not supported = %d\n", Common
->Code
);
650 return ZwCallbackReturn(NULL
, 0, STATUS_NOT_SUPPORTED
);
657 Result
= Proc(Common
->Code
, wParam
, lParam
);
659 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
667 ERR("Null Proc! Common = 0x%x, Proc = 0x%x\n",Common
,Proc
);
672 CbtCreatewndExtra
->WndInsertAfter
= CbtCreatewndw
.hwndInsertAfter
;
673 CbtCreatewndExtra
->Cs
.x
= CbtCreatewndw
.lpcs
->x
;
674 CbtCreatewndExtra
->Cs
.y
= CbtCreatewndw
.lpcs
->y
;
675 CbtCreatewndExtra
->Cs
.cx
= CbtCreatewndw
.lpcs
->cx
;
676 CbtCreatewndExtra
->Cs
.cy
= CbtCreatewndw
.lpcs
->cy
;
682 //ERR("WH_KEYBOARD_LL: Code %d, wParam %d\n",Common->Code,Common->wParam);
683 pKeyboardLlData
= (PKBDLLHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
684 RtlCopyMemory(&KeyboardLlData
, pKeyboardLlData
, sizeof(KBDLLHOOKSTRUCT
));
685 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) &KeyboardLlData
);
688 //ERR("WH_MOUSE_LL: Code %d, wParam %d\n",Common->Code,Common->wParam);
689 pMouseLlData
= (PMSLLHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
690 RtlCopyMemory(&MouseLlData
, pMouseLlData
, sizeof(MSLLHOOKSTRUCT
));
691 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) &MouseLlData
);
693 case WH_MOUSE
: /* SEH support */
694 pMHook
= (PMOUSEHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
697 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pMHook
);
699 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
706 // ERR("WH_CALLWNDPROC: Code %d, wParam %d\n",Common->Code,Common->wParam);
707 pCWP
= HeapAlloc(GetProcessHeap(), 0, ArgumentLength
- sizeof(HOOKPROC_CALLBACK_ARGUMENTS
));
708 RtlCopyMemory(pCWP
, (PCHAR
) Common
+ Common
->lParam
, sizeof(CWPSTRUCT
));
709 /* If more memory is reserved, then lParam is a pointer.
710 * Size of the buffer is stocked in the lParam member, and its content
711 * is at the end of the argument buffer */
712 if(ArgumentLength
> (sizeof(CWPSTRUCT
) + sizeof(HOOKPROC_CALLBACK_ARGUMENTS
)))
714 RtlCopyMemory((PCHAR
)pCWP
+ sizeof(CWPSTRUCT
),
715 (PCHAR
)Common
+ Common
->lParam
+ sizeof(CWPSTRUCT
),
717 pCWP
->lParam
= (LPARAM
)((PCHAR
)pCWP
+ sizeof(CWPSTRUCT
));
719 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pCWP
);
720 HeapFree(GetProcessHeap(), 0, pCWP
);
722 case WH_CALLWNDPROCRET
:
723 /* Almost the same as WH_CALLWNDPROC */
724 pCWPR
= HeapAlloc(GetProcessHeap(), 0, ArgumentLength
- sizeof(HOOKPROC_CALLBACK_ARGUMENTS
));
725 RtlCopyMemory(pCWPR
, (PCHAR
) Common
+ Common
->lParam
, sizeof(CWPRETSTRUCT
));
726 if(ArgumentLength
> (sizeof(CWPRETSTRUCT
) + sizeof(HOOKPROC_CALLBACK_ARGUMENTS
)))
728 RtlCopyMemory((PCHAR
)pCWPR
+ sizeof(CWPRETSTRUCT
),
729 (PCHAR
)Common
+ Common
->lParam
+ sizeof(CWPRETSTRUCT
),
731 pCWPR
->lParam
= (LPARAM
)((PCHAR
)pCWPR
+ sizeof(CWPRETSTRUCT
));
733 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pCWPR
);
734 HeapFree(GetProcessHeap(), 0, pCWPR
);
736 case WH_MSGFILTER
: /* All SEH support */
737 case WH_SYSMSGFILTER
:
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);
745 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pcMsg
);
747 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
752 if (!Hit
&& Common
->HookId
== WH_GETMESSAGE
)
753 RtlCopyMemory(pMsg
, pcMsg
, sizeof(MSG
));
754 HeapFree( GetProcessHeap(), 0, pcMsg
);
758 Result
= Proc(Common
->Code
, Common
->wParam
, Common
->lParam
);
760 case WH_FOREGROUNDIDLE
: /* <-- SEH support */
763 Result
= Proc(Common
->Code
, Common
->wParam
, Common
->lParam
);
765 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
772 if (Loaded
) FreeLibrary(mod
);
773 ERR("WH_ not supported = %d\n", Common
->HookId
);
774 return ZwCallbackReturn(NULL
, 0, STATUS_NOT_SUPPORTED
);
778 ERR("Hook Exception! Id: %d, Code %d, Proc 0x%x\n",Common
->HookId
,Common
->Code
,Proc
);
779 Status
= STATUS_UNSUCCESSFUL
;
781 if (Loaded
) FreeLibrary(mod
);
782 Common
->Result
= Result
;
783 return ZwCallbackReturn(Arguments
, ArgumentLength
, Status
);
787 User32CallEventProcFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
789 PEVENTPROC_CALLBACK_ARGUMENTS Common
;
791 WCHAR module
[MAX_PATH
];
796 Common
= (PEVENTPROC_CALLBACK_ARGUMENTS
) Arguments
;
800 if (Common
->offPfn
&& Common
->Mod
)
801 { // Validate the module again.
802 if (!(len
= GetModuleFileNameW((HINSTANCE
)Common
->Mod
, module
, MAX_PATH
)) || len
>= MAX_PATH
)
804 ERR("Error check for module!\n");
808 if (Common
->Mod
&& !(mod
= GetModuleHandleW(module
)))
810 TRACE("Reloading Event Module.\n");
811 if (!(mod
= LoadLibraryExW(module
, NULL
, LOAD_WITH_ALTERED_SEARCH_PATH
)))
813 ERR("Failed to load Event Module.\n");
817 Loaded
= TRUE
; // Free it only when loaded.
823 TRACE("Loading Event Module. %S\n",module
);
824 Proc
= (WINEVENTPROC
)((char *)mod
+ Common
->offPfn
);
833 Common
->dwEventThread
,
834 Common
->dwmsEventTime
);
836 if (Loaded
) FreeLibrary(mod
);
838 return ZwCallbackReturn(NULL
, 0, STATUS_SUCCESS
);