2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window event handlers
5 * FILE: subsystems/win32/win32k/ntuser/event.c
6 * PROGRAMER: James Tabor (james.tabor@rectos.org)
10 DBG_DEFAULT_CHANNEL(UserEvent
);
12 typedef struct _EVENTPACK
17 } EVENTPACK
, *PEVENTPACK
;
19 static PEVENTTABLE GlobalEvents
= NULL
;
21 /* PRIVATE FUNCTIONS *********************************************************/
26 GetMaskFromEvent(DWORD Event
)
30 if ( Event
> EVENT_OBJECT_STATECHANGE
)
32 if ( Event
== EVENT_OBJECT_LOCATIONCHANGE
) return SRV_EVENT_LOCATIONCHANGE
;
33 if ( Event
== EVENT_OBJECT_NAMECHANGE
) return SRV_EVENT_NAMECHANGE
;
34 if ( Event
== EVENT_OBJECT_VALUECHANGE
) return SRV_EVENT_VALUECHANGE
;
35 return SRV_EVENT_CREATE
;
38 if ( Event
== EVENT_OBJECT_STATECHANGE
) return SRV_EVENT_STATECHANGE
;
40 Ret
= SRV_EVENT_RUNNING
;
42 if ( Event
< EVENT_SYSTEM_MENUSTART
) return SRV_EVENT_CREATE
;
44 if ( Event
<= EVENT_SYSTEM_MENUPOPUPEND
)
50 if ( Event
<= EVENT_CONSOLE_CARET
-1 ) return SRV_EVENT_CREATE
;
51 if ( Event
<= EVENT_CONSOLE_END_APPLICATION
) return SRV_EVENT_END_APPLICATION
;
52 if ( Event
!= EVENT_OBJECT_FOCUS
) return SRV_EVENT_CREATE
;
60 IntSetSrvEventMask( UINT EventMin
, UINT EventMax
)
63 TRACE("SetSrvEventMask 1\n");
64 for ( event
= EventMin
; event
<= EventMax
; event
++)
66 if ((event
>= EVENT_SYSTEM_SOUND
&& event
<= EVENT_SYSTEM_MINIMIZEEND
) ||
67 (event
>= EVENT_CONSOLE_CARET
&& event
<= EVENT_CONSOLE_END_APPLICATION
) ||
68 (event
>= EVENT_OBJECT_CREATE
&& event
<= EVENT_OBJECT_ACCELERATORCHANGE
))
70 gpsi
->dwInstalledEventHooks
|= GetMaskFromEvent(event
);
72 if (event
> EVENT_SYSTEM_MINIMIZEEND
&& event
< EVENT_CONSOLE_CARET
)
74 event
= EVENT_CONSOLE_CARET
-1;
75 gpsi
->dwInstalledEventHooks
|= GetMaskFromEvent(event
);
77 if (event
> EVENT_CONSOLE_END_APPLICATION
&& event
< EVENT_OBJECT_CREATE
)
79 event
= EVENT_OBJECT_CREATE
-1;
80 gpsi
->dwInstalledEventHooks
|= GetMaskFromEvent(event
);
82 if (event
> EVENT_OBJECT_ACCELERATORCHANGE
&& event
< EVENT_MAX
)
85 gpsi
->dwInstalledEventHooks
|= GetMaskFromEvent(event
);
89 if (!gpsi
->dwInstalledEventHooks
)
90 gpsi
->dwInstalledEventHooks
|= SRV_EVENT_RUNNING
; // Set something.
91 TRACE("SetSrvEventMask 2 : %x\n", gpsi
->dwInstalledEventHooks
);
97 IntCallLowLevelEvent( PEVENTHOOK pEH
,
105 ULONG_PTR uResult
= 0;
107 pEP
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(EVENTPACK
), TAG_HOOK
);
111 pEP
->idObject
= idObject
;
112 pEP
->idChild
= idChild
;
114 /* FIXME: Should get timeout from
115 * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
116 Status
= co_MsqSendMessage( pEH
->head
.pti
,
125 if (!NT_SUCCESS(Status
))
127 ExFreePoolWithTag(pEP
, TAG_HOOK
);
129 return NT_SUCCESS(Status
) ? uResult
: 0;
133 IntRemoveEvent(PVOID Object
)
135 PEVENTHOOK pEH
= Object
;
138 TRACE("IntRemoveEvent pEH %p\n", pEH
);
139 KeEnterCriticalRegion();
140 RemoveEntryList(&pEH
->Chain
);
141 GlobalEvents
->Counts
--;
142 if (!GlobalEvents
->Counts
) gpsi
->dwInstalledEventHooks
= 0;
143 UserDeleteObject(UserHMGetHandle(pEH
), TYPE_WINEVENTHOOK
);
144 KeLeaveCriticalRegion();
150 /* FUNCTIONS *****************************************************************/
153 // Dispatch MsgQueue Event Call processor!
157 co_EVENT_CallEvents( DWORD event
,
164 PEVENTPACK pEP
= (PEVENTPACK
)idChild
;
168 Result
= co_IntCallEventProc( UserHMGetHandle(pEH
),
173 PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
),
174 (DWORD
)EngGetTickCount(),
177 ExFreePoolWithTag(pEP
, TAG_HOOK
);
192 PTHREADINFO pti
, ptiCurrent
;
194 TRACE("IntNotifyWinEvent GlobalEvents = %p pWnd %p\n", GlobalEvents
, pWnd
);
196 if (!GlobalEvents
|| !GlobalEvents
->Counts
) return;
198 if (pWnd
&& pWnd
->state
& WNDS_DESTROYED
) return;
200 ptiCurrent
= PsGetCurrentThreadWin32Thread();
202 if (pWnd
&& flags
& WEF_SETBYWNDPTI
)
203 pti
= pWnd
->head
.pti
;
207 pLE
= GlobalEvents
->Events
.Flink
;
208 pEH
= CONTAINING_RECORD(pLE
, EVENTHOOK
, Chain
);
212 UserReferenceObject(pEH
);
213 // Must be inside the event window.
214 if ( (pEH
->eventMin
<= Event
) && (pEH
->eventMax
>= Event
))
216 // if all process || all thread || other thread same process
217 // if ^skip own thread && ((Pid && CPid == Pid && ^skip own process) || all process)
218 if ( (!pEH
->idProcess
|| pEH
->idProcess
== PtrToUint(pti
->pEThread
->Cid
.UniqueProcess
)) &&
219 (!(pEH
->Flags
& WINEVENT_SKIPOWNPROCESS
) || pEH
->head
.pti
->ppi
!= pti
->ppi
) &&
220 (!pEH
->idThread
|| pEH
->idThread
== PtrToUint(pti
->pEThread
->Cid
.UniqueThread
)) &&
221 (!(pEH
->Flags
& WINEVENT_SKIPOWNTHREAD
) || pEH
->head
.pti
!= pti
) &&
222 pEH
->head
.pti
->rpdesk
== ptiCurrent
->rpdesk
) // Same as hooks.
224 // Send message to the thread if pEH is not current.
225 if (pEH
->head
.pti
!= ptiCurrent
)
227 ERR("Global Event 0x%x, idObject %d\n", Event
, idObject
);
228 IntCallLowLevelEvent( pEH
,
230 pWnd
? UserHMGetHandle(pWnd
) : NULL
,
236 ERR("Local Event 0x%x, idObject %d\n", Event
, idObject
);
237 co_IntCallEventProc( UserHMGetHandle(pEH
),
239 pWnd
? UserHMGetHandle(pWnd
) : NULL
,
242 PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
),
243 (DWORD
)EngGetTickCount(),
248 UserDereferenceObject(pEH
);
249 pLE
= pEH
->Chain
.Flink
;
250 pEH
= CONTAINING_RECORD(pLE
, EVENTHOOK
, Chain
);
251 } while (pLE
!= &GlobalEvents
->Events
);
256 NtUserNotifyWinEvent(
263 USER_REFERENCE_ENTRY Ref
;
264 UserEnterExclusive();
267 if (hWnd
&& (hWnd
!= INVALID_HANDLE_VALUE
))
269 Window
= UserGetWindowObject(hWnd
);
277 if (gpsi
->dwInstalledEventHooks
& GetMaskFromEvent(Event
))
279 if (Window
) UserRefObjectCo(Window
, &Ref
);
280 IntNotifyWinEvent( Event
, Window
, idObject
, idChild
, WEF_SETBYWNDPTI
);
281 if (Window
) UserDerefObjectCo(Window
);
288 NtUserSetWinEventHook(
291 HMODULE hmodWinEventProc
,
292 PUNICODE_STRING puString
,
293 WINEVENTPROC lpfnWinEventProc
,
299 HWINEVENTHOOK Ret
= NULL
;
304 TRACE("NtUserSetWinEventHook hmod %p, pfn %p\n", hmodWinEventProc
, lpfnWinEventProc
);
306 UserEnterExclusive();
310 GlobalEvents
= ExAllocatePoolWithTag(PagedPool
, sizeof(EVENTTABLE
), TAG_HOOK
);
311 if (GlobalEvents
== NULL
)
313 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
316 GlobalEvents
->Counts
= 0;
317 InitializeListHead(&GlobalEvents
->Events
);
320 if (eventMin
> eventMax
)
322 EngSetLastError(ERROR_INVALID_HOOK_FILTER
);
326 if (!lpfnWinEventProc
)
328 EngSetLastError(ERROR_INVALID_FILTER_PROC
);
332 if ((dwflags
& WINEVENT_INCONTEXT
) && !hmodWinEventProc
)
334 EngSetLastError(ERROR_HOOK_NEEDS_HMOD
);
341 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)idThread
, &Thread
);
342 if (!NT_SUCCESS(Status
))
344 EngSetLastError(ERROR_INVALID_THREAD_ID
);
347 pti
= PsGetThreadWin32Thread(Thread
);
348 ObDereferenceObject(Thread
);
352 pti
= PsGetCurrentThreadWin32Thread();
354 // Creator, pti is set here.
355 pEH
= UserCreateObject(gHandleTable
, NULL
, pti
, &Handle
, TYPE_WINEVENTHOOK
, sizeof(EVENTHOOK
));
358 InsertTailList(&GlobalEvents
->Events
, &pEH
->Chain
);
359 GlobalEvents
->Counts
++;
361 UserHMGetHandle(pEH
) = Handle
;
362 pEH
->eventMin
= eventMin
;
363 pEH
->eventMax
= eventMax
;
364 pEH
->idProcess
= idProcess
; // These are cmp'ed
365 pEH
->idThread
= idThread
; // "
366 pEH
->Flags
= dwflags
;
368 If WINEVENT_INCONTEXT, set offset from hmod and proc. Save ihmod from
369 the atom index table where the hmod data is saved to be recalled later
370 if fSync set by WINEVENT_INCONTEXT.
371 If WINEVENT_OUTOFCONTEXT just use proc..
374 if (NULL
!= hmodWinEventProc
)
376 pEH
->offPfn
= (ULONG_PTR
)((char *)lpfnWinEventProc
- (char *)hmodWinEventProc
);
377 pEH
->ihmod
= (INT
)hmodWinEventProc
;
378 pEH
->Proc
= lpfnWinEventProc
;
381 pEH
->Proc
= lpfnWinEventProc
;
383 UserDereferenceObject(pEH
);
386 IntSetSrvEventMask( eventMin
, eventMax
);
396 NtUserUnhookWinEvent(
397 HWINEVENTHOOK hWinEventHook
)
402 UserEnterExclusive();
404 pEH
= (PEVENTHOOK
)UserGetObject(gHandleTable
, hWinEventHook
, TYPE_WINEVENTHOOK
);
407 Ret
= IntRemoveEvent(pEH
);