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
;
575 Common
= (PHOOKPROC_CALLBACK_ARGUMENTS
) Arguments
;
577 switch(Common
->HookId
)
581 //ERR("WH_CBT: Code %d\n", Common->Code);
585 CbtCreatewndExtra
= (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS
)
586 ((PCHAR
) Common
+ Common
->lParam
);
587 RtlCopyMemory(&Csw
, &CbtCreatewndExtra
->Cs
, sizeof(CREATESTRUCTW
));
588 CbtCreatewndw
.lpcs
= &Csw
;
589 CbtCreatewndw
.hwndInsertAfter
= CbtCreatewndExtra
->WndInsertAfter
;
590 wParam
= Common
->wParam
;
591 lParam
= (LPARAM
) &CbtCreatewndw
;
592 //ERR("HCBT_CREATEWND: hWnd 0x%x Name 0x%x Class 0x%x\n", Common->wParam, Csw.lpszName, Csw.lpszClass);
594 case HCBT_CLICKSKIPPED
:
595 pMHook
= (PMOUSEHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
596 lParam
= (LPARAM
) pMHook
;
599 prl
= (PRECTL
)((PCHAR
) Common
+ Common
->lParam
);
600 lParam
= (LPARAM
) prl
;
603 pcbtas
= (LPCBTACTIVATESTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
604 lParam
= (LPARAM
) pcbtas
;
606 case HCBT_KEYSKIPPED
: /* The rest SEH support */
609 case HCBT_SYSCOMMAND
:
610 case HCBT_DESTROYWND
:
612 wParam
= Common
->wParam
;
613 lParam
= Common
->lParam
;
616 ERR("HCBT_ not supported = %d\n", Common
->Code
);
617 return ZwCallbackReturn(NULL
, 0, STATUS_NOT_SUPPORTED
);
624 Result
= Common
->Proc(Common
->Code
, wParam
, lParam
);
626 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
634 ERR("Null Proc! Common = 0x%x, Proc = 0x%x\n",Common
,Common
->Proc
);
639 CbtCreatewndExtra
->WndInsertAfter
= CbtCreatewndw
.hwndInsertAfter
;
640 CbtCreatewndExtra
->Cs
.x
= CbtCreatewndw
.lpcs
->x
;
641 CbtCreatewndExtra
->Cs
.y
= CbtCreatewndw
.lpcs
->y
;
642 CbtCreatewndExtra
->Cs
.cx
= CbtCreatewndw
.lpcs
->cx
;
643 CbtCreatewndExtra
->Cs
.cy
= CbtCreatewndw
.lpcs
->cy
;
649 //ERR("WH_KEYBOARD_LL: Code %d, wParam %d\n",Common->Code,Common->wParam);
650 pKeyboardLlData
= (PKBDLLHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
651 RtlCopyMemory(&KeyboardLlData
, pKeyboardLlData
, sizeof(KBDLLHOOKSTRUCT
));
652 Result
= Common
->Proc(Common
->Code
, Common
->wParam
, (LPARAM
) &KeyboardLlData
);
655 //ERR("WH_MOUSE_LL: Code %d, wParam %d\n",Common->Code,Common->wParam);
656 pMouseLlData
= (PMSLLHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
657 RtlCopyMemory(&MouseLlData
, pMouseLlData
, sizeof(MSLLHOOKSTRUCT
));
658 Result
= Common
->Proc(Common
->Code
, Common
->wParam
, (LPARAM
) &MouseLlData
);
660 case WH_MOUSE
: /* SEH support */
661 pMHook
= (PMOUSEHOOKSTRUCT
)((PCHAR
) Common
+ Common
->lParam
);
664 Result
= Common
->Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pMHook
);
666 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
673 // ERR("WH_CALLWNDPROC: Code %d, wParam %d\n",Common->Code,Common->wParam);
674 pCWP
= HeapAlloc(GetProcessHeap(), 0, ArgumentLength
- sizeof(HOOKPROC_CALLBACK_ARGUMENTS
));
675 RtlCopyMemory(pCWP
, (PCHAR
) Common
+ Common
->lParam
, sizeof(CWPSTRUCT
));
676 /* If more memory is reserved, then lParam is a pointer.
677 * Size of the buffer is stocked in the lParam member, and its content
678 * is at the end of the argument buffer */
679 if(ArgumentLength
> (sizeof(CWPSTRUCT
) + sizeof(HOOKPROC_CALLBACK_ARGUMENTS
)))
681 RtlCopyMemory((PCHAR
)pCWP
+ sizeof(CWPSTRUCT
),
682 (PCHAR
)Common
+ Common
->lParam
+ sizeof(CWPSTRUCT
),
684 pCWP
->lParam
= (LPARAM
)((PCHAR
)pCWP
+ sizeof(CWPSTRUCT
));
686 Result
= Common
->Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pCWP
);
687 HeapFree(GetProcessHeap(), 0, pCWP
);
689 case WH_CALLWNDPROCRET
:
690 /* Almost the same as WH_CALLWNDPROC */
691 pCWPR
= HeapAlloc(GetProcessHeap(), 0, ArgumentLength
- sizeof(HOOKPROC_CALLBACK_ARGUMENTS
));
692 RtlCopyMemory(pCWPR
, (PCHAR
) Common
+ Common
->lParam
, sizeof(CWPRETSTRUCT
));
693 if(ArgumentLength
> (sizeof(CWPRETSTRUCT
) + sizeof(HOOKPROC_CALLBACK_ARGUMENTS
)))
695 RtlCopyMemory((PCHAR
)pCWPR
+ sizeof(CWPRETSTRUCT
),
696 (PCHAR
)Common
+ Common
->lParam
+ sizeof(CWPRETSTRUCT
),
698 pCWPR
->lParam
= (LPARAM
)((PCHAR
)pCWPR
+ sizeof(CWPRETSTRUCT
));
700 Result
= Common
->Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pCWPR
);
701 HeapFree(GetProcessHeap(), 0, pCWPR
);
703 case WH_MSGFILTER
: /* All SEH support */
704 case WH_SYSMSGFILTER
:
706 pMsg
= (PMSG
)((PCHAR
) Common
+ Common
->lParam
);
707 pcMsg
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MSG
));
708 RtlCopyMemory(pcMsg
, pMsg
, sizeof(MSG
));
709 // ERR("pMsg %d pcMsg %d\n",pMsg->message, pcMsg->message);
712 Result
= Common
->Proc(Common
->Code
, Common
->wParam
, (LPARAM
) pcMsg
);
714 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
719 if (!Hit
&& Common
->HookId
== WH_GETMESSAGE
)
720 RtlCopyMemory(pMsg
, pcMsg
, sizeof(MSG
));
721 HeapFree( GetProcessHeap(), 0, pcMsg
);
725 Result
= Common
->Proc(Common
->Code
, Common
->wParam
, Common
->lParam
);
727 case WH_FOREGROUNDIDLE
: /* <-- SEH support */
730 Result
= Common
->Proc(Common
->Code
, Common
->wParam
, Common
->lParam
);
732 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
739 return ZwCallbackReturn(NULL
, 0, STATUS_NOT_SUPPORTED
);
743 ERR("Hook Exception! Id: %d, Code %d, Proc 0x%x\n",Common
->HookId
,Common
->Code
,Common
->Proc
);
745 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
749 User32CallEventProcFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
751 PEVENTPROC_CALLBACK_ARGUMENTS Common
;
753 Common
= (PEVENTPROC_CALLBACK_ARGUMENTS
) Arguments
;
755 Common
->Proc(Common
->hook
,
760 Common
->dwEventThread
,
761 Common
->dwmsEventTime
);
763 return ZwCallbackReturn(NULL
, 0, STATUS_SUCCESS
);