d46270211865621f82ee463d493c1d42a61a4f97
[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->SrvEventActivity |= GetMaskFromEvent(event);
66 }
67 if (event > EVENT_SYSTEM_MINIMIZEEND && event < EVENT_CONSOLE_CARET)
68 {
69 event = EVENT_CONSOLE_CARET-1;
70 gpsi->SrvEventActivity |= GetMaskFromEvent(event);
71 }
72 if (event > EVENT_CONSOLE_END_APPLICATION && event < EVENT_OBJECT_CREATE )
73 {
74 event = EVENT_OBJECT_CREATE-1;
75 gpsi->SrvEventActivity |= GetMaskFromEvent(event);
76 }
77 if (event > EVENT_OBJECT_ACCELERATORCHANGE && event < EVENT_MAX)
78 {
79 event = EVENT_MAX-1;
80 gpsi->SrvEventActivity |= GetMaskFromEvent(event);
81 break;
82 }
83 }
84 if (!gpsi->SrvEventActivity)
85 gpsi->SrvEventActivity |= SRV_EVENT_RUNNING; // Set something.
86 DPRINT("SetSrvEventMask 2 : %x\n", gpsi->SrvEventActivity);
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 RemoveEntryList(&pEH->Chain);
130 GlobalEvents->Counts--;
131 if (!GlobalEvents->Counts) gpsi->SrvEventActivity = 0;
132 UserDeleteObject(pEH->Self, otEvent);
133 return TRUE;
134 }
135 return FALSE;
136 }
137
138 /* FUNCTIONS *****************************************************************/
139
140 LRESULT
141 FASTCALL
142 co_EVENT_CallEvents( DWORD event,
143 HWND hwnd,
144 UINT_PTR idObject,
145 LONG_PTR idChild)
146 {
147 PEVENTHOOK pEH;
148 LRESULT Result;
149 PEVENTPACK pEP = (PEVENTPACK)idChild;
150
151 pEH = pEP->pEH;
152
153 Result = co_IntCallEventProc( pEH->Self,
154 event,
155 hwnd,
156 pEP->idObject,
157 pEP->idChild,
158 (DWORD_PTR)(NtCurrentTeb()->ClientId).UniqueThread,
159 (DWORD)EngGetTickCount(),
160 pEH->Proc);
161 return Result;
162 }
163
164 VOID
165 FASTCALL
166 IntNotifyWinEvent(
167 DWORD Event,
168 PWINDOW_OBJECT Window,
169 LONG idObject,
170 LONG idChild)
171 {
172 PEVENTHOOK pEH;
173 LRESULT Result;
174
175 if (!GlobalEvents->Counts) return;
176
177 pEH = (PEVENTHOOK)GlobalEvents->Events.Flink;
178
179 do
180 {
181 UserReferenceObject(pEH);
182 // Must be inside the event window.
183 if ( (pEH->eventMin <= Event) && (pEH->eventMax >= Event))
184 {
185 if ((pEH->Thread != PsGetCurrentThread()) && (pEH->Thread != NULL))
186 { // if all process || all thread || other thread same process
187 if (!(pEH->idProcess) || !(pEH->idThread) ||
188 (NtCurrentTeb()->ClientId.UniqueProcess == (PVOID)(DWORD_PTR)pEH->idProcess))
189 {
190 Result = IntCallLowLevelEvent(pEH, Event, Window->hSelf, idObject, idChild);
191 }
192 }// if ^skip own thread && ((Pid && CPid == Pid && ^skip own process) || all process)
193 else if ( !(pEH->Flags & WINEVENT_SKIPOWNTHREAD) &&
194 ( ((pEH->idProcess &&
195 NtCurrentTeb()->ClientId.UniqueProcess == (PVOID)(DWORD_PTR)pEH->idProcess) &&
196 !(pEH->Flags & WINEVENT_SKIPOWNPROCESS)) ||
197 !pEH->idProcess ) )
198 {
199 Result = co_IntCallEventProc( pEH->Self,
200 Event,
201 Window->hSelf,
202 idObject,
203 idChild,
204 PtrToUint(NtCurrentTeb()->ClientId.UniqueThread),
205 (DWORD)EngGetTickCount(),
206 pEH->Proc);
207 }
208 }
209 UserDereferenceObject(pEH);
210
211 pEH = (PEVENTHOOK)pEH->Chain.Flink;
212 } while (pEH != (PEVENTHOOK)&GlobalEvents->Events.Flink);
213 }
214
215 VOID
216 APIENTRY
217 NtUserNotifyWinEvent(
218 DWORD Event,
219 HWND hWnd,
220 LONG idObject,
221 LONG idChild)
222 {
223 PWINDOW_OBJECT Window = NULL;
224 USER_REFERENCE_ENTRY Ref;
225 UserEnterExclusive();
226
227 /* Validate input */
228 if (hWnd && (hWnd != INVALID_HANDLE_VALUE) && !(Window = UserGetWindowObject(hWnd)))
229 {
230 UserLeave();
231 return;
232 }
233
234 if (gpsi->SrvEventActivity & GetMaskFromEvent(Event))
235 {
236 UserRefObjectCo(Window, &Ref);
237 IntNotifyWinEvent( Event, Window, idObject, idChild);
238 UserDerefObjectCo(Window);
239 }
240 UserLeave();
241 }
242
243 HWINEVENTHOOK
244 APIENTRY
245 NtUserSetWinEventHook(
246 UINT eventMin,
247 UINT eventMax,
248 HMODULE hmodWinEventProc,
249 PUNICODE_STRING puString,
250 WINEVENTPROC lpfnWinEventProc,
251 DWORD idProcess,
252 DWORD idThread,
253 UINT dwflags)
254 {
255 PEVENTHOOK pEH;
256 HWINEVENTHOOK Ret = NULL;
257 UNICODE_STRING ModuleName;
258 NTSTATUS Status;
259 HANDLE Handle;
260 PETHREAD Thread = NULL;
261
262 UserEnterExclusive();
263
264 if ( !GlobalEvents )
265 {
266 GlobalEvents = ExAllocatePoolWithTag(PagedPool, sizeof(EVENTTABLE), TAG_HOOK);
267 if (GlobalEvents == NULL)
268 {
269 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
270 goto SetEventExit;
271 }
272 GlobalEvents->Counts = 0;
273 InitializeListHead(&GlobalEvents->Events);
274 }
275
276 if (eventMin > eventMax)
277 {
278 SetLastWin32Error(ERROR_INVALID_HOOK_FILTER);
279 goto SetEventExit;
280 }
281
282 if (!lpfnWinEventProc)
283 {
284 SetLastWin32Error(ERROR_INVALID_FILTER_PROC);
285 goto SetEventExit;
286 }
287
288 if ((dwflags & WINEVENT_INCONTEXT) && !hmodWinEventProc)
289 {
290 SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD);
291 goto SetEventExit;
292 }
293
294 if (idThread)
295 {
296 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)idThread, &Thread);
297 if (!NT_SUCCESS(Status))
298 {
299 SetLastWin32Error(ERROR_INVALID_THREAD_ID);
300 goto SetEventExit;
301 }
302 }
303
304 pEH = UserCreateObject(gHandleTable, &Handle, otEvent, sizeof(EVENTHOOK));
305 if (pEH)
306 {
307 InsertTailList(&GlobalEvents->Events, &pEH->Chain);
308 GlobalEvents->Counts++;
309
310 pEH->Self = Handle;
311 if (Thread)
312 pEH->Thread = Thread;
313 else
314 pEH->Thread = PsGetCurrentThread();
315 pEH->eventMin = eventMin;
316 pEH->eventMax = eventMax;
317 pEH->idProcess = idProcess;
318 pEH->idThread = idThread;
319 pEH->Ansi = FALSE;
320 pEH->Flags = dwflags;
321
322
323 if (NULL != hmodWinEventProc)
324 {
325 Status = MmCopyFromCaller(&ModuleName,
326 puString,
327 sizeof(UNICODE_STRING));
328
329 if (! NT_SUCCESS(Status))
330 {
331 UserDereferenceObject(pEH);
332 IntRemoveEvent(pEH);
333 SetLastNtError(Status);
334 goto SetEventExit;
335 }
336
337 pEH->ModuleName.Buffer = ExAllocatePoolWithTag(PagedPool,
338 ModuleName.MaximumLength,
339 TAG_HOOK);
340
341 if (NULL == pEH->ModuleName.Buffer)
342 {
343 UserDereferenceObject(pEH);
344 IntRemoveEvent(pEH);
345 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
346 goto SetEventExit;
347 }
348
349 pEH->ModuleName.MaximumLength = ModuleName.MaximumLength;
350
351 Status = MmCopyFromCaller(pEH->ModuleName.Buffer,
352 ModuleName.Buffer,
353 ModuleName.MaximumLength);
354
355 if (! NT_SUCCESS(Status))
356 {
357 ExFreePoolWithTag(pEH->ModuleName.Buffer, TAG_HOOK);
358 UserDereferenceObject(pEH);
359 IntRemoveEvent(pEH);
360 SetLastNtError(Status);
361 goto SetEventExit;
362 }
363
364 pEH->ModuleName.Length = ModuleName.Length;
365
366 pEH->Proc = (void *)((char *)lpfnWinEventProc - (char *)hmodWinEventProc);
367 }
368 else
369 pEH->Proc = lpfnWinEventProc;
370
371 UserDereferenceObject(pEH);
372
373 Ret = Handle;
374 IntSetSrvEventMask( eventMin, eventMax);
375 }
376
377 SetEventExit:
378 if (Thread) ObDereferenceObject(Thread);
379 UserLeave();
380 return Ret;
381 }
382
383 BOOL
384 APIENTRY
385 NtUserUnhookWinEvent(
386 HWINEVENTHOOK hWinEventHook)
387 {
388 PEVENTHOOK pEH;
389 BOOL Ret = FALSE;
390
391 UserEnterExclusive();
392
393 pEH = (PEVENTHOOK)UserGetObject(gHandleTable, hWinEventHook, otEvent);
394 if (pEH)
395 {
396 Ret = IntRemoveEvent(pEH);
397 }
398
399 UserLeave();
400 return Ret;
401 }
402
403 /* EOF */