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)
14 typedef struct _EVENTPACK
19 } EVENTPACK
, *PEVENTPACK
;
21 static PEVENTTABLE GlobalEvents
= NULL
;
23 /* PRIVATE FUNCTIONS *********************************************************/
28 GetMaskFromEvent(DWORD Event
)
32 if ( Event
> EVENT_OBJECT_STATECHANGE
)
34 if ( Event
== EVENT_OBJECT_LOCATIONCHANGE
) return SRV_EVENT_LOCATIONCHANGE
;
35 if ( Event
== EVENT_OBJECT_NAMECHANGE
) return SRV_EVENT_NAMECHANGE
;
36 if ( Event
== EVENT_OBJECT_VALUECHANGE
) return SRV_EVENT_VALUECHANGE
;
37 return SRV_EVENT_CREATE
;
40 if ( Event
== EVENT_OBJECT_STATECHANGE
) return SRV_EVENT_STATECHANGE
;
42 Ret
= SRV_EVENT_RUNNING
;
44 if ( Event
< EVENT_SYSTEM_MENUSTART
) return SRV_EVENT_CREATE
;
46 if ( Event
<= EVENT_SYSTEM_MENUPOPUPEND
)
52 if ( Event
<= EVENT_CONSOLE_CARET
-1 ) return SRV_EVENT_CREATE
;
53 if ( Event
<= EVENT_CONSOLE_END_APPLICATION
) return SRV_EVENT_END_APPLICATION
;
54 if ( Event
!= EVENT_OBJECT_FOCUS
) return SRV_EVENT_CREATE
;
62 IntSetSrvEventMask( UINT EventMin
, UINT EventMax
)
65 DPRINT("SetSrvEventMask 1\n");
66 for ( event
= EventMin
; event
<= EventMax
; event
++)
68 if ((event
>= EVENT_SYSTEM_SOUND
&& event
<= EVENT_SYSTEM_MINIMIZEEND
) ||
69 (event
>= EVENT_CONSOLE_CARET
&& event
<= EVENT_CONSOLE_END_APPLICATION
) ||
70 (event
>= EVENT_OBJECT_CREATE
&& event
<= EVENT_OBJECT_ACCELERATORCHANGE
))
72 gpsi
->dwInstalledEventHooks
|= GetMaskFromEvent(event
);
74 if (event
> EVENT_SYSTEM_MINIMIZEEND
&& event
< EVENT_CONSOLE_CARET
)
76 event
= EVENT_CONSOLE_CARET
-1;
77 gpsi
->dwInstalledEventHooks
|= GetMaskFromEvent(event
);
79 if (event
> EVENT_CONSOLE_END_APPLICATION
&& event
< EVENT_OBJECT_CREATE
)
81 event
= EVENT_OBJECT_CREATE
-1;
82 gpsi
->dwInstalledEventHooks
|= GetMaskFromEvent(event
);
84 if (event
> EVENT_OBJECT_ACCELERATORCHANGE
&& event
< EVENT_MAX
)
87 gpsi
->dwInstalledEventHooks
|= GetMaskFromEvent(event
);
91 if (!gpsi
->dwInstalledEventHooks
)
92 gpsi
->dwInstalledEventHooks
|= SRV_EVENT_RUNNING
; // Set something.
93 DPRINT("SetSrvEventMask 2 : %x\n", gpsi
->dwInstalledEventHooks
);
99 IntCallLowLevelEvent( PEVENTHOOK pEH
,
107 ULONG_PTR uResult
= 0;
109 pEP
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(EVENTPACK
), TAG_HOOK
);
113 pEP
->idObject
= idObject
;
114 pEP
->idChild
= idChild
;
116 /* FIXME should get timeout from
117 * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
118 Status
= co_MsqSendMessage( pEH
->head
.pti
->MessageQueue
,
127 if (!NT_SUCCESS(Status
))
129 ExFreePoolWithTag(pEP
, TAG_HOOK
);
131 return NT_SUCCESS(Status
) ? uResult
: 0;
137 IntRemoveEvent(PEVENTHOOK pEH
)
141 DPRINT("IntRemoveEvent pEH 0x%x\n",pEH
);
142 KeEnterCriticalRegion();
143 RemoveEntryList(&pEH
->Chain
);
144 GlobalEvents
->Counts
--;
145 if (!GlobalEvents
->Counts
) gpsi
->dwInstalledEventHooks
= 0;
146 UserDeleteObject(UserHMGetHandle(pEH
), otEvent
);
147 KeLeaveCriticalRegion();
155 EVENT_DestroyThreadEvents(PETHREAD Thread
)
161 pti
= Thread
->Tcb
.Win32Thread
;
164 if (!GlobalEvents
|| !GlobalEvents
->Counts
) return;
166 pLE
= GlobalEvents
->Events
.Flink
;
167 if (IsListEmpty(pLE
)) return;
169 pEH
= CONTAINING_RECORD(pLE
, EVENTHOOK
, Chain
);
172 if (IsListEmpty(pLE
)) break;
174 pLE
= pEH
->Chain
.Flink
;
175 if (pEH
->head
.pti
== pti
)
179 pEH
= CONTAINING_RECORD(pLE
, EVENTHOOK
, Chain
);
180 } while (pLE
!= &GlobalEvents
->Events
);
185 /* FUNCTIONS *****************************************************************/
188 // Dispatch MsgQueue Event Call processor!
192 co_EVENT_CallEvents( DWORD event
,
199 PEVENTPACK pEP
= (PEVENTPACK
)idChild
;
203 Result
= co_IntCallEventProc( UserHMGetHandle(pEH
),
208 PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
),
209 (DWORD
)EngGetTickCount(),
212 ExFreePoolWithTag(pEP
, TAG_HOOK
);
227 PTHREADINFO pti
, ptiCurrent
;
229 DPRINT("IntNotifyWinEvent GlobalEvents = 0x%x pWnd 0x%x\n",GlobalEvents
, pWnd
);
231 if (!GlobalEvents
|| !GlobalEvents
->Counts
) return;
233 if (pWnd
&& pWnd
->state
& WNDS_DESTROYED
) return;
235 ptiCurrent
= PsGetCurrentThreadWin32Thread();
237 if (pWnd
&& flags
& WEF_SETBYWNDPTI
)
238 pti
= pWnd
->head
.pti
;
242 pLE
= GlobalEvents
->Events
.Flink
;
243 pEH
= CONTAINING_RECORD(pLE
, EVENTHOOK
, Chain
);
247 UserReferenceObject(pEH
);
248 // Must be inside the event window.
249 if ( (pEH
->eventMin
<= Event
) && (pEH
->eventMax
>= Event
))
251 // if all process || all thread || other thread same process
252 // if ^skip own thread && ((Pid && CPid == Pid && ^skip own process) || all process)
253 if ( (!pEH
->idProcess
|| pEH
->idProcess
== PtrToUint(pti
->pEThread
->Cid
.UniqueProcess
)) &&
254 (!(pEH
->Flags
& WINEVENT_SKIPOWNPROCESS
) || pEH
->head
.pti
->ppi
!= pti
->ppi
) &&
255 (!pEH
->idThread
|| pEH
->idThread
== PtrToUint(pti
->pEThread
->Cid
.UniqueThread
)) &&
256 (!(pEH
->Flags
& WINEVENT_SKIPOWNTHREAD
) || pEH
->head
.pti
!= pti
) &&
257 pEH
->head
.pti
->rpdesk
== ptiCurrent
->rpdesk
) // Same as hooks.
259 // Send message to the thread if pEH is not current.
260 if (pEH
->head
.pti
!= ptiCurrent
)
262 DPRINT1("Global Event 0x%x, idObject %d\n", Event
, idObject
);
263 IntCallLowLevelEvent( pEH
,
265 UserHMGetHandle(pWnd
),
271 DPRINT1("Local Event 0x%x, idObject %d\n", Event
, idObject
);
272 co_IntCallEventProc( UserHMGetHandle(pEH
),
274 UserHMGetHandle(pWnd
),
277 PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
),
278 (DWORD
)EngGetTickCount(),
283 UserDereferenceObject(pEH
);
284 pLE
= pEH
->Chain
.Flink
;
285 pEH
= CONTAINING_RECORD(pLE
, EVENTHOOK
, Chain
);
286 } while (pLE
!= &GlobalEvents
->Events
);
291 NtUserNotifyWinEvent(
298 USER_REFERENCE_ENTRY Ref
;
299 UserEnterExclusive();
302 if (hWnd
&& (hWnd
!= INVALID_HANDLE_VALUE
))
304 Window
= UserGetWindowObject(hWnd
);
312 if (gpsi
->dwInstalledEventHooks
& GetMaskFromEvent(Event
))
314 if (Window
) UserRefObjectCo(Window
, &Ref
);
315 IntNotifyWinEvent( Event
, Window
, idObject
, idChild
, WEF_SETBYWNDPTI
);
316 if (Window
) UserDerefObjectCo(Window
);
323 NtUserSetWinEventHook(
326 HMODULE hmodWinEventProc
,
327 PUNICODE_STRING puString
,
328 WINEVENTPROC lpfnWinEventProc
,
334 HWINEVENTHOOK Ret
= NULL
;
337 PETHREAD Thread
= NULL
;
339 DPRINT("NtUserSetWinEventHook hmod 0x%x, pfn 0x%x\n",hmodWinEventProc
, lpfnWinEventProc
);
341 UserEnterExclusive();
345 GlobalEvents
= ExAllocatePoolWithTag(PagedPool
, sizeof(EVENTTABLE
), TAG_HOOK
);
346 if (GlobalEvents
== NULL
)
348 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
351 GlobalEvents
->Counts
= 0;
352 InitializeListHead(&GlobalEvents
->Events
);
355 if (eventMin
> eventMax
)
357 SetLastWin32Error(ERROR_INVALID_HOOK_FILTER
);
361 if (!lpfnWinEventProc
)
363 SetLastWin32Error(ERROR_INVALID_FILTER_PROC
);
367 if ((dwflags
& WINEVENT_INCONTEXT
) && !hmodWinEventProc
)
369 SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD
);
375 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)idThread
, &Thread
);
376 if (!NT_SUCCESS(Status
))
378 SetLastWin32Error(ERROR_INVALID_THREAD_ID
);
382 // Creator, pti is set here.
383 pEH
= UserCreateObject(gHandleTable
, NULL
, &Handle
, otEvent
, sizeof(EVENTHOOK
));
386 InsertTailList(&GlobalEvents
->Events
, &pEH
->Chain
);
387 GlobalEvents
->Counts
++;
389 UserHMGetHandle(pEH
) = Handle
;
390 pEH
->eventMin
= eventMin
;
391 pEH
->eventMax
= eventMax
;
392 pEH
->idProcess
= idProcess
; // These are cmp'ed
393 pEH
->idThread
= idThread
; // "
394 pEH
->Flags
= dwflags
;
396 If WINEVENT_INCONTEXT, set offset from hmod and proc. Save ihmod from
397 the atom index table where the hmod data is saved to be recalled later
398 if fSync set by WINEVENT_INCONTEXT.
399 If WINEVENT_OUTOFCONTEXT just use proc..
402 if (NULL
!= hmodWinEventProc
)
404 pEH
->offPfn
= (ULONG_PTR
)((char *)lpfnWinEventProc
- (char *)hmodWinEventProc
);
405 pEH
->ihmod
= (INT
)hmodWinEventProc
;
406 pEH
->Proc
= lpfnWinEventProc
;
409 pEH
->Proc
= lpfnWinEventProc
;
411 UserDereferenceObject(pEH
);
414 IntSetSrvEventMask( eventMin
, eventMax
);
418 if (Thread
) ObDereferenceObject(Thread
);
425 NtUserUnhookWinEvent(
426 HWINEVENTHOOK hWinEventHook
)
431 UserEnterExclusive();
433 pEH
= (PEVENTHOOK
)UserGetObject(gHandleTable
, hWinEventHook
, otEvent
);
436 Ret
= IntRemoveEvent(pEH
);