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