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
;
558 CBT_CREATEWNDW CbtCreatewndw
;
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
);
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);
618 case HCBT_CLICKSKIPPED
:
619 pMHook
= (PMOUSEHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
620 lParam
= (LPARAM
) pMHook
;
621 wParam
= Common
->wParam
;
624 prl
= (PRECTL
)((PCHAR
) Common
+ Common
->lParam
);
625 lParam
= (LPARAM
) prl
;
626 wParam
= Common
->wParam
;
629 //ERR("HCBT_ACTIVATE: hwnd %p\n",Common->wParam);
630 pcbtas
= (LPCBTACTIVATESTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
631 lParam
= (LPARAM
) pcbtas
;
632 wParam
= Common
->wParam
;
634 case HCBT_KEYSKIPPED
: /* The rest SEH support */
637 case HCBT_SYSCOMMAND
:
638 case HCBT_DESTROYWND
:
640 wParam
= Common
->wParam
;
641 lParam
= Common
->lParam
;
644 if (Loaded
) FreeLibrary(mod
);
645 ERR("HCBT_ not supported = %d\n", Common
->Code
);
646 return ZwCallbackReturn(NULL
, 0, STATUS_NOT_SUPPORTED
);
653 Result
= Proc(Common
->Code
, wParam
, lParam
);
655 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
663 ERR("Null Proc! Common = 0x%x, Proc = 0x%x\n",Common
,Proc
);
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
;
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
);
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
);
689 case WH_MOUSE
: /* SEH support */
690 pMHook
= (PMOUSEHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
693 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pMHook
);
695 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
702 // ERR("WH_CALLWNDPROC: Code %d, wParam %d\n",Common->Code,Common->wParam);
703 pCWP
= HeapAlloc(GetProcessHeap(), 0, ArgumentLength
- sizeof(HOOKPROC_CALLBACK_ARGUMENTS
));
704 RtlCopyMemory(pCWP
, (PCHAR
) Common
+ Common
->lParam
, sizeof(CWPSTRUCT
));
705 /* If more memory is reserved, then lParam is a pointer.
706 * Size of the buffer is stocked in the lParam member, and its content
707 * is at the end of the argument buffer */
708 if(ArgumentLength
> (sizeof(CWPSTRUCT
) + sizeof(HOOKPROC_CALLBACK_ARGUMENTS
)))
710 RtlCopyMemory((PCHAR
)pCWP
+ sizeof(CWPSTRUCT
),
711 (PCHAR
)Common
+ Common
->lParam
+ sizeof(CWPSTRUCT
),
713 pCWP
->lParam
= (LPARAM
)((PCHAR
)pCWP
+ sizeof(CWPSTRUCT
));
715 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pCWP
);
716 HeapFree(GetProcessHeap(), 0, pCWP
);
718 case WH_CALLWNDPROCRET
:
719 /* Almost the same as WH_CALLWNDPROC */
720 pCWPR
= HeapAlloc(GetProcessHeap(), 0, ArgumentLength
- sizeof(HOOKPROC_CALLBACK_ARGUMENTS
));
721 RtlCopyMemory(pCWPR
, (PCHAR
) Common
+ Common
->lParam
, sizeof(CWPRETSTRUCT
));
722 if(ArgumentLength
> (sizeof(CWPRETSTRUCT
) + sizeof(HOOKPROC_CALLBACK_ARGUMENTS
)))
724 RtlCopyMemory((PCHAR
)pCWPR
+ sizeof(CWPRETSTRUCT
),
725 (PCHAR
)Common
+ Common
->lParam
+ sizeof(CWPRETSTRUCT
),
727 pCWPR
->lParam
= (LPARAM
)((PCHAR
)pCWPR
+ sizeof(CWPRETSTRUCT
));
729 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pCWPR
);
730 HeapFree(GetProcessHeap(), 0, pCWPR
);
732 case WH_MSGFILTER
: /* All SEH support */
733 case WH_SYSMSGFILTER
:
735 pMsg
= (PMSG
)((PCHAR
) Common
+ Common
->lParam
);
736 pcMsg
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MSG
));
737 RtlCopyMemory(pcMsg
, pMsg
, sizeof(MSG
));
738 // ERR("pMsg %d pcMsg %d\n",pMsg->message, pcMsg->message);
741 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pcMsg
);
743 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
748 if (!Hit
&& Common
->HookId
== WH_GETMESSAGE
)
749 RtlCopyMemory(pMsg
, pcMsg
, sizeof(MSG
));
750 HeapFree( GetProcessHeap(), 0, pcMsg
);
754 Result
= Proc(Common
->Code
, Common
->wParam
, Common
->lParam
);
756 case WH_FOREGROUNDIDLE
: /* <-- SEH support */
759 Result
= Proc(Common
->Code
, Common
->wParam
, Common
->lParam
);
761 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
768 if (Loaded
) FreeLibrary(mod
);
769 ERR("WH_ not supported = %d\n", Common
->HookId
);
770 return ZwCallbackReturn(NULL
, 0, STATUS_NOT_SUPPORTED
);
774 ERR("Hook Exception! Id: %d, Code %d, Proc 0x%x\n",Common
->HookId
,Common
->Code
,Proc
);
775 Status
= STATUS_UNSUCCESSFUL
;
777 if (Loaded
) FreeLibrary(mod
);
778 Common
->Result
= Result
;
779 return ZwCallbackReturn(Arguments
, ArgumentLength
, Status
);
783 User32CallEventProcFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
785 PEVENTPROC_CALLBACK_ARGUMENTS Common
;
787 WCHAR module
[MAX_PATH
];
792 Common
= (PEVENTPROC_CALLBACK_ARGUMENTS
) Arguments
;
796 if (Common
->offPfn
&& Common
->Mod
)
797 { // Validate the module again.
798 if (!(len
= GetModuleFileNameW((HINSTANCE
)Common
->Mod
, module
, MAX_PATH
)) || len
>= MAX_PATH
)
800 ERR("Error check for module!\n");
804 if (Common
->Mod
&& !(mod
= GetModuleHandleW(module
)))
806 TRACE("Reloading Event Module.\n");
807 if (!(mod
= LoadLibraryExW(module
, NULL
, LOAD_WITH_ALTERED_SEARCH_PATH
)))
809 ERR("Failed to load Event Module.\n");
813 Loaded
= TRUE
; // Free it only when loaded.
819 TRACE("Loading Event Module. %S\n",module
);
820 Proc
= (WINEVENTPROC
)((char *)mod
+ Common
->offPfn
);
829 Common
->dwEventThread
,
830 Common
->dwmsEventTime
);
832 if (Loaded
) FreeLibrary(mod
);
834 return ZwCallbackReturn(NULL
, 0, STATUS_SUCCESS
);