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
->MessageQueue
,
125 if (!NT_SUCCESS(Status
))
127 ExFreePoolWithTag(pEP
, TAG_HOOK
);
129 return NT_SUCCESS(Status
) ? uResult
: 0;
135 IntRemoveEvent(PEVENTHOOK pEH
)
139 TRACE("IntRemoveEvent pEH 0x%x\n",pEH
);
140 KeEnterCriticalRegion();
141 RemoveEntryList(&pEH
->Chain
);
142 GlobalEvents
->Counts
--;
143 if (!GlobalEvents
->Counts
) gpsi
->dwInstalledEventHooks
= 0;
144 UserDeleteObject(UserHMGetHandle(pEH
), TYPE_WINEVENTHOOK
);
145 KeLeaveCriticalRegion();
153 EVENT_DestroyThreadEvents(PETHREAD Thread
)
159 pti
= Thread
->Tcb
.Win32Thread
;
162 if (!GlobalEvents
|| !GlobalEvents
->Counts
) return;
164 pLE
= GlobalEvents
->Events
.Flink
;
165 if (IsListEmpty(pLE
)) return;
167 pEH
= CONTAINING_RECORD(pLE
, EVENTHOOK
, Chain
);
170 if (IsListEmpty(pLE
)) break;
172 pLE
= pEH
->Chain
.Flink
;
173 if (pEH
->head
.pti
== pti
)
177 pEH
= CONTAINING_RECORD(pLE
, EVENTHOOK
, Chain
);
178 } while (pLE
!= &GlobalEvents
->Events
);
183 /* FUNCTIONS *****************************************************************/
186 // Dispatch MsgQueue Event Call processor!
190 co_EVENT_CallEvents( DWORD event
,
197 PEVENTPACK pEP
= (PEVENTPACK
)idChild
;
201 Result
= co_IntCallEventProc( UserHMGetHandle(pEH
),
206 PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
),
207 (DWORD
)EngGetTickCount(),
210 ExFreePoolWithTag(pEP
, TAG_HOOK
);
225 PTHREADINFO pti
, ptiCurrent
;
227 TRACE("IntNotifyWinEvent GlobalEvents = 0x%x pWnd 0x%x\n",GlobalEvents
, pWnd
);
229 if (!GlobalEvents
|| !GlobalEvents
->Counts
) return;
231 if (pWnd
&& pWnd
->state
& WNDS_DESTROYED
) return;
233 ptiCurrent
= PsGetCurrentThreadWin32Thread();
235 if (pWnd
&& flags
& WEF_SETBYWNDPTI
)
236 pti
= pWnd
->head
.pti
;
240 pLE
= GlobalEvents
->Events
.Flink
;
241 pEH
= CONTAINING_RECORD(pLE
, EVENTHOOK
, Chain
);
245 UserReferenceObject(pEH
);
246 // Must be inside the event window.
247 if ( (pEH
->eventMin
<= Event
) && (pEH
->eventMax
>= Event
))
249 // if all process || all thread || other thread same process
250 // if ^skip own thread && ((Pid && CPid == Pid && ^skip own process) || all process)
251 if ( (!pEH
->idProcess
|| pEH
->idProcess
== PtrToUint(pti
->pEThread
->Cid
.UniqueProcess
)) &&
252 (!(pEH
->Flags
& WINEVENT_SKIPOWNPROCESS
) || pEH
->head
.pti
->ppi
!= pti
->ppi
) &&
253 (!pEH
->idThread
|| pEH
->idThread
== PtrToUint(pti
->pEThread
->Cid
.UniqueThread
)) &&
254 (!(pEH
->Flags
& WINEVENT_SKIPOWNTHREAD
) || pEH
->head
.pti
!= pti
) &&
255 pEH
->head
.pti
->rpdesk
== ptiCurrent
->rpdesk
) // Same as hooks.
257 // Send message to the thread if pEH is not current.
258 if (pEH
->head
.pti
!= ptiCurrent
)
260 ERR("Global Event 0x%x, idObject %d\n", Event
, idObject
);
261 IntCallLowLevelEvent( pEH
,
263 UserHMGetHandle(pWnd
),
269 ERR("Local Event 0x%x, idObject %d\n", Event
, idObject
);
270 co_IntCallEventProc( UserHMGetHandle(pEH
),
272 UserHMGetHandle(pWnd
),
275 PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
),
276 (DWORD
)EngGetTickCount(),
281 UserDereferenceObject(pEH
);
282 pLE
= pEH
->Chain
.Flink
;
283 pEH
= CONTAINING_RECORD(pLE
, EVENTHOOK
, Chain
);
284 } while (pLE
!= &GlobalEvents
->Events
);
289 NtUserNotifyWinEvent(
296 USER_REFERENCE_ENTRY Ref
;
297 UserEnterExclusive();
300 if (hWnd
&& (hWnd
!= INVALID_HANDLE_VALUE
))
302 Window
= UserGetWindowObject(hWnd
);
310 if (gpsi
->dwInstalledEventHooks
& GetMaskFromEvent(Event
))
312 if (Window
) UserRefObjectCo(Window
, &Ref
);
313 IntNotifyWinEvent( Event
, Window
, idObject
, idChild
, WEF_SETBYWNDPTI
);
314 if (Window
) UserDerefObjectCo(Window
);
321 NtUserSetWinEventHook(
324 HMODULE hmodWinEventProc
,
325 PUNICODE_STRING puString
,
326 WINEVENTPROC lpfnWinEventProc
,
332 HWINEVENTHOOK Ret
= NULL
;
335 PETHREAD Thread
= NULL
;
337 TRACE("NtUserSetWinEventHook hmod 0x%x, pfn 0x%x\n",hmodWinEventProc
, lpfnWinEventProc
);
339 UserEnterExclusive();
343 GlobalEvents
= ExAllocatePoolWithTag(PagedPool
, sizeof(EVENTTABLE
), TAG_HOOK
);
344 if (GlobalEvents
== NULL
)
346 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
349 GlobalEvents
->Counts
= 0;
350 InitializeListHead(&GlobalEvents
->Events
);
353 if (eventMin
> eventMax
)
355 EngSetLastError(ERROR_INVALID_HOOK_FILTER
);
359 if (!lpfnWinEventProc
)
361 EngSetLastError(ERROR_INVALID_FILTER_PROC
);
365 if ((dwflags
& WINEVENT_INCONTEXT
) && !hmodWinEventProc
)
367 EngSetLastError(ERROR_HOOK_NEEDS_HMOD
);
373 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)idThread
, &Thread
);
374 if (!NT_SUCCESS(Status
))
376 EngSetLastError(ERROR_INVALID_THREAD_ID
);
380 // Creator, pti is set here.
381 pEH
= UserCreateObject(gHandleTable
, NULL
, NULL
, &Handle
, TYPE_WINEVENTHOOK
, sizeof(EVENTHOOK
));
384 InsertTailList(&GlobalEvents
->Events
, &pEH
->Chain
);
385 GlobalEvents
->Counts
++;
387 UserHMGetHandle(pEH
) = Handle
;
388 pEH
->eventMin
= eventMin
;
389 pEH
->eventMax
= eventMax
;
390 pEH
->idProcess
= idProcess
; // These are cmp'ed
391 pEH
->idThread
= idThread
; // "
392 pEH
->Flags
= dwflags
;
394 If WINEVENT_INCONTEXT, set offset from hmod and proc. Save ihmod from
395 the atom index table where the hmod data is saved to be recalled later
396 if fSync set by WINEVENT_INCONTEXT.
397 If WINEVENT_OUTOFCONTEXT just use proc..
400 if (NULL
!= hmodWinEventProc
)
402 pEH
->offPfn
= (ULONG_PTR
)((char *)lpfnWinEventProc
- (char *)hmodWinEventProc
);
403 pEH
->ihmod
= (INT
)hmodWinEventProc
;
404 pEH
->Proc
= lpfnWinEventProc
;
407 pEH
->Proc
= lpfnWinEventProc
;
409 UserDereferenceObject(pEH
);
412 IntSetSrvEventMask( eventMin
, eventMax
);
416 if (Thread
) ObDereferenceObject(Thread
);
423 NtUserUnhookWinEvent(
424 HWINEVENTHOOK hWinEventHook
)
429 UserEnterExclusive();
431 pEH
= (PEVENTHOOK
)UserGetObject(gHandleTable
, hWinEventHook
, TYPE_WINEVENTHOOK
);
434 Ret
= IntRemoveEvent(pEH
);