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: dll/win32/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
;
216 ClientInfo
= GetWin32ClientInfo();
218 if (!ClientInfo
->phkCurrent
) return 0;
220 pHook
= DesktopPtrToUser(ClientInfo
->phkCurrent
);
222 if (!pHook
->phkNext
) return 0; // Nothing to do....
224 phkNext
= DesktopPtrToUser(pHook
->phkNext
);
226 if ( phkNext
->HookId
== WH_CALLWNDPROC
||
227 phkNext
->HookId
== WH_CALLWNDPROCRET
)
229 Save
= ClientInfo
->dwHookData
;
230 Flags
= ClientInfo
->CI_flags
& CI_CURTHPRHOOK
;
231 // wParam: If the message was sent by the current thread/process, it is
232 // nonzero; otherwise, it is zero.
233 if (wParam
) ClientInfo
->CI_flags
|= CI_CURTHPRHOOK
;
234 else ClientInfo
->CI_flags
&= ~CI_CURTHPRHOOK
;
236 if (phkNext
->HookId
== WH_CALLWNDPROC
)
238 PCWPSTRUCT pCWP
= (PCWPSTRUCT
)lParam
;
240 NtUserMessageCall( pCWP
->hwnd
,
250 PCWPRETSTRUCT pCWPR
= (PCWPRETSTRUCT
)lParam
;
252 ClientInfo
->dwHookData
= pCWPR
->lResult
;
254 NtUserMessageCall( pCWPR
->hwnd
,
262 ClientInfo
->CI_flags
^= ((ClientInfo
->CI_flags
^ Flags
) & CI_CURTHPRHOOK
);
263 ClientInfo
->dwHookData
= Save
;
266 lResult
= NtUserCallNextHookEx(Code
, wParam
, lParam
, pHook
->Ansi
);
277 SetWindowsHookW(int idHook
, HOOKPROC lpfn
)
279 DWORD ThreadId
= PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
);
280 return IntSetWindowsHook(idHook
, lpfn
, NULL
, ThreadId
, FALSE
);
281 // return NtUserSetWindowsHookAW(idHook, lpfn, FALSE);
289 SetWindowsHookA(int idHook
, HOOKPROC lpfn
)
291 DWORD ThreadId
= PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
);
292 return IntSetWindowsHook(idHook
, lpfn
, NULL
, ThreadId
, TRUE
);
293 // return NtUserSetWindowsHookAW(idHook, lpfn, TRUE);
301 DeregisterShellHookWindow(HWND hWnd
)
303 return NtUserxDeregisterShellHookWindow(hWnd
);
311 RegisterShellHookWindow(HWND hWnd
)
313 return NtUserxRegisterShellHookWindow(hWnd
);
321 UnhookWindowsHook ( int nCode
, HOOKPROC pfnFilterProc
)
323 return NtUserxUnhookWindowsHook(nCode
, pfnFilterProc
);
338 // "Servers call NotifyWinEvent to announce the event to the system after the
339 // event has occurred; they must never notify the system of an event before
340 // the event has occurred." msdn on NotifyWinEvent.
341 if (gpsi
->dwInstalledEventHooks
& GetMaskFromEvent(event
)) // Check to see.
342 NtUserNotifyWinEvent(event
, hwnd
, idObject
, idChild
);
353 HMODULE hmodWinEventProc
,
354 WINEVENTPROC pfnWinEventProc
,
360 WCHAR ModuleName
[MAX_PATH
];
361 UNICODE_STRING USModuleName
;
363 if ((hmodWinEventProc
!= NULL
) && (dwFlags
& WINEVENT_INCONTEXT
))
365 if (0 == GetModuleFileNameW(hmodWinEventProc
, ModuleName
, MAX_PATH
))
369 RtlInitUnicodeString(&USModuleName
, ModuleName
);
373 RtlInitUnicodeString(&USModuleName
, NULL
);
376 return NtUserSetWinEventHook(eventMin
,
391 IsWinEventHookInstalled(
394 if ((PTHREADINFO
)NtCurrentTeb()->Win32ThreadInfo
)
396 return (gpsi
->dwInstalledEventHooks
& GetMaskFromEvent(event
)) != 0;
412 return IntSetWindowsHook(idHook
, lpfn
, hMod
, dwThreadId
, TRUE
);
427 return IntSetWindowsHook(idHook
, lpfn
, hMod
, dwThreadId
, FALSE
);
433 PUNICODE_STRING pstrLibName
,
434 PUNICODE_STRING pstrInitFunc
,
441 ANSI_STRING InitFuncName
;
442 BOOL bResult
= FALSE
;
444 TRACE("ClientLoadLibrary: pid: %d, strLibraryName: %S, "
445 "strInitFuncName: %S, bUnload: %d, bApiHook:%d\n",
446 GetCurrentProcessId(),
448 pstrInitFunc
->Buffer
,
452 /* Check if we have to load the module */
453 if (bUnload
== FALSE
)
455 ASSERT(pstrLibName
->Buffer
!= NULL
);
458 hLibrary
= LoadLibrary(pstrLibName
->Buffer
);
466 /* There is nothing more to do for a global hook*/
470 /* Initialize the user api hook */
471 ASSERT(pstrInitFunc
->Buffer
);
472 Status
= RtlUnicodeStringToAnsiString(&InitFuncName
,
475 if (!NT_SUCCESS(Status
))
477 FreeLibrary(hLibrary
);
481 /* Get the address of the initialization routine */
482 pInitFunction
= GetProcAddress(hLibrary
, InitFuncName
.Buffer
);
485 /* Call the initialization routine */
486 bResult
= InitUserApiHook(hLibrary
, (USERAPIHOOKPROC
)pInitFunction
);
489 RtlFreeAnsiString(&InitFuncName
);
491 /* In case of error unload the library */
492 if (bResult
== FALSE
)
494 FreeLibrary(hLibrary
);
499 /* Cleanup user api hook before unloading */
502 hLibrary
= ghmodUserApiHook
;
503 bResult
= ClearUserApiHook(ghmodUserApiHook
);
505 /* Check if we can we unload it now */
508 /* Return success because we are going to free
509 the library in EndUserApiHook*/
515 /* Get the library handle from the name */
516 hLibrary
= GetModuleHandle(pstrLibName
->Buffer
);
517 if (hLibrary
== NULL
)
523 bResult
= FreeLibrary(hLibrary
);
530 User32CallClientLoadLibraryFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
533 PCLIENT_LOAD_LIBRARY_ARGUMENTS Argument
;
535 /* Retireve the callback parameters */
536 Argument
= (PCLIENT_LOAD_LIBRARY_ARGUMENTS
)Arguments
;
537 if(Argument
->strLibraryName
.Buffer
!= NULL
)
539 Argument
->strLibraryName
.Buffer
= (PWCHAR
)((ULONG_PTR
)Argument
->strLibraryName
.Buffer
+ (ULONG_PTR
)Argument
);
541 if(Argument
->strInitFuncName
.Buffer
!= NULL
)
543 Argument
->strInitFuncName
.Buffer
= (PWCHAR
)((ULONG_PTR
)Argument
->strInitFuncName
.Buffer
+ (ULONG_PTR
)Argument
);
546 /* Call the implementation of the callback */
547 bResult
= ClientLoadLibrary(&Argument
->strLibraryName
,
548 &Argument
->strInitFuncName
,
552 return ZwCallbackReturn(&bResult
, sizeof(HINSTANCE
), STATUS_SUCCESS
);
556 User32CallHookProcFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
558 PHOOKPROC_CALLBACK_ARGUMENTS Common
;
560 CBT_CREATEWNDW CbtCreatewndw
;
561 PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra
= NULL
;
562 KBDLLHOOKSTRUCT KeyboardLlData
, *pKeyboardLlData
;
563 MSLLHOOKSTRUCT MouseLlData
, *pMouseLlData
;
565 PMOUSEHOOKSTRUCT pMHook
;
569 LPCBTACTIVATESTRUCT pcbtas
;
577 Common
= (PHOOKPROC_CALLBACK_ARGUMENTS
) Arguments
;
580 // HookProc Justin Case module is from another process.
581 if (Common
->offPfn
&& Common
->Mod
)
583 if (!(mod
= GetModuleHandleW((LPCWSTR
)Common
->ModuleName
)))
585 TRACE("Reloading Hook Module.\n");
586 if (!(mod
= LoadLibraryExW((LPCWSTR
)Common
->ModuleName
, NULL
, LOAD_WITH_ALTERED_SEARCH_PATH
)))
588 ERR("Failed to load Hook Module.\n");
593 TRACE("Loading Hook Module.\n");
594 Proc
= (HOOKPROC
)((char *)mod
+ Common
->offPfn
);
598 switch(Common
->HookId
)
602 //ERR("WH_CBT: Code %d\n", Common->Code);
606 CbtCreatewndExtra
= (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS
)
607 ((PCHAR
) Common
+ Common
->lParam
);
608 RtlCopyMemory(&Csw
, &CbtCreatewndExtra
->Cs
, sizeof(CREATESTRUCTW
));
609 CbtCreatewndw
.lpcs
= &Csw
;
610 CbtCreatewndw
.hwndInsertAfter
= CbtCreatewndExtra
->WndInsertAfter
;
611 wParam
= Common
->wParam
;
612 lParam
= (LPARAM
) &CbtCreatewndw
;
613 //ERR("HCBT_CREATEWND: hWnd 0x%x Name 0x%x Class 0x%x\n", Common->wParam, Csw.lpszName, Csw.lpszClass);
615 case HCBT_CLICKSKIPPED
:
616 pMHook
= (PMOUSEHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
617 lParam
= (LPARAM
) pMHook
;
620 prl
= (PRECTL
)((PCHAR
) Common
+ Common
->lParam
);
621 lParam
= (LPARAM
) prl
;
624 pcbtas
= (LPCBTACTIVATESTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
625 lParam
= (LPARAM
) pcbtas
;
627 case HCBT_KEYSKIPPED
: /* The rest SEH support */
630 case HCBT_SYSCOMMAND
:
631 case HCBT_DESTROYWND
:
633 wParam
= Common
->wParam
;
634 lParam
= Common
->lParam
;
637 if (mod
) FreeLibrary(mod
);
638 ERR("HCBT_ not supported = %d\n", Common
->Code
);
639 return ZwCallbackReturn(NULL
, 0, STATUS_NOT_SUPPORTED
);
646 Result
= Proc(Common
->Code
, wParam
, lParam
);
648 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
656 ERR("Null Proc! Common = 0x%x, Proc = 0x%x\n",Common
,Proc
);
661 CbtCreatewndExtra
->WndInsertAfter
= CbtCreatewndw
.hwndInsertAfter
;
662 CbtCreatewndExtra
->Cs
.x
= CbtCreatewndw
.lpcs
->x
;
663 CbtCreatewndExtra
->Cs
.y
= CbtCreatewndw
.lpcs
->y
;
664 CbtCreatewndExtra
->Cs
.cx
= CbtCreatewndw
.lpcs
->cx
;
665 CbtCreatewndExtra
->Cs
.cy
= CbtCreatewndw
.lpcs
->cy
;
671 //ERR("WH_KEYBOARD_LL: Code %d, wParam %d\n",Common->Code,Common->wParam);
672 pKeyboardLlData
= (PKBDLLHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
673 RtlCopyMemory(&KeyboardLlData
, pKeyboardLlData
, sizeof(KBDLLHOOKSTRUCT
));
674 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) &KeyboardLlData
);
677 //ERR("WH_MOUSE_LL: Code %d, wParam %d\n",Common->Code,Common->wParam);
678 pMouseLlData
= (PMSLLHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
679 RtlCopyMemory(&MouseLlData
, pMouseLlData
, sizeof(MSLLHOOKSTRUCT
));
680 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) &MouseLlData
);
682 case WH_MOUSE
: /* SEH support */
683 pMHook
= (PMOUSEHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
686 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pMHook
);
688 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
695 // ERR("WH_CALLWNDPROC: Code %d, wParam %d\n",Common->Code,Common->wParam);
696 pCWP
= HeapAlloc(GetProcessHeap(), 0, ArgumentLength
- sizeof(HOOKPROC_CALLBACK_ARGUMENTS
));
697 RtlCopyMemory(pCWP
, (PCHAR
) Common
+ Common
->lParam
, sizeof(CWPSTRUCT
));
698 /* If more memory is reserved, then lParam is a pointer.
699 * Size of the buffer is stocked in the lParam member, and its content
700 * is at the end of the argument buffer */
701 if(ArgumentLength
> (sizeof(CWPSTRUCT
) + sizeof(HOOKPROC_CALLBACK_ARGUMENTS
)))
703 RtlCopyMemory((PCHAR
)pCWP
+ sizeof(CWPSTRUCT
),
704 (PCHAR
)Common
+ Common
->lParam
+ sizeof(CWPSTRUCT
),
706 pCWP
->lParam
= (LPARAM
)((PCHAR
)pCWP
+ sizeof(CWPSTRUCT
));
708 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pCWP
);
709 HeapFree(GetProcessHeap(), 0, pCWP
);
711 case WH_CALLWNDPROCRET
:
712 /* Almost the same as WH_CALLWNDPROC */
713 pCWPR
= HeapAlloc(GetProcessHeap(), 0, ArgumentLength
- sizeof(HOOKPROC_CALLBACK_ARGUMENTS
));
714 RtlCopyMemory(pCWPR
, (PCHAR
) Common
+ Common
->lParam
, sizeof(CWPRETSTRUCT
));
715 if(ArgumentLength
> (sizeof(CWPRETSTRUCT
) + sizeof(HOOKPROC_CALLBACK_ARGUMENTS
)))
717 RtlCopyMemory((PCHAR
)pCWPR
+ sizeof(CWPRETSTRUCT
),
718 (PCHAR
)Common
+ Common
->lParam
+ sizeof(CWPRETSTRUCT
),
720 pCWPR
->lParam
= (LPARAM
)((PCHAR
)pCWPR
+ sizeof(CWPRETSTRUCT
));
722 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pCWPR
);
723 HeapFree(GetProcessHeap(), 0, pCWPR
);
725 case WH_MSGFILTER
: /* All SEH support */
726 case WH_SYSMSGFILTER
:
728 pMsg
= (PMSG
)((PCHAR
) Common
+ Common
->lParam
);
729 pcMsg
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MSG
));
730 RtlCopyMemory(pcMsg
, pMsg
, sizeof(MSG
));
731 // ERR("pMsg %d pcMsg %d\n",pMsg->message, pcMsg->message);
734 Result
= Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pcMsg
);
736 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
741 if (!Hit
&& Common
->HookId
== WH_GETMESSAGE
)
742 RtlCopyMemory(pMsg
, pcMsg
, sizeof(MSG
));
743 HeapFree( GetProcessHeap(), 0, pcMsg
);
747 Result
= Proc(Common
->Code
, Common
->wParam
, Common
->lParam
);
749 case WH_FOREGROUNDIDLE
: /* <-- SEH support */
752 Result
= Proc(Common
->Code
, Common
->wParam
, Common
->lParam
);
754 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
761 if (mod
) FreeLibrary(mod
);
762 return ZwCallbackReturn(NULL
, 0, STATUS_NOT_SUPPORTED
);
766 ERR("Hook Exception! Id: %d, Code %d, Proc 0x%x\n",Common
->HookId
,Common
->Code
,Proc
);
768 if (mod
) FreeLibrary(mod
);
769 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
773 User32CallEventProcFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
775 PEVENTPROC_CALLBACK_ARGUMENTS Common
;
777 Common
= (PEVENTPROC_CALLBACK_ARGUMENTS
) Arguments
;
779 Common
->Proc(Common
->hook
,
784 Common
->dwEventThread
,
785 Common
->dwmsEventTime
);
787 return ZwCallbackReturn(NULL
, 0, STATUS_SUCCESS
);