Sync to trunk head (r42241)
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / event.c
1
2 #include <w32k.h>
3
4 #define NDEBUG
5 #include <debug.h>
6
7 typedef struct _EVENTPACK
8 {
9 PEVENTHOOK pEH;
10 LONG idObject;
11 LONG idChild;
12 } EVENTPACK, *PEVENTPACK;
13
14 static PEVENTTABLE GlobalEvents = NULL;
15
16 /* PRIVATE FUNCTIONS *********************************************************/
17
18 static
19 DWORD
20 FASTCALL
21 GetMaskFromEvent(DWORD Event)
22 {
23 DWORD Ret = 0;
24
25 if ( Event > EVENT_OBJECT_STATECHANGE )
26 {
27 if ( Event == EVENT_OBJECT_LOCATIONCHANGE ) return SRV_EVENT_LOCATIONCHANGE;
28 if ( Event == EVENT_OBJECT_NAMECHANGE ) return SRV_EVENT_NAMECHANGE;
29 if ( Event == EVENT_OBJECT_VALUECHANGE ) return SRV_EVENT_VALUECHANGE;
30 return SRV_EVENT_CREATE;
31 }
32
33 if ( Event == EVENT_OBJECT_STATECHANGE ) return SRV_EVENT_STATECHANGE;
34
35 Ret = SRV_EVENT_RUNNING;
36
37 if ( Event < EVENT_SYSTEM_MENUSTART ) return SRV_EVENT_CREATE;
38
39 if ( Event <= EVENT_SYSTEM_MENUPOPUPEND )
40 {
41 Ret = SRV_EVENT_MENU;
42 }
43 else
44 {
45 if ( Event <= EVENT_CONSOLE_CARET-1 ) return SRV_EVENT_CREATE;
46 if ( Event <= EVENT_CONSOLE_END_APPLICATION ) return SRV_EVENT_END_APPLICATION;
47 if ( Event != EVENT_OBJECT_FOCUS ) return SRV_EVENT_CREATE;
48 }
49 return Ret;
50 }
51
52 static
53 VOID
54 FASTCALL
55 IntSetSrvEventMask( UINT EventMin, UINT EventMax)
56 {
57 UINT event;
58 DPRINT("SetSrvEventMask 1\n");
59 for ( event = EventMin; event <= EventMax; event++)
60 {
61 if ((event >= EVENT_SYSTEM_SOUND && event <= EVENT_SYSTEM_MINIMIZEEND) ||
62 (event >= EVENT_CONSOLE_CARET && event <= EVENT_CONSOLE_END_APPLICATION) ||
63 (event >= EVENT_OBJECT_CREATE && event <= EVENT_OBJECT_ACCELERATORCHANGE))
64 {
65 gpsi->dwInstalledEventHooks |= GetMaskFromEvent(event);
66 }
67 if (event > EVENT_SYSTEM_MINIMIZEEND && event < EVENT_CONSOLE_CARET)
68 {
69 event = EVENT_CONSOLE_CARET-1;
70 gpsi->dwInstalledEventHooks |= GetMaskFromEvent(event);
71 }
72 if (event > EVENT_CONSOLE_END_APPLICATION && event < EVENT_OBJECT_CREATE )
73 {
74 event = EVENT_OBJECT_CREATE-1;
75 gpsi->dwInstalledEventHooks |= GetMaskFromEvent(event);
76 }
77 if (event > EVENT_OBJECT_ACCELERATORCHANGE && event < EVENT_MAX)
78 {
79 event = EVENT_MAX-1;
80 gpsi->dwInstalledEventHooks |= GetMaskFromEvent(event);
81 break;
82 }
83 }
84 if (!gpsi->dwInstalledEventHooks)
85 gpsi->dwInstalledEventHooks |= SRV_EVENT_RUNNING; // Set something.
86 DPRINT("SetSrvEventMask 2 : %x\n", gpsi->dwInstalledEventHooks);
87 }
88
89 static
90 LRESULT
91 FASTCALL
92 IntCallLowLevelEvent( PEVENTHOOK pEH,
93 DWORD event,
94 HWND hwnd,
95 LONG idObject,
96 LONG idChild)
97 {
98 NTSTATUS Status;
99 ULONG_PTR uResult;
100 EVENTPACK EP;
101
102 EP.pEH = pEH;
103 EP.idObject = idObject;
104 EP.idChild = idChild;
105
106 /* FIXME should get timeout from
107 * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
108 Status = co_MsqSendMessage(((PTHREADINFO)pEH->Thread->Tcb.Win32Thread)->MessageQueue,
109 hwnd,
110 event,
111 0,
112 (LPARAM)&EP,
113 5000,
114 TRUE,
115 MSQ_ISEVENT,
116 &uResult);
117
118 return NT_SUCCESS(Status) ? uResult : 0;
119 }
120
121
122 static
123 BOOL
124 FASTCALL
125 IntRemoveEvent(PEVENTHOOK pEH)
126 {
127 if (pEH)
128 {
129 DPRINT("IntRemoveEvent pEH 0x%x\n",pEH);
130 KeEnterCriticalRegion();
131 RemoveEntryList(&pEH->Chain);
132 GlobalEvents->Counts--;
133 if (!GlobalEvents->Counts) gpsi->dwInstalledEventHooks = 0;
134 UserDeleteObject(pEH->head.h, otEvent);
135 KeLeaveCriticalRegion();
136 return TRUE;
137 }
138 return FALSE;
139 }
140
141 /* FUNCTIONS *****************************************************************/
142
143 LRESULT
144 FASTCALL
145 co_EVENT_CallEvents( DWORD event,
146 HWND hwnd,
147 UINT_PTR idObject,
148 LONG_PTR idChild)
149 {
150 PEVENTHOOK pEH;
151 LRESULT Result;
152 PEVENTPACK pEP = (PEVENTPACK)idChild;
153
154 pEH = pEP->pEH;
155
156 Result = co_IntCallEventProc( pEH->head.h,
157 event,
158 hwnd,
159 pEP->idObject,
160 pEP->idChild,
161 (DWORD_PTR)(NtCurrentTeb()->ClientId).UniqueThread,
162 (DWORD)EngGetTickCount(),
163 pEH->Proc);
164 return Result;
165 }
166
167 VOID
168 FASTCALL
169 IntNotifyWinEvent(
170 DWORD Event,
171 PWND pWnd,
172 LONG idObject,
173 LONG idChild)
174 {
175 PEVENTHOOK pEH;
176 PLIST_ENTRY pLE;
177 LRESULT Result;
178
179 DPRINT("IntNotifyWinEvent GlobalEvents = 0x%x pWnd 0x%x\n",GlobalEvents, pWnd);
180
181 if (!pWnd) return;
182
183 if (pWnd && pWnd->state & WNDS_DESTROYED) return;
184
185 if (!GlobalEvents || !GlobalEvents->Counts) return;
186
187 pLE = GlobalEvents->Events.Flink;
188 pEH = CONTAINING_RECORD(pLE, EVENTHOOK, Chain);
189 do
190 {
191 UserReferenceObject(pEH);
192 // Must be inside the event window.
193 if ( (pEH->eventMin <= Event) && (pEH->eventMax >= Event))
194 {
195 if ((pEH->Thread != PsGetCurrentThread()) && (pEH->Thread != NULL))
196 { // if all process || all thread || other thread same process
197 if (!(pEH->idProcess) || !(pEH->idThread) ||
198 (NtCurrentTeb()->ClientId.UniqueProcess == (PVOID)(DWORD_PTR)pEH->idProcess))
199 {
200 Result = IntCallLowLevelEvent( pEH,
201 Event,
202 UserHMGetHandle(pWnd),
203 idObject,
204 idChild);
205 }
206 }// if ^skip own thread && ((Pid && CPid == Pid && ^skip own process) || all process)
207 else if ( !(pEH->Flags & WINEVENT_SKIPOWNTHREAD) &&
208 ( ((pEH->idProcess &&
209 NtCurrentTeb()->ClientId.UniqueProcess == (PVOID)(DWORD_PTR)pEH->idProcess) &&
210 !(pEH->Flags & WINEVENT_SKIPOWNPROCESS)) ||
211 !pEH->idProcess ) )
212 {
213 Result = co_IntCallEventProc( UserHMGetHandle(pEH),
214 Event,
215 UserHMGetHandle(pWnd),
216 idObject,
217 idChild,
218 PtrToUint(NtCurrentTeb()->ClientId.UniqueThread),
219 (DWORD)EngGetTickCount(),
220 pEH->Proc);
221 }
222 }
223 UserDereferenceObject(pEH);
224 pLE = pEH->Chain.Flink;
225 pEH = CONTAINING_RECORD(pLE, EVENTHOOK, Chain);
226 } while (pLE != &GlobalEvents->Events);
227 }
228
229 VOID
230 APIENTRY
231 NtUserNotifyWinEvent(
232 DWORD Event,
233 HWND hWnd,
234 LONG idObject,
235 LONG idChild)
236 {
237 PWINDOW_OBJECT Window = NULL;
238 USER_REFERENCE_ENTRY Ref;
239 UserEnterExclusive();
240
241 /* Validate input */
242 if (hWnd && (hWnd != INVALID_HANDLE_VALUE) && !(Window = UserGetWindowObject(hWnd)))
243 {
244 UserLeave();
245 return;
246 }
247
248 if (gpsi->dwInstalledEventHooks & GetMaskFromEvent(Event))
249 {
250 UserRefObjectCo(Window, &Ref);
251 IntNotifyWinEvent( Event, Window->Wnd, idObject, idChild);
252 UserDerefObjectCo(Window);
253 }
254 UserLeave();
255 }
256
257 HWINEVENTHOOK
258 APIENTRY
259 NtUserSetWinEventHook(
260 UINT eventMin,
261 UINT eventMax,
262 HMODULE hmodWinEventProc,
263 PUNICODE_STRING puString,
264 WINEVENTPROC lpfnWinEventProc,
265 DWORD idProcess,
266 DWORD idThread,
267 UINT dwflags)
268 {
269 PEVENTHOOK pEH;
270 HWINEVENTHOOK Ret = NULL;
271 NTSTATUS Status;
272 HANDLE Handle;
273 PETHREAD Thread = NULL;
274
275 DPRINT("NtUserSetWinEventHook hmod 0x%x, pfn 0x%x\n",hmodWinEventProc, lpfnWinEventProc);
276
277 UserEnterExclusive();
278
279 if ( !GlobalEvents )
280 {
281 GlobalEvents = ExAllocatePoolWithTag(PagedPool, sizeof(EVENTTABLE), TAG_HOOK);
282 if (GlobalEvents == NULL)
283 {
284 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
285 goto SetEventExit;
286 }
287 GlobalEvents->Counts = 0;
288 InitializeListHead(&GlobalEvents->Events);
289 }
290
291 if (eventMin > eventMax)
292 {
293 SetLastWin32Error(ERROR_INVALID_HOOK_FILTER);
294 goto SetEventExit;
295 }
296
297 if (!lpfnWinEventProc)
298 {
299 SetLastWin32Error(ERROR_INVALID_FILTER_PROC);
300 goto SetEventExit;
301 }
302
303 if ((dwflags & WINEVENT_INCONTEXT) && !hmodWinEventProc)
304 {
305 SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD);
306 goto SetEventExit;
307 }
308
309 if (idThread)
310 {
311 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)idThread, &Thread);
312 if (!NT_SUCCESS(Status))
313 {
314 SetLastWin32Error(ERROR_INVALID_THREAD_ID);
315 goto SetEventExit;
316 }
317 }
318
319 pEH = UserCreateObject(gHandleTable, &Handle, otEvent, sizeof(EVENTHOOK));
320 if (pEH)
321 {
322 InsertTailList(&GlobalEvents->Events, &pEH->Chain);
323 GlobalEvents->Counts++;
324
325 UserHMGetHandle(pEH) = Handle;
326 // pEH->head.pti =?
327 // pEH->head.rpdesk
328 if (Thread)
329 pEH->Thread = Thread;
330 else
331 pEH->Thread = PsGetCurrentThread();
332 pEH->eventMin = eventMin;
333 pEH->eventMax = eventMax;
334 pEH->idProcess = idProcess;
335 pEH->idThread = idThread;
336 pEH->Flags = dwflags;
337
338 if (NULL != hmodWinEventProc)
339 {
340 pEH->offPfn = (ULONG_PTR)((char *)lpfnWinEventProc - (char *)hmodWinEventProc);
341 pEH->ihmod = (INT)hmodWinEventProc;
342 pEH->Proc = lpfnWinEventProc;
343 }
344 else
345 pEH->Proc = lpfnWinEventProc;
346
347 UserDereferenceObject(pEH);
348
349 Ret = Handle;
350 IntSetSrvEventMask( eventMin, eventMax);
351 }
352
353 SetEventExit:
354 if (Thread) ObDereferenceObject(Thread);
355 UserLeave();
356 return Ret;
357 }
358
359 BOOL
360 APIENTRY
361 NtUserUnhookWinEvent(
362 HWINEVENTHOOK hWinEventHook)
363 {
364 PEVENTHOOK pEH;
365 BOOL Ret = FALSE;
366
367 UserEnterExclusive();
368
369 pEH = (PEVENTHOOK)UserGetObject(gHandleTable, hWinEventHook, otEvent);
370 if (pEH)
371 {
372 Ret = IntRemoveEvent(pEH);
373 }
374
375 UserLeave();
376 return Ret;
377 }
378
379 /* EOF */