1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Window event handlers 5 * FILE: win32ss/user/ntuser/event.c 6 * PROGRAMER: James Tabor (james.tabor@rectos.org) 7 */ 8 9 #include <win32k.h> 10 DBG_DEFAULT_CHANNEL(UserEvent); 11 12 typedef struct _EVENTPACK 13 { 14 PEVENTHOOK pEH; 15 LONG idObject; 16 LONG idChild; 17 LONG idThread; 18 } EVENTPACK, *PEVENTPACK; 19 20 static PEVENTTABLE GlobalEvents = NULL; 21 22 /* PRIVATE FUNCTIONS *********************************************************/ 23 24 static 25 DWORD 26 FASTCALL 27 GetMaskFromEvent(DWORD Event) 28 { 29 DWORD Ret = 0; 30 31 if ( Event > EVENT_OBJECT_STATECHANGE ) 32 { 33 if ( Event == EVENT_OBJECT_LOCATIONCHANGE ) return SRV_EVENT_LOCATIONCHANGE; 34 if ( Event == EVENT_OBJECT_NAMECHANGE ) return SRV_EVENT_NAMECHANGE; 35 if ( Event == EVENT_OBJECT_VALUECHANGE ) return SRV_EVENT_VALUECHANGE; 36 return SRV_EVENT_CREATE; 37 } 38 39 if ( Event == EVENT_OBJECT_STATECHANGE ) return SRV_EVENT_STATECHANGE; 40 41 Ret = SRV_EVENT_RUNNING; 42 43 if ( Event < EVENT_SYSTEM_MENUSTART ) return SRV_EVENT_CREATE; 44 45 if ( Event <= EVENT_SYSTEM_MENUPOPUPEND ) 46 { 47 Ret = SRV_EVENT_MENU; 48 } 49 else 50 { 51 if ( Event <= EVENT_CONSOLE_CARET-1 ) return SRV_EVENT_CREATE; 52 if ( Event <= EVENT_CONSOLE_END_APPLICATION ) return SRV_EVENT_END_APPLICATION; 53 if ( Event != EVENT_OBJECT_FOCUS ) return SRV_EVENT_CREATE; 54 } 55 return Ret; 56 } 57 58 static 59 VOID 60 FASTCALL 61 IntSetSrvEventMask( UINT EventMin, UINT EventMax) 62 { 63 UINT event; 64 TRACE("SetSrvEventMask 1\n"); 65 for ( event = EventMin; event <= EventMax; event++) 66 { 67 if ((event >= EVENT_SYSTEM_SOUND && event <= EVENT_SYSTEM_MINIMIZEEND) || 68 (event >= EVENT_CONSOLE_CARET && event <= EVENT_CONSOLE_END_APPLICATION) || 69 (event >= EVENT_OBJECT_CREATE && event <= EVENT_OBJECT_ACCELERATORCHANGE)) 70 { 71 gpsi->dwInstalledEventHooks |= GetMaskFromEvent(event); 72 } 73 if (event > EVENT_SYSTEM_MINIMIZEEND && event < EVENT_CONSOLE_CARET) 74 { 75 event = EVENT_CONSOLE_CARET-1; 76 gpsi->dwInstalledEventHooks |= GetMaskFromEvent(event); 77 } 78 if (event > EVENT_CONSOLE_END_APPLICATION && event < EVENT_OBJECT_CREATE ) 79 { 80 event = EVENT_OBJECT_CREATE-1; 81 gpsi->dwInstalledEventHooks |= GetMaskFromEvent(event); 82 } 83 if (event > EVENT_OBJECT_ACCELERATORCHANGE && event < EVENT_MAX) 84 { 85 event = EVENT_MAX-1; 86 gpsi->dwInstalledEventHooks |= GetMaskFromEvent(event); 87 break; 88 } 89 } 90 if (!gpsi->dwInstalledEventHooks) 91 gpsi->dwInstalledEventHooks |= SRV_EVENT_RUNNING; // Set something. 92 TRACE("SetSrvEventMask 2 : %x\n", gpsi->dwInstalledEventHooks); 93 } 94 95 static 96 LRESULT 97 FASTCALL 98 IntCallLowLevelEvent( PEVENTHOOK pEH, 99 DWORD event, 100 HWND hwnd, 101 LONG idObject, 102 LONG idChild, 103 LONG idThread) 104 { 105 PEVENTPACK pEP; 106 MSG Msg; 107 108 pEP = ExAllocatePoolWithTag(NonPagedPool, sizeof(EVENTPACK), TAG_HOOK); 109 if (!pEP) return 0; 110 111 pEP->pEH = pEH; 112 pEP->idObject = idObject; 113 pEP->idChild = idChild; 114 pEP->idThread = idThread; 115 116 Msg.message = event; 117 Msg.hwnd = hwnd; 118 Msg.wParam = 0; 119 Msg.lParam = POSTEVENT_NWE; 120 Msg.time = 0; 121 122 MsqPostMessage(pEH->head.pti, &Msg, FALSE, QS_EVENT, POSTEVENT_NWE, (LONG_PTR)pEP); 123 return 0; 124 } 125 126 BOOLEAN 127 IntRemoveEvent(PVOID Object) 128 { 129 PEVENTHOOK pEH = Object; 130 if (pEH) 131 { 132 TRACE("IntRemoveEvent pEH %p\n", pEH); 133 KeEnterCriticalRegion(); 134 RemoveEntryList(&pEH->Chain); 135 GlobalEvents->Counts--; 136 if (!GlobalEvents->Counts) gpsi->dwInstalledEventHooks = 0; 137 UserDeleteObject(UserHMGetHandle(pEH), TYPE_WINEVENTHOOK); 138 KeLeaveCriticalRegion(); 139 return TRUE; 140 } 141 return FALSE; 142 } 143 144 /* FUNCTIONS *****************************************************************/ 145 146 // 147 // Dispatch MsgQueue Event Call processor! 148 // 149 LRESULT 150 APIENTRY 151 co_EVENT_CallEvents( DWORD event, 152 HWND hwnd, 153 UINT_PTR idObject, 154 LONG_PTR idChild) 155 { 156 PEVENTHOOK pEH; 157 LRESULT Result; 158 PEVENTPACK pEP = (PEVENTPACK)idChild; 159 160 pEH = pEP->pEH; 161 TRACE("Dispatch Event 0x%lx, idObject %uI hwnd %p\n", event, idObject, hwnd); 162 Result = co_IntCallEventProc( UserHMGetHandle(pEH), 163 event, 164 hwnd, 165 pEP->idObject, 166 pEP->idChild, 167 pEP->idThread, 168 (DWORD)EngGetTickCount(), 169 pEH->Proc, 170 pEH->ihmod, 171 pEH->offPfn); 172 173 ExFreePoolWithTag(pEP, TAG_HOOK); 174 return Result; 175 } 176 177 VOID 178 FASTCALL 179 IntNotifyWinEvent( 180 DWORD Event, 181 PWND pWnd, 182 LONG idObject, 183 LONG idChild, 184 DWORD flags) 185 { 186 PEVENTHOOK pEH; 187 PLIST_ENTRY ListEntry; 188 PTHREADINFO pti, ptiCurrent; 189 USER_REFERENCE_ENTRY Ref; 190 191 TRACE("IntNotifyWinEvent GlobalEvents = %p pWnd %p\n", GlobalEvents, pWnd); 192 193 if (!GlobalEvents || !GlobalEvents->Counts) return; 194 195 if (pWnd && pWnd->state & WNDS_DESTROYED) return; 196 197 ptiCurrent = PsGetCurrentThreadWin32Thread(); 198 199 if (pWnd && flags & WEF_SETBYWNDPTI) 200 pti = pWnd->head.pti; 201 else 202 pti = ptiCurrent; 203 204 ListEntry = GlobalEvents->Events.Flink; 205 ASSERT(ListEntry != &GlobalEvents->Events); 206 while (ListEntry != &GlobalEvents->Events) 207 { 208 pEH = CONTAINING_RECORD(ListEntry, EVENTHOOK, Chain); 209 ListEntry = ListEntry->Flink; 210 211 // Must be inside the event window. 212 if ( Event >= pEH->eventMin && Event <= pEH->eventMax ) 213 { 214 // if all process || all thread || other thread same process 215 // if ^skip own thread && ((Pid && CPid == Pid && ^skip own process) || all process) 216 if (!( (pEH->idProcess && pEH->idProcess != PtrToUint(pti->pEThread->Cid.UniqueProcess)) || 217 (pEH->Flags & WINEVENT_SKIPOWNPROCESS && pEH->head.pti->ppi == pti->ppi) || 218 (pEH->idThread && pEH->idThread != PtrToUint(pti->pEThread->Cid.UniqueThread)) || 219 (pEH->Flags & WINEVENT_SKIPOWNTHREAD && pEH->head.pti == pti) || 220 pEH->head.pti->rpdesk != ptiCurrent->rpdesk ) ) // Same as hooks. 221 { 222 UserRefObjectCo(pEH, &Ref); 223 if (pEH->Flags & WINEVENT_INCONTEXT) 224 { 225 TRACE("In Event 0x%x, idObject %d hwnd %p\n", Event, idObject, pWnd ? UserHMGetHandle(pWnd) : NULL); 226 co_IntCallEventProc( UserHMGetHandle(pEH), 227 Event, 228 pWnd ? UserHMGetHandle(pWnd) : NULL, 229 idObject, 230 idChild, 231 PtrToUint(NtCurrentTeb()->ClientId.UniqueThread), 232 (DWORD)EngGetTickCount(), 233 pEH->Proc, 234 pEH->ihmod, 235 pEH->offPfn); 236 } 237 else 238 { 239 TRACE("Out Event 0x%x, idObject %d hwnd %p\n", Event, idObject, pWnd ? UserHMGetHandle(pWnd) : NULL); 240 IntCallLowLevelEvent( pEH, 241 Event, 242 pWnd ? UserHMGetHandle(pWnd) : NULL, 243 idObject, 244 idChild, 245 PtrToUint(NtCurrentTeb()->ClientId.UniqueThread)); 246 } 247 UserDerefObjectCo(pEH); 248 } 249 } 250 } 251 } 252 253 VOID 254 APIENTRY 255 NtUserNotifyWinEvent( 256 DWORD Event, 257 HWND hWnd, 258 LONG idObject, 259 LONG idChild) 260 { 261 PWND Window = NULL; 262 USER_REFERENCE_ENTRY Ref; 263 UserEnterExclusive(); 264 265 /* Validate input */ 266 if (hWnd && (hWnd != INVALID_HANDLE_VALUE)) 267 { 268 Window = UserGetWindowObject(hWnd); 269 if (!Window) 270 { 271 UserLeave(); 272 return; 273 } 274 } 275 276 if (gpsi->dwInstalledEventHooks & GetMaskFromEvent(Event)) 277 { 278 if (Window) UserRefObjectCo(Window, &Ref); 279 IntNotifyWinEvent( Event, Window, idObject, idChild, WEF_SETBYWNDPTI); 280 if (Window) UserDerefObjectCo(Window); 281 } 282 UserLeave(); 283 } 284 285 HWINEVENTHOOK 286 APIENTRY 287 NtUserSetWinEventHook( 288 UINT eventMin, 289 UINT eventMax, 290 HMODULE hmodWinEventProc, 291 PUNICODE_STRING puString, 292 WINEVENTPROC lpfnWinEventProc, 293 DWORD idProcess, 294 DWORD idThread, 295 UINT dwflags) 296 { 297 PEVENTHOOK pEH; 298 HWINEVENTHOOK Ret = NULL; 299 NTSTATUS Status; 300 HANDLE Handle; 301 PTHREADINFO pti; 302 303 TRACE("NtUserSetWinEventHook hmod %p, pfn %p\n", hmodWinEventProc, lpfnWinEventProc); 304 305 UserEnterExclusive(); 306 307 if ( !GlobalEvents ) 308 { 309 GlobalEvents = ExAllocatePoolWithTag(PagedPool, sizeof(EVENTTABLE), TAG_HOOK); 310 if (GlobalEvents == NULL) 311 { 312 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 313 goto SetEventExit; 314 } 315 GlobalEvents->Counts = 0; 316 InitializeListHead(&GlobalEvents->Events); 317 } 318 319 if (eventMin > eventMax) 320 { 321 EngSetLastError(ERROR_INVALID_HOOK_FILTER); 322 goto SetEventExit; 323 } 324 325 if (!lpfnWinEventProc) 326 { 327 EngSetLastError(ERROR_INVALID_FILTER_PROC); 328 goto SetEventExit; 329 } 330 331 if (dwflags & WINEVENT_INCONTEXT) 332 { 333 if (!hmodWinEventProc) 334 { 335 ERR("Hook needs a module\n"); 336 EngSetLastError(ERROR_HOOK_NEEDS_HMOD); 337 goto SetEventExit; 338 } 339 if (puString == NULL) 340 { 341 ERR("Dll not found\n"); 342 EngSetLastError(ERROR_DLL_NOT_FOUND); 343 goto SetEventExit; 344 } 345 } 346 else 347 { 348 TRACE("Out of Context\n"); 349 hmodWinEventProc = 0; 350 } 351 352 if (idThread) 353 { 354 PETHREAD Thread; 355 Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)idThread, &Thread); 356 if (!NT_SUCCESS(Status)) 357 { 358 EngSetLastError(ERROR_INVALID_THREAD_ID); 359 goto SetEventExit; 360 } 361 pti = PsGetThreadWin32Thread(Thread); 362 ObDereferenceObject(Thread); 363 } 364 else 365 { 366 pti = PsGetCurrentThreadWin32Thread(); 367 } 368 // Creator, pti is set here. 369 pEH = UserCreateObject(gHandleTable, NULL, pti, &Handle, TYPE_WINEVENTHOOK, sizeof(EVENTHOOK)); 370 if (pEH) 371 { 372 InsertTailList(&GlobalEvents->Events, &pEH->Chain); 373 GlobalEvents->Counts++; 374 375 UserHMGetHandle(pEH) = Handle; 376 pEH->eventMin = eventMin; 377 pEH->eventMax = eventMax; 378 pEH->idProcess = idProcess; // These are cmp'ed 379 pEH->idThread = idThread; // " 380 pEH->Flags = dwflags; 381 /* 382 If WINEVENT_INCONTEXT, set offset from hmod and proc. Save ihmod from 383 the atom index table where the hmod data is saved to be recalled later 384 if fSync set by WINEVENT_INCONTEXT. 385 If WINEVENT_OUTOFCONTEXT just use proc.. 386 Do this instead.... 387 */ 388 if (hmodWinEventProc != NULL) 389 { 390 pEH->offPfn = (ULONG_PTR)((char *)lpfnWinEventProc - (char *)hmodWinEventProc); 391 pEH->ihmod = (INT)hmodWinEventProc; 392 pEH->Proc = lpfnWinEventProc; 393 } 394 else 395 { 396 pEH->Proc = lpfnWinEventProc; 397 pEH->offPfn = 0; 398 pEH->ihmod = (INT)hmodWinEventProc; 399 } 400 401 UserDereferenceObject(pEH); 402 403 Ret = Handle; 404 IntSetSrvEventMask( eventMin, eventMax); 405 } 406 407 SetEventExit: 408 UserLeave(); 409 return Ret; 410 } 411 412 BOOL 413 APIENTRY 414 NtUserUnhookWinEvent( 415 HWINEVENTHOOK hWinEventHook) 416 { 417 PEVENTHOOK pEH; 418 BOOL Ret = FALSE; 419 420 UserEnterExclusive(); 421 422 pEH = (PEVENTHOOK)UserGetObject(gHandleTable, hWinEventHook, TYPE_WINEVENTHOOK); 423 if (pEH) 424 { 425 Ret = IntRemoveEvent(pEH); 426 } 427 428 UserLeave(); 429 return Ret; 430 } 431 432 /* EOF */ 433