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
31 WINE_DEFAULT_DEBUG_CHANNEL(user32
);
33 typedef struct _NOTIFYEVENT
39 } NOTIFYEVENT
, *PNOTIFYEVENT
;
41 /* PRIVATE FUNCTIONS *********************************************************/
46 GetMaskFromEvent(DWORD Event
)
50 if ( Event
> EVENT_OBJECT_STATECHANGE
)
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
;
58 if ( Event
== EVENT_OBJECT_STATECHANGE
) return SRV_EVENT_STATECHANGE
;
60 Ret
= SRV_EVENT_RUNNING
;
62 if ( Event
< EVENT_SYSTEM_MENUSTART
) return SRV_EVENT_CREATE
;
64 if ( Event
<= EVENT_SYSTEM_MENUPOPUPEND
)
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
;
87 WCHAR ModuleName
[MAX_PATH
];
88 UNICODE_STRING USModuleName
;
92 if (0 == GetModuleFileNameW(hMod
, ModuleName
, MAX_PATH
))
96 RtlInitUnicodeString(&USModuleName
, ModuleName
);
100 RtlInitUnicodeString(&USModuleName
, NULL
);
103 return NtUserSetWindowsHookEx(hMod
, &USModuleName
, dwThreadId
, idHook
, lpfn
, bAnsi
);
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.
123 ne
.idObject
= idObject
;
124 ne
.idChild
= idChild
;
126 if (gpsi
->dwInstalledEventHooks
& GetMaskFromEvent(event
))
127 NtUserxNotifyWinEvent(hwnd
, &ne
);
130 /* FUNCTIONS *****************************************************************/
154 if ( NtCurrentTeb()->Win32ThreadInfo
&&
155 (ISITHOOKED(WH_MSGFILTER
) || ISITHOOKED(WH_SYSMSGFILTER
)) )
157 if ( lpMsg
->message
& ~WM_MAXIMUM
)
159 SetLastError(ERROR_INVALID_PARAMETER
);
162 RtlCopyMemory(&Msg
, lpMsg
, sizeof(MSG
));
163 return NtUserCallMsgFilter( &Msg
, nCode
);
179 if ( NtCurrentTeb()->Win32ThreadInfo
&&
180 (ISITHOOKED(WH_MSGFILTER
) || ISITHOOKED(WH_SYSMSGFILTER
)) )
182 if ( lpMsg
->message
& ~WM_MAXIMUM
)
184 SetLastError(ERROR_INVALID_PARAMETER
);
187 RtlCopyMemory(&Msg
, lpMsg
, sizeof(MSG
));
188 return NtUserCallMsgFilter( &Msg
, nCode
);
200 HHOOK Hook
, // Windows NT/XP/2003: Ignored.
205 PCLIENTINFO ClientInfo
;
207 PHOOK pHook
, phkNext
;
210 ClientInfo
= GetWin32ClientInfo();
212 if (!ClientInfo
->phkCurrent
) return 0;
214 pHook
= DesktopPtrToUser(ClientInfo
->phkCurrent
);
216 if (!pHook
->phkNext
) return 0; // Nothing to do....
218 phkNext
= DesktopPtrToUser(pHook
->phkNext
);
220 if ( phkNext
->HookId
== WH_CALLWNDPROC
||
221 phkNext
->HookId
== WH_CALLWNDPROCRET
)
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
;
230 if (phkNext
->HookId
== WH_CALLWNDPROC
)
232 PCWPSTRUCT pCWP
= (PCWPSTRUCT
)lParam
;
234 NtUserMessageCall( pCWP
->hwnd
,
244 PCWPRETSTRUCT pCWPR
= (PCWPRETSTRUCT
)lParam
;
246 ClientInfo
->dwHookData
= pCWPR
->lResult
;
248 NtUserMessageCall( pCWPR
->hwnd
,
256 ClientInfo
->CI_flags
^= ((ClientInfo
->CI_flags
^ Flags
) & CI_CURTHPRHOOK
);
257 ClientInfo
->dwHookData
= Save
;
260 lResult
= NtUserCallNextHookEx(Code
, wParam
, lParam
, pHook
->Ansi
);
271 SetWindowsHookW(int idHook
, HOOKPROC lpfn
)
273 DWORD ThreadId
= PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
);
274 return IntSetWindowsHook(idHook
, lpfn
, NULL
, ThreadId
, FALSE
);
275 // return NtUserSetWindowsHookAW(idHook, lpfn, FALSE);
283 SetWindowsHookA(int idHook
, HOOKPROC lpfn
)
285 DWORD ThreadId
= PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
);
286 return IntSetWindowsHook(idHook
, lpfn
, NULL
, ThreadId
, TRUE
);
287 // return NtUserSetWindowsHookAW(idHook, lpfn, TRUE);
295 DeregisterShellHookWindow(HWND hWnd
)
297 return NtUserxDeregisterShellHookWindow(hWnd
);
305 RegisterShellHookWindow(HWND hWnd
)
307 return NtUserxRegisterShellHookWindow(hWnd
);
315 UnhookWindowsHook ( int nCode
, HOOKPROC pfnFilterProc
)
317 return NtUserxUnhookWindowsHook(nCode
, pfnFilterProc
);
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
);
347 HMODULE hmodWinEventProc
,
348 WINEVENTPROC pfnWinEventProc
,
354 WCHAR ModuleName
[MAX_PATH
];
355 UNICODE_STRING USModuleName
;
356 PUNICODE_STRING pusmodName
;
358 RtlInitUnicodeString(&USModuleName
, NULL
);
360 if ((hmodWinEventProc
!= NULL
) && (dwFlags
& WINEVENT_INCONTEXT
))
362 if (0 == GetModuleFileNameW(hmodWinEventProc
, ModuleName
, MAX_PATH
))
366 RtlInitUnicodeString(&USModuleName
, ModuleName
);
367 pusmodName
= &USModuleName
;
374 return NtUserSetWinEventHook(eventMin
,
389 IsWinEventHookInstalled(
392 if ((PTHREADINFO
)NtCurrentTeb()->Win32ThreadInfo
)
394 return (gpsi
->dwInstalledEventHooks
& GetMaskFromEvent(event
)) != 0;
410 return IntSetWindowsHook(idHook
, lpfn
, hMod
, dwThreadId
, TRUE
);
425 return IntSetWindowsHook(idHook
, lpfn
, hMod
, dwThreadId
, FALSE
);
431 PUNICODE_STRING pstrLibName
,
432 PUNICODE_STRING pstrInitFunc
,
439 ANSI_STRING InitFuncName
;
440 BOOL bResult
= FALSE
;
442 TRACE("ClientLoadLibrary: pid: %d, strLibraryName: %S, "
443 "strInitFuncName: %S, bUnload: %d, bApiHook:%d\n",
444 GetCurrentProcessId(),
446 pstrInitFunc
->Buffer
,
450 /* Check if we have to load the module */
451 if (bUnload
== FALSE
)
453 ASSERT(pstrLibName
->Buffer
!= NULL
);
456 hLibrary
= LoadLibrary(pstrLibName
->Buffer
);
464 /* There is nothing more to do for a global hook*/
468 /* Initialize the user api hook */
469 ASSERT(pstrInitFunc
->Buffer
);
470 Status
= RtlUnicodeStringToAnsiString(&InitFuncName
,
473 if (!NT_SUCCESS(Status
))
475 FreeLibrary(hLibrary
);
479 /* Get the address of the initialization routine */
480 pInitFunction
= GetProcAddress(hLibrary
, InitFuncName
.Buffer
);
483 /* Call the initialization routine */
484 bResult
= InitUserApiHook(hLibrary
, (USERAPIHOOKPROC
)pInitFunction
);
487 RtlFreeAnsiString(&InitFuncName
);
489 /* In case of error unload the library */
490 if (bResult
== FALSE
)
492 FreeLibrary(hLibrary
);
497 /* Cleanup user api hook before unloading */
500 hLibrary
= ghmodUserApiHook
;
501 bResult
= ClearUserApiHook(ghmodUserApiHook
);
503 /* Check if we can we unload it now */
506 /* Return success because we are going to free
507 the library in EndUserApiHook*/
513 /* Get the library handle from the name */
514 hLibrary
= GetModuleHandle(pstrLibName
->Buffer
);
515 if (hLibrary
== NULL
)
521 bResult
= FreeLibrary(hLibrary
);
528 User32CallClientLoadLibraryFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
531 PCLIENT_LOAD_LIBRARY_ARGUMENTS Argument
;
533 /* Retireve the callback parameters */
534 Argument
= (PCLIENT_LOAD_LIBRARY_ARGUMENTS
)Arguments
;
535 if(Argument
->strLibraryName
.Buffer
!= NULL
)
537 Argument
->strLibraryName
.Buffer
= (PWCHAR
)((ULONG_PTR
)Argument
->strLibraryName
.Buffer
+ (ULONG_PTR
)Argument
);
539 if(Argument
->strInitFuncName
.Buffer
!= NULL
)
541 Argument
->strInitFuncName
.Buffer
= (PWCHAR
)((ULONG_PTR
)Argument
->strInitFuncName
.Buffer
+ (ULONG_PTR
)Argument
);
544 /* Call the implementation of the callback */
545 bResult
= ClientLoadLibrary(&Argument
->strLibraryName
,
546 &Argument
->strInitFuncName
,
550 return ZwCallbackReturn(&bResult
, sizeof(HINSTANCE
), STATUS_SUCCESS
);
554 User32CallHookProcFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
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
;
563 PMOUSEHOOKSTRUCT pMHook
;
567 LPCBTACTIVATESTRUCT pcbtas
;
572 BOOL Hit
= FALSE
, Loaded
= FALSE
;
574 NTSTATUS Status
= STATUS_SUCCESS
;
576 Common
= (PHOOKPROC_CALLBACK_ARGUMENTS
) Arguments
;
579 // HookProc Justin Case module is from another process.
580 if (Common
->offPfn
&& Common
->Mod
)
582 if (!(mod
= GetModuleHandleW((LPCWSTR
)Common
->ModuleName
)))
584 TRACE("Reloading Hook Module.\n");
585 if (!(mod
= LoadLibraryExW((LPCWSTR
)Common
->ModuleName
, NULL
, LOAD_WITH_ALTERED_SEARCH_PATH
)))
587 ERR("Failed to load Hook Module.\n");
591 Loaded
= TRUE
; // Free it only when loaded.
596 TRACE("Loading Hook Module. %S\n",Common
->ModuleName
);
597 Proc
= (HOOKPROC
)((char *)mod
+ Common
->offPfn
);
601 switch(Common
->HookId
)
605 //ERR("WH_CBT: Code %d\n", Common->Code);
609 CbtCreatewndExtra
= (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS
)
610 ((PCHAR
) Common
+ Common
->lParam
);
612 pCbtCreatewndw
= (CBT_CREATEWNDW
*)HeapAlloc(GetProcessHeap(), 0, sizeof(CBT_CREATEWNDW
));
613 RtlCopyMemory(pCbtCreatewndw
, CbtCreatewndExtra
, sizeof(CBT_CREATEWNDW
));
615 pCsw
= (CREATESTRUCTW
*)HeapAlloc(GetProcessHeap(), 0, sizeof(CREATESTRUCTW
));
616 RtlCopyMemory(pCsw
, &CbtCreatewndExtra
->Cs
, sizeof(CREATESTRUCTW
));
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);
624 case HCBT_CLICKSKIPPED
:
625 pMHook
= (PMOUSEHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
626 lParam
= (LPARAM
) pMHook
;
627 wParam
= Common
->wParam
;
630 prl
= (PRECTL
)((PCHAR
) Common
+ Common
->lParam
);
631 lParam
= (LPARAM
) prl
;
632 wParam
= Common
->wParam
;
635 //ERR("HCBT_ACTIVATE: hwnd %p\n",Common->wParam);
636 pcbtas
= (LPCBTACTIVATESTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
637 lParam
= (LPARAM
) pcbtas
;
638 wParam
= Common
->wParam
;
640 case HCBT_KEYSKIPPED
: /* The rest SEH support */
643 case HCBT_SYSCOMMAND
:
644 case HCBT_DESTROYWND
:
646 wParam
= Common
->wParam
;
647 lParam
= Common
->lParam
;
650 if (Loaded
) FreeLibrary(mod
);
651 ERR("HCBT_ not supported = %d\n", Common
->Code
);
652 return ZwCallbackReturn(NULL
, 0, STATUS_NOT_SUPPORTED
);
659 Result
= Proc(Common
->Code
, wParam
, lParam
);
661 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
669 ERR("Null Proc! Common = 0x%x, Proc = 0x%x\n",Common
,Proc
);
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
);
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
);
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
);
697 case WH_MOUSE
: /* SEH support */
698 pMHook
= (PMOUSEHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
701 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pMHook
);
703 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
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
)
721 pCWP
->lParam
= (LPARAM
)((PCHAR
)pCWP
+ sizeof(CWPSTRUCT
));
722 RtlCopyMemory( (PCHAR
)pCWP
+ sizeof(CWPSTRUCT
), &pcwps
->Extra
, Common
->lParamSize
);
724 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pCWP
);
725 HeapFree(GetProcessHeap(), 0, pCWP
);
728 case WH_CALLWNDPROCRET
:
729 /* Almost the same as WH_CALLWNDPROC */
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
)
737 pCWPR
->lParam
= (LPARAM
)((PCHAR
)pCWPR
+ sizeof(CWPRETSTRUCT
));
738 RtlCopyMemory( (PCHAR
)pCWPR
+ sizeof(CWPRETSTRUCT
), &pcwprs
->Extra
, Common
->lParamSize
);
740 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pCWPR
);
741 HeapFree(GetProcessHeap(), 0, pCWPR
);
744 case WH_MSGFILTER
: /* All SEH support */
745 case WH_SYSMSGFILTER
:
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);
753 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pcMsg
);
755 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
760 if (!Hit
&& Common
->HookId
== WH_GETMESSAGE
)
761 RtlCopyMemory(pMsg
, pcMsg
, sizeof(MSG
));
762 HeapFree( GetProcessHeap(), 0, pcMsg
);
766 Result
= Proc(Common
->Code
, Common
->wParam
, Common
->lParam
);
768 case WH_FOREGROUNDIDLE
: /* <-- SEH support */
771 Result
= Proc(Common
->Code
, Common
->wParam
, Common
->lParam
);
773 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
780 if (Loaded
) FreeLibrary(mod
);
781 ERR("WH_ not supported = %d\n", Common
->HookId
);
782 return ZwCallbackReturn(NULL
, 0, STATUS_NOT_SUPPORTED
);
786 ERR("Hook Exception! Id: %d, Code %d, Proc 0x%x\n",Common
->HookId
,Common
->Code
,Proc
);
787 Status
= STATUS_UNSUCCESSFUL
;
789 if (Loaded
) FreeLibrary(mod
);
790 Common
->Result
= Result
;
791 return ZwCallbackReturn(Arguments
, ArgumentLength
, Status
);
795 User32CallEventProcFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
797 PEVENTPROC_CALLBACK_ARGUMENTS Common
;
799 WCHAR module
[MAX_PATH
];
804 Common
= (PEVENTPROC_CALLBACK_ARGUMENTS
) Arguments
;
808 if (Common
->offPfn
&& Common
->Mod
)
809 { // Validate the module again.
810 if (!(len
= GetModuleFileNameW((HINSTANCE
)Common
->Mod
, module
, MAX_PATH
)) || len
>= MAX_PATH
)
812 ERR("Error check for module!\n");
816 if (Common
->Mod
&& !(mod
= GetModuleHandleW(module
)))
818 TRACE("Reloading Event Module.\n");
819 if (!(mod
= LoadLibraryExW(module
, NULL
, LOAD_WITH_ALTERED_SEARCH_PATH
)))
821 ERR("Failed to load Event Module.\n");
825 Loaded
= TRUE
; // Free it only when loaded.
831 TRACE("Loading Event Module. %S\n",module
);
832 Proc
= (WINEVENTPROC
)((char *)mod
+ Common
->offPfn
);
841 Common
->dwEventThread
,
842 Common
->dwmsEventTime
);
844 if (Loaded
) FreeLibrary(mod
);
846 return ZwCallbackReturn(NULL
, 0, STATUS_SUCCESS
);