1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: Messages 5 * FILE: win32ss/user/ntuser/message.c 6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) 7 */ 8 9 #include <win32k.h> 10 11 #include <dde.h> 12 13 DBG_DEFAULT_CHANNEL(UserMsg); 14 15 #define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE) 16 17 /* FUNCTIONS *****************************************************************/ 18 19 NTSTATUS FASTCALL 20 IntInitMessageImpl(VOID) 21 { 22 return STATUS_SUCCESS; 23 } 24 25 NTSTATUS FASTCALL 26 IntCleanupMessageImpl(VOID) 27 { 28 return STATUS_SUCCESS; 29 } 30 31 /* From wine: */ 32 /* flag for messages that contain pointers */ 33 /* 32 messages per entry, messages 0..31 map to bits 0..31 */ 34 35 #define SET(msg) (1 << ((msg) & 31)) 36 37 static const unsigned int message_pointer_flags[] = 38 { 39 /* 0x00 - 0x1f */ 40 SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) | 41 SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE), 42 /* 0x20 - 0x3f */ 43 SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM) | 44 SET(WM_COMPAREITEM), 45 /* 0x40 - 0x5f */ 46 SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) | SET(WM_COPYGLOBALDATA) | SET(WM_HELP), 47 /* 0x60 - 0x7f */ 48 SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED), 49 /* 0x80 - 0x9f */ 50 SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE), 51 /* 0xa0 - 0xbf */ 52 SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP), 53 /* 0xc0 - 0xdf */ 54 SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS), 55 /* 0xe0 - 0xff */ 56 SET(SBM_GETRANGE) | SET(SBM_SETSCROLLINFO) | SET(SBM_GETSCROLLINFO) | SET(SBM_GETSCROLLBARINFO), 57 /* 0x100 - 0x11f */ 58 0, 59 /* 0x120 - 0x13f */ 60 0, 61 /* 0x140 - 0x15f */ 62 SET(CB_GETEDITSEL) | SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) | 63 SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) | 64 SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT), 65 /* 0x160 - 0x17f */ 66 0, 67 /* 0x180 - 0x19f */ 68 SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) | 69 SET(LB_DIR) | SET(LB_FINDSTRING) | 70 SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT), 71 /* 0x1a0 - 0x1bf */ 72 SET(LB_FINDSTRINGEXACT), 73 /* 0x1c0 - 0x1df */ 74 0, 75 /* 0x1e0 - 0x1ff */ 76 0, 77 /* 0x200 - 0x21f */ 78 SET(WM_NEXTMENU) | SET(WM_SIZING) | SET(WM_MOVING) | SET(WM_DEVICECHANGE), 79 /* 0x220 - 0x23f */ 80 SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) | 81 SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGLOOP) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE), 82 /* 0x240 - 0x25f */ 83 0, 84 /* 0x260 - 0x27f */ 85 0, 86 /* 0x280 - 0x29f */ 87 0, 88 /* 0x2a0 - 0x2bf */ 89 0, 90 /* 0x2c0 - 0x2df */ 91 0, 92 /* 0x2e0 - 0x2ff */ 93 0, 94 /* 0x300 - 0x31f */ 95 SET(WM_ASKCBFORMATNAME) 96 }; 97 98 /* check whether a given message type includes pointers */ 99 static inline int is_pointer_message( UINT message ) 100 { 101 if (message >= 8*sizeof(message_pointer_flags)) return FALSE; 102 return (message_pointer_flags[message / 32] & SET(message)) != 0; 103 } 104 #undef SET 105 106 #define MMS_SIZE_WPARAM -1 107 #define MMS_SIZE_WPARAMWCHAR -2 108 #define MMS_SIZE_LPARAMSZ -3 109 #define MMS_SIZE_SPECIAL -4 110 #define MMS_FLAG_READ 0x01 111 #define MMS_FLAG_WRITE 0x02 112 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE) 113 typedef struct tagMSGMEMORY 114 { 115 UINT Message; 116 UINT Size; 117 INT Flags; 118 } 119 MSGMEMORY, *PMSGMEMORY; 120 121 static MSGMEMORY g_MsgMemory[] = 122 { 123 { WM_CREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE }, 124 { WM_GETMINMAXINFO, sizeof(MINMAXINFO), MMS_FLAG_READWRITE }, 125 { WM_GETTEXT, MMS_SIZE_WPARAMWCHAR, MMS_FLAG_WRITE }, 126 { WM_NCCALCSIZE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE }, 127 { WM_NCCREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE }, 128 { WM_SETTEXT, MMS_SIZE_LPARAMSZ, MMS_FLAG_READ }, 129 { WM_STYLECHANGED, sizeof(STYLESTRUCT), MMS_FLAG_READ }, 130 { WM_STYLECHANGING, sizeof(STYLESTRUCT), MMS_FLAG_READWRITE }, 131 { WM_SETTINGCHANGE, MMS_SIZE_LPARAMSZ, MMS_FLAG_READ }, 132 { WM_COPYDATA, MMS_SIZE_SPECIAL, MMS_FLAG_READ }, 133 { WM_COPYGLOBALDATA, MMS_SIZE_WPARAM, MMS_FLAG_READ }, 134 { WM_WINDOWPOSCHANGED, sizeof(WINDOWPOS), MMS_FLAG_READWRITE }, 135 { WM_WINDOWPOSCHANGING, sizeof(WINDOWPOS), MMS_FLAG_READWRITE }, 136 { WM_SIZING, sizeof(RECT), MMS_FLAG_READWRITE }, 137 { WM_MOVING, sizeof(RECT), MMS_FLAG_READWRITE }, 138 { WM_MEASUREITEM, sizeof(MEASUREITEMSTRUCT), MMS_FLAG_READWRITE }, 139 { WM_DRAWITEM, sizeof(DRAWITEMSTRUCT), MMS_FLAG_READWRITE }, 140 { WM_HELP, sizeof(HELPINFO), MMS_FLAG_READWRITE }, 141 { WM_NEXTMENU, sizeof(MDINEXTMENU), MMS_FLAG_READWRITE }, 142 }; 143 144 static PMSGMEMORY FASTCALL 145 FindMsgMemory(UINT Msg) 146 { 147 PMSGMEMORY MsgMemoryEntry; 148 149 /* See if this message type is present in the table */ 150 for (MsgMemoryEntry = g_MsgMemory; 151 MsgMemoryEntry < g_MsgMemory + sizeof(g_MsgMemory) / sizeof(MSGMEMORY); 152 MsgMemoryEntry++) 153 { 154 if (Msg == MsgMemoryEntry->Message) 155 { 156 return MsgMemoryEntry; 157 } 158 } 159 160 return NULL; 161 } 162 163 static UINT FASTCALL 164 MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam) 165 { 166 CREATESTRUCTW *Cs; 167 PUNICODE_STRING WindowName; 168 PUNICODE_STRING ClassName; 169 UINT Size = 0; 170 171 _SEH2_TRY 172 { 173 if (MMS_SIZE_WPARAM == MsgMemoryEntry->Size) 174 { 175 Size = (UINT)wParam; 176 } 177 else if (MMS_SIZE_WPARAMWCHAR == MsgMemoryEntry->Size) 178 { 179 Size = (UINT) (wParam * sizeof(WCHAR)); 180 } 181 else if (MMS_SIZE_LPARAMSZ == MsgMemoryEntry->Size) 182 { 183 // WM_SETTEXT and WM_SETTINGCHANGE can be null! 184 if (!lParam) 185 { 186 TRACE("lParam is NULL!\n"); 187 Size = 0; 188 } 189 else 190 Size = (UINT) ((wcslen((PWSTR) lParam) + 1) * sizeof(WCHAR)); 191 } 192 else if (MMS_SIZE_SPECIAL == MsgMemoryEntry->Size) 193 { 194 switch(MsgMemoryEntry->Message) 195 { 196 case WM_CREATE: 197 case WM_NCCREATE: 198 Cs = (CREATESTRUCTW *) lParam; 199 WindowName = (PUNICODE_STRING) Cs->lpszName; 200 ClassName = (PUNICODE_STRING) Cs->lpszClass; 201 Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR); 202 if (IS_ATOM(ClassName->Buffer)) 203 { 204 Size += sizeof(WCHAR) + sizeof(ATOM); 205 } 206 else 207 { 208 Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR); 209 } 210 break; 211 212 case WM_NCCALCSIZE: 213 Size = wParam ? sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS) : sizeof(RECT); 214 break; 215 216 case WM_COPYDATA: 217 { 218 COPYDATASTRUCT *cds = (COPYDATASTRUCT *)lParam; 219 Size = sizeof(COPYDATASTRUCT) + cds->cbData; 220 } 221 break; 222 223 default: 224 ASSERT(FALSE); 225 Size = 0; 226 break; 227 } 228 } 229 else 230 { 231 Size = MsgMemoryEntry->Size; 232 } 233 } 234 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 235 { 236 ERR("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode()); 237 Size = 0; 238 } 239 _SEH2_END; 240 return Size; 241 } 242 243 UINT lParamMemorySize(UINT Msg, WPARAM wParam, LPARAM lParam) 244 { 245 PMSGMEMORY MsgMemoryEntry = FindMsgMemory(Msg); 246 if(MsgMemoryEntry == NULL) return 0; 247 return MsgMemorySize(MsgMemoryEntry, wParam, lParam); 248 } 249 250 static NTSTATUS 251 PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolNeeded) 252 { 253 NCCALCSIZE_PARAMS *UnpackedNcCalcsize; 254 NCCALCSIZE_PARAMS *PackedNcCalcsize; 255 CREATESTRUCTW *UnpackedCs; 256 CREATESTRUCTW *PackedCs; 257 PLARGE_STRING WindowName; 258 PUNICODE_STRING ClassName; 259 POOL_TYPE PoolType; 260 UINT Size; 261 PCHAR CsData; 262 263 *lParamPacked = lParam; 264 265 if (NonPagedPoolNeeded) 266 PoolType = NonPagedPool; 267 else 268 PoolType = PagedPool; 269 270 if (WM_NCCALCSIZE == Msg && wParam) 271 { 272 273 UnpackedNcCalcsize = (NCCALCSIZE_PARAMS *) lParam; 274 PackedNcCalcsize = ExAllocatePoolWithTag(PoolType, 275 sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS), 276 TAG_MSG); 277 278 if (NULL == PackedNcCalcsize) 279 { 280 ERR("Not enough memory to pack lParam\n"); 281 return STATUS_NO_MEMORY; 282 } 283 RtlCopyMemory(PackedNcCalcsize, UnpackedNcCalcsize, sizeof(NCCALCSIZE_PARAMS)); 284 PackedNcCalcsize->lppos = (PWINDOWPOS) (PackedNcCalcsize + 1); 285 RtlCopyMemory(PackedNcCalcsize->lppos, UnpackedNcCalcsize->lppos, sizeof(WINDOWPOS)); 286 *lParamPacked = (LPARAM) PackedNcCalcsize; 287 } 288 else if (WM_CREATE == Msg || WM_NCCREATE == Msg) 289 { 290 UnpackedCs = (CREATESTRUCTW *) lParam; 291 WindowName = (PLARGE_STRING) UnpackedCs->lpszName; 292 ClassName = (PUNICODE_STRING) UnpackedCs->lpszClass; 293 Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR); 294 if (IS_ATOM(ClassName->Buffer)) 295 { 296 Size += sizeof(WCHAR) + sizeof(ATOM); 297 } 298 else 299 { 300 Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR); 301 } 302 PackedCs = ExAllocatePoolWithTag(PoolType, Size, TAG_MSG); 303 if (NULL == PackedCs) 304 { 305 ERR("Not enough memory to pack lParam\n"); 306 return STATUS_NO_MEMORY; 307 } 308 RtlCopyMemory(PackedCs, UnpackedCs, sizeof(CREATESTRUCTW)); 309 CsData = (PCHAR) (PackedCs + 1); 310 PackedCs->lpszName = (LPCWSTR) (CsData - (PCHAR) PackedCs); 311 RtlCopyMemory(CsData, WindowName->Buffer, WindowName->Length); 312 CsData += WindowName->Length; 313 *((WCHAR *) CsData) = L'\0'; 314 CsData += sizeof(WCHAR); 315 PackedCs->lpszClass = (LPCWSTR) (CsData - (PCHAR) PackedCs); 316 if (IS_ATOM(ClassName->Buffer)) 317 { 318 *((WCHAR *) CsData) = L'A'; 319 CsData += sizeof(WCHAR); 320 *((ATOM *) CsData) = (ATOM)(DWORD_PTR) ClassName->Buffer; 321 CsData += sizeof(ATOM); 322 } 323 else 324 { 325 NT_ASSERT(ClassName->Buffer != NULL); 326 *((WCHAR *) CsData) = L'S'; 327 CsData += sizeof(WCHAR); 328 RtlCopyMemory(CsData, ClassName->Buffer, ClassName->Length); 329 CsData += ClassName->Length; 330 *((WCHAR *) CsData) = L'\0'; 331 CsData += sizeof(WCHAR); 332 } 333 ASSERT(CsData == (PCHAR) PackedCs + Size); 334 *lParamPacked = (LPARAM) PackedCs; 335 } 336 else if (PoolType == NonPagedPool) 337 { 338 PMSGMEMORY MsgMemoryEntry; 339 PVOID PackedData; 340 SIZE_T size; 341 342 MsgMemoryEntry = FindMsgMemory(Msg); 343 344 if (!MsgMemoryEntry) 345 { 346 /* Keep previous behavior */ 347 return STATUS_SUCCESS; 348 } 349 size = MsgMemorySize(MsgMemoryEntry, wParam, lParam); 350 if (!size) 351 { 352 ERR("No size for lParamPacked\n"); 353 return STATUS_SUCCESS; 354 } 355 PackedData = ExAllocatePoolWithTag(NonPagedPool, size, TAG_MSG); 356 if (PackedData == NULL) 357 { 358 ERR("Not enough memory to pack lParam\n"); 359 return STATUS_NO_MEMORY; 360 } 361 RtlCopyMemory(PackedData, (PVOID)lParam, MsgMemorySize(MsgMemoryEntry, wParam, lParam)); 362 *lParamPacked = (LPARAM)PackedData; 363 } 364 365 return STATUS_SUCCESS; 366 } 367 368 static NTSTATUS 369 UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolUsed) 370 { 371 NCCALCSIZE_PARAMS *UnpackedParams; 372 NCCALCSIZE_PARAMS *PackedParams; 373 PWINDOWPOS UnpackedWindowPos; 374 375 if (lParamPacked == lParam) 376 { 377 return STATUS_SUCCESS; 378 } 379 380 if (WM_NCCALCSIZE == Msg && wParam) 381 { 382 PackedParams = (NCCALCSIZE_PARAMS *) lParamPacked; 383 UnpackedParams = (NCCALCSIZE_PARAMS *) lParam; 384 UnpackedWindowPos = UnpackedParams->lppos; 385 RtlCopyMemory(UnpackedParams, PackedParams, sizeof(NCCALCSIZE_PARAMS)); 386 UnpackedParams->lppos = UnpackedWindowPos; 387 RtlCopyMemory(UnpackedWindowPos, PackedParams + 1, sizeof(WINDOWPOS)); 388 ExFreePool((PVOID) lParamPacked); 389 390 return STATUS_SUCCESS; 391 } 392 else if (WM_CREATE == Msg || WM_NCCREATE == Msg) 393 { 394 ExFreePool((PVOID) lParamPacked); 395 396 return STATUS_SUCCESS; 397 } 398 else if (NonPagedPoolUsed) 399 { 400 PMSGMEMORY MsgMemoryEntry; 401 MsgMemoryEntry = FindMsgMemory(Msg); 402 ASSERT(MsgMemoryEntry); 403 404 if (MsgMemoryEntry->Flags == MMS_FLAG_READWRITE) 405 { 406 //RtlCopyMemory((PVOID)lParam, (PVOID)lParamPacked, MsgMemoryEntry->Size); 407 } 408 ExFreePool((PVOID) lParamPacked); 409 return STATUS_SUCCESS; 410 } 411 412 ASSERT(FALSE); 413 414 return STATUS_INVALID_PARAMETER; 415 } 416 417 static NTSTATUS FASTCALL 418 CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry) 419 { 420 NTSTATUS Status; 421 422 PVOID KernelMem; 423 UINT Size; 424 425 *KernelModeMsg = *UserModeMsg; 426 427 /* See if this message type is present in the table */ 428 if (NULL == MsgMemoryEntry) 429 { 430 /* Not present, no copying needed */ 431 return STATUS_SUCCESS; 432 } 433 434 /* Determine required size */ 435 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam); 436 437 if (0 != Size) 438 { 439 /* Allocate kernel mem */ 440 KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG); 441 if (NULL == KernelMem) 442 { 443 ERR("Not enough memory to copy message to kernel mem\n"); 444 return STATUS_NO_MEMORY; 445 } 446 KernelModeMsg->lParam = (LPARAM) KernelMem; 447 448 /* Copy data if required */ 449 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ)) 450 { 451 TRACE("Copy Message %u from usermode buffer\n", KernelModeMsg->message); 452 Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size); 453 if (! NT_SUCCESS(Status)) 454 { 455 ERR("Failed to copy message to kernel: invalid usermode lParam buffer\n"); 456 ExFreePoolWithTag(KernelMem, TAG_MSG); 457 return Status; 458 } 459 } 460 else 461 { 462 /* Make sure we don't pass any secrets to usermode */ 463 RtlZeroMemory(KernelMem, Size); 464 } 465 } 466 else 467 { 468 KernelModeMsg->lParam = 0; 469 } 470 471 return STATUS_SUCCESS; 472 } 473 474 static NTSTATUS FASTCALL 475 CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg) 476 { 477 NTSTATUS Status; 478 PMSGMEMORY MsgMemoryEntry; 479 UINT Size; 480 481 /* See if this message type is present in the table */ 482 MsgMemoryEntry = FindMsgMemory(UserModeMsg->message); 483 if (NULL == MsgMemoryEntry) 484 { 485 /* Not present, no copying needed */ 486 return STATUS_SUCCESS; 487 } 488 489 /* Determine required size */ 490 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam); 491 492 if (0 != Size) 493 { 494 /* Copy data if required */ 495 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE)) 496 { 497 Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size); 498 if (! NT_SUCCESS(Status)) 499 { 500 ERR("Failed to copy message from kernel: invalid usermode lParam buffer\n"); 501 ExFreePool((PVOID) KernelModeMsg->lParam); 502 return Status; 503 } 504 } 505 ExFreePool((PVOID) KernelModeMsg->lParam); 506 } 507 508 return STATUS_SUCCESS; 509 } 510 511 // 512 // Wakeup any thread/process waiting on idle input. 513 // 514 VOID FASTCALL 515 IdlePing(VOID) 516 { 517 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process(); 518 PTHREADINFO pti; 519 520 pti = PsGetCurrentThreadWin32Thread(); 521 522 if ( pti ) 523 { 524 pti->pClientInfo->cSpins = 0; // Reset spins. 525 526 if ( pti->pDeskInfo && pti == gptiForeground ) 527 { 528 if ( pti->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) || 529 pti->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) ) 530 { 531 co_HOOK_CallHooks(WH_FOREGROUNDIDLE,HC_ACTION,0,0); 532 } 533 } 534 } 535 536 TRACE("IdlePing ppi %p\n", ppi); 537 if ( ppi && ppi->InputIdleEvent ) 538 { 539 TRACE("InputIdleEvent\n"); 540 KeSetEvent( ppi->InputIdleEvent, IO_NO_INCREMENT, FALSE); 541 } 542 } 543 544 VOID FASTCALL 545 IdlePong(VOID) 546 { 547 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process(); 548 549 TRACE("IdlePong ppi %p\n", ppi); 550 if ( ppi && ppi->InputIdleEvent ) 551 { 552 KeClearEvent(ppi->InputIdleEvent); 553 } 554 } 555 556 static BOOL is_message_broadcastable(UINT msg) 557 { 558 return msg < WM_USER || msg >= 0xc000; 559 } 560 561 UINT FASTCALL 562 GetWakeMask(UINT first, UINT last ) 563 { 564 UINT mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */ 565 566 if (first || last) 567 { 568 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY; 569 if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) || 570 ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE; 571 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER; 572 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER; 573 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT; 574 } 575 else mask = QS_ALLINPUT; 576 577 return mask; 578 } 579 580 static VOID FASTCALL 581 IntCallWndProc( PWND Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) 582 { 583 BOOL SameThread = FALSE; 584 CWPSTRUCT CWP; 585 586 if (Window->head.pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread())) 587 SameThread = TRUE; 588 589 CWP.hwnd = hWnd; 590 CWP.message = Msg; 591 CWP.wParam = wParam; 592 CWP.lParam = lParam; 593 co_HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, SameThread, (LPARAM)&CWP ); 594 } 595 596 static VOID FASTCALL 597 IntCallWndProcRet ( PWND Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *uResult) 598 { 599 BOOL SameThread = FALSE; 600 CWPRETSTRUCT CWPR; 601 602 if (Window->head.pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread())) 603 SameThread = TRUE; 604 605 CWPR.hwnd = hWnd; 606 CWPR.message = Msg; 607 CWPR.wParam = wParam; 608 CWPR.lParam = lParam; 609 CWPR.lResult = uResult ? (*uResult) : 0; 610 co_HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, SameThread, (LPARAM)&CWPR ); 611 } 612 613 static LRESULT handle_internal_message( PWND pWnd, UINT msg, WPARAM wparam, LPARAM lparam ) 614 { 615 LRESULT lRes; 616 // USER_REFERENCE_ENTRY Ref; 617 // PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 618 619 if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd)) 620 return 0; 621 622 TRACE("Internal Event Msg 0x%x hWnd 0x%p\n", msg, pWnd->head.h); 623 624 switch(msg) 625 { 626 case WM_ASYNC_SHOWWINDOW: 627 return co_WinPosShowWindow( pWnd, wparam ); 628 case WM_ASYNC_SETWINDOWPOS: 629 { 630 PWINDOWPOS winpos = (PWINDOWPOS)lparam; 631 if (!winpos) return 0; 632 lRes = co_WinPosSetWindowPos( pWnd, 633 winpos->hwndInsertAfter, 634 winpos->x, 635 winpos->y, 636 winpos->cx, 637 winpos->cy, 638 winpos->flags); 639 ExFreePoolWithTag(winpos, USERTAG_SWP); 640 return lRes; 641 } 642 case WM_ASYNC_DESTROYWINDOW: 643 { 644 ERR("WM_ASYNC_DESTROYWINDOW\n"); 645 if (pWnd->style & WS_CHILD) 646 return co_UserFreeWindow(pWnd, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE); 647 else 648 co_UserDestroyWindow(pWnd); 649 } 650 } 651 return 0; 652 } 653 654 static LRESULT handle_internal_events( PTHREADINFO pti, PWND pWnd, DWORD dwQEvent, LONG_PTR ExtraInfo, PMSG pMsg) 655 { 656 LRESULT Result = 0; 657 658 switch(dwQEvent) 659 { 660 case POSTEVENT_NWE: 661 { 662 co_EVENT_CallEvents( pMsg->message, pMsg->hwnd, pMsg->wParam, ExtraInfo); 663 } 664 break; 665 case POSTEVENT_SAW: 666 { 667 //ERR("HIE : SAW : pti 0x%p hWnd 0x%p\n",pti,pMsg->hwnd); 668 IntActivateWindow((PWND)pMsg->wParam, pti, (HANDLE)pMsg->lParam, (DWORD)ExtraInfo); 669 } 670 break; 671 case POSTEVENT_DAW: 672 { 673 //ERR("HIE : DAW : pti 0x%p tid 0x%p hWndPrev 0x%p\n",pti,ExtraInfo,pMsg->hwnd); 674 IntDeactivateWindow(pti, (HANDLE)ExtraInfo); 675 } 676 break; 677 } 678 return Result; 679 } 680 681 LRESULT FASTCALL 682 IntDispatchMessage(PMSG pMsg) 683 { 684 LARGE_INTEGER TickCount; 685 LONG Time; 686 LRESULT retval = 0; 687 PTHREADINFO pti; 688 PWND Window = NULL; 689 BOOL DoCallBack = TRUE; 690 691 if (pMsg->hwnd) 692 { 693 Window = UserGetWindowObject(pMsg->hwnd); 694 if (!Window) return 0; 695 } 696 697 pti = PsGetCurrentThreadWin32Thread(); 698 699 if ( Window && Window->head.pti != pti) 700 { 701 EngSetLastError( ERROR_MESSAGE_SYNC_ONLY ); 702 return 0; 703 } 704 705 if (((pMsg->message == WM_SYSTIMER) || 706 (pMsg->message == WM_TIMER)) && 707 (pMsg->lParam) ) 708 { 709 if (pMsg->message == WM_TIMER) 710 { 711 if (ValidateTimerCallback(pti,pMsg->lParam)) 712 { 713 KeQueryTickCount(&TickCount); 714 Time = MsqCalculateMessageTime(&TickCount); 715 retval = co_IntCallWindowProc((WNDPROC)pMsg->lParam, 716 TRUE, 717 pMsg->hwnd, 718 WM_TIMER, 719 pMsg->wParam, 720 (LPARAM)Time, 721 -1); 722 } 723 return retval; 724 } 725 else 726 { 727 PTIMER pTimer = FindSystemTimer(pMsg); 728 if (pTimer && pTimer->pfn) 729 { 730 KeQueryTickCount(&TickCount); 731 Time = MsqCalculateMessageTime(&TickCount); 732 pTimer->pfn(pMsg->hwnd, WM_SYSTIMER, (UINT)pMsg->wParam, Time); 733 } 734 return 0; 735 } 736 } 737 // Need a window! 738 if ( !Window ) return 0; 739 740 if (pMsg->message == WM_PAINT) Window->state |= WNDS_PAINTNOTPROCESSED; 741 742 if ( Window->state & WNDS_SERVERSIDEWINDOWPROC ) 743 { 744 TRACE("Dispatch: Server Side Window Procedure\n"); 745 switch(Window->fnid) 746 { 747 case FNID_DESKTOP: 748 DoCallBack = !DesktopWindowProc( Window, 749 pMsg->message, 750 pMsg->wParam, 751 pMsg->lParam, 752 &retval); 753 break; 754 case FNID_MESSAGEWND: 755 DoCallBack = !UserMessageWindowProc( Window, 756 pMsg->message, 757 pMsg->wParam, 758 pMsg->lParam, 759 &retval); 760 break; 761 case FNID_MENU: 762 DoCallBack = !PopupMenuWndProc( Window, 763 pMsg->message, 764 pMsg->wParam, 765 pMsg->lParam, 766 &retval); 767 break; 768 } 769 } 770 771 /* Since we are doing a callback on the same thread right away, there is 772 no need to copy the lparam to kernel mode and then back to usermode. 773 We just pretend it isn't a pointer */ 774 775 if (DoCallBack) 776 retval = co_IntCallWindowProc( Window->lpfnWndProc, 777 !Window->Unicode, 778 pMsg->hwnd, 779 pMsg->message, 780 pMsg->wParam, 781 pMsg->lParam, 782 -1); 783 784 if ( pMsg->message == WM_PAINT && 785 VerifyWnd(Window) && 786 Window->state & WNDS_PAINTNOTPROCESSED ) // <--- Cleared, paint was already processed! 787 { 788 Window->state2 &= ~WNDS2_WMPAINTSENT; 789 /* send a WM_ERASEBKGND if the non-client area is still invalid */ 790 ERR("Message WM_PAINT count %d Internal Paint Set? %s\n",Window->head.pti->cPaintsReady, Window->state & WNDS_INTERNALPAINT ? "TRUE" : "FALSE"); 791 IntPaintWindow( Window ); 792 } 793 794 return retval; 795 } 796 797 /* 798 * Internal version of PeekMessage() doing all the work 799 * 800 * MSDN: 801 * Sent messages 802 * Posted messages 803 * Input (hardware) messages and system internal events 804 * Sent messages (again) 805 * WM_PAINT messages 806 * WM_TIMER messages 807 */ 808 BOOL APIENTRY 809 co_IntPeekMessage( PMSG Msg, 810 PWND Window, 811 UINT MsgFilterMin, 812 UINT MsgFilterMax, 813 UINT RemoveMsg, 814 LONG_PTR *ExtraInfo, 815 BOOL bGMSG ) 816 { 817 PTHREADINFO pti; 818 LARGE_INTEGER LargeTickCount; 819 BOOL RemoveMessages; 820 UINT ProcessMask; 821 BOOL Hit = FALSE; 822 823 pti = PsGetCurrentThreadWin32Thread(); 824 825 RemoveMessages = RemoveMsg & PM_REMOVE; 826 ProcessMask = HIWORD(RemoveMsg); 827 828 /* Hint, "If wMsgFilterMin and wMsgFilterMax are both zero, PeekMessage returns 829 all available messages (that is, no range filtering is performed)". */ 830 if (!ProcessMask) ProcessMask = (QS_ALLPOSTMESSAGE|QS_ALLINPUT); 831 832 IdlePong(); 833 834 do 835 { 836 KeQueryTickCount(&LargeTickCount); 837 pti->timeLast = LargeTickCount.u.LowPart; 838 pti->pcti->tickLastMsgChecked = LargeTickCount.u.LowPart; 839 840 // Post mouse moves while looping through peek messages. 841 if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED) 842 { 843 IntCoalesceMouseMove(pti); 844 } 845 846 /* Dispatch sent messages here. */ 847 while ( co_MsqDispatchOneSentMessage(pti) ) 848 { 849 /* if some PM_QS* flags were specified, only handle sent messages from now on */ 850 if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE; // wine does this; ProcessMask = QS_SENDMESSAGE; 851 } 852 if (Hit) return FALSE; 853 854 /* Clear changed bits so we can wait on them if we don't find a message */ 855 if (ProcessMask & QS_POSTMESSAGE) 856 { 857 pti->pcti->fsChangeBits &= ~(QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER); 858 if (MsgFilterMin == 0 && MsgFilterMax == 0) // Wine hack does this; ~0U) 859 { 860 pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE; 861 } 862 } 863 864 if (ProcessMask & QS_INPUT) 865 { 866 pti->pcti->fsChangeBits &= ~QS_INPUT; 867 } 868 869 /* Now check for normal messages. */ 870 if (( (ProcessMask & QS_POSTMESSAGE) || 871 (ProcessMask & QS_HOTKEY) ) && 872 MsqPeekMessage( pti, 873 RemoveMessages, 874 Window, 875 MsgFilterMin, 876 MsgFilterMax, 877 ProcessMask, 878 ExtraInfo, 879 0, 880 Msg )) 881 { 882 return TRUE; 883 } 884 885 /* Only check for quit messages if not posted messages pending. */ 886 if (ProcessMask & QS_POSTMESSAGE && pti->QuitPosted) 887 { 888 /* According to the PSDK, WM_QUIT messages are always returned, regardless 889 of the filter specified */ 890 Msg->hwnd = NULL; 891 Msg->message = WM_QUIT; 892 Msg->wParam = pti->exitCode; 893 Msg->lParam = 0; 894 if (RemoveMessages) 895 { 896 pti->QuitPosted = FALSE; 897 ClearMsgBitsMask(pti, QS_POSTMESSAGE); 898 pti->pcti->fsWakeBits &= ~QS_ALLPOSTMESSAGE; 899 pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE; 900 } 901 return TRUE; 902 } 903 904 /* Check for hardware events. */ 905 if ((ProcessMask & QS_INPUT) && 906 co_MsqPeekHardwareMessage( pti, 907 RemoveMessages, 908 Window, 909 MsgFilterMin, 910 MsgFilterMax, 911 ProcessMask, 912 Msg)) 913 { 914 return TRUE; 915 } 916 917 /* Now check for System Event messages. */ 918 { 919 LONG_PTR eExtraInfo; 920 MSG eMsg; 921 DWORD dwQEvent; 922 if (MsqPeekMessage( pti, 923 TRUE, 924 Window, 925 0, 926 0, 927 QS_EVENT, 928 &eExtraInfo, 929 &dwQEvent, 930 &eMsg )) 931 { 932 handle_internal_events( pti, Window, dwQEvent, eExtraInfo, &eMsg); 933 continue; 934 } 935 } 936 937 /* Check for sent messages again. */ 938 while ( co_MsqDispatchOneSentMessage(pti) ) 939 { 940 if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE; 941 } 942 if (Hit) return FALSE; 943 944 /* Check for paint messages. */ 945 if ((ProcessMask & QS_PAINT) && 946 pti->cPaintsReady && 947 IntGetPaintMessage( Window, 948 MsgFilterMin, 949 MsgFilterMax, 950 pti, 951 Msg, 952 RemoveMessages)) 953 { 954 return TRUE; 955 } 956 957 /* This is correct, check for the current threads timers waiting to be 958 posted to this threads message queue. If any we loop again. 959 */ 960 if ((ProcessMask & QS_TIMER) && 961 PostTimerMessages(Window)) 962 { 963 continue; 964 } 965 966 return FALSE; 967 } 968 while (TRUE); 969 970 return TRUE; 971 } 972 973 BOOL FASTCALL 974 co_IntWaitMessage( PWND Window, 975 UINT MsgFilterMin, 976 UINT MsgFilterMax ) 977 { 978 PTHREADINFO pti; 979 NTSTATUS Status = STATUS_SUCCESS; 980 MSG Msg; 981 LONG_PTR ExtraInfo = 0; 982 983 pti = PsGetCurrentThreadWin32Thread(); 984 985 do 986 { 987 if ( co_IntPeekMessage( &Msg, // Dont reenter! 988 Window, 989 MsgFilterMin, 990 MsgFilterMax, 991 MAKELONG( PM_NOREMOVE, GetWakeMask( MsgFilterMin, MsgFilterMax)), 992 &ExtraInfo, 993 TRUE ) ) // act like GetMessage. 994 { 995 return TRUE; 996 } 997 998 /* Nothing found. Wait for new messages. */ 999 Status = co_MsqWaitForNewMessages( pti, 1000 Window, 1001 MsgFilterMin, 1002 MsgFilterMax); 1003 if (!NT_SUCCESS(Status)) 1004 { 1005 SetLastNtError(Status); 1006 ERR("Exit co_IntWaitMessage on error!\n"); 1007 return FALSE; 1008 } 1009 if (Status == STATUS_USER_APC || Status == STATUS_TIMEOUT) 1010 { 1011 return FALSE; 1012 } 1013 } 1014 while ( TRUE ); 1015 1016 return FALSE; 1017 } 1018 1019 BOOL APIENTRY 1020 co_IntGetPeekMessage( PMSG pMsg, 1021 HWND hWnd, 1022 UINT MsgFilterMin, 1023 UINT MsgFilterMax, 1024 UINT RemoveMsg, 1025 BOOL bGMSG ) 1026 { 1027 PWND Window; 1028 PTHREADINFO pti; 1029 BOOL Present = FALSE; 1030 NTSTATUS Status; 1031 LONG_PTR ExtraInfo = 0; 1032 1033 if ( hWnd == HWND_TOPMOST || hWnd == HWND_BROADCAST ) 1034 hWnd = HWND_BOTTOM; 1035 1036 /* Validate input */ 1037 if (hWnd && hWnd != HWND_BOTTOM) 1038 { 1039 if (!(Window = UserGetWindowObject(hWnd))) 1040 { 1041 if (bGMSG) 1042 return -1; 1043 else 1044 return FALSE; 1045 } 1046 } 1047 else 1048 { 1049 Window = (PWND)hWnd; 1050 } 1051 1052 if (MsgFilterMax < MsgFilterMin) 1053 { 1054 MsgFilterMin = 0; 1055 MsgFilterMax = 0; 1056 } 1057 1058 if (bGMSG) 1059 { 1060 RemoveMsg |= ((GetWakeMask( MsgFilterMin, MsgFilterMax ))<< 16); 1061 } 1062 1063 pti = PsGetCurrentThreadWin32Thread(); 1064 pti->pClientInfo->cSpins++; // Bump up the spin count. 1065 1066 do 1067 { 1068 Present = co_IntPeekMessage( pMsg, 1069 Window, 1070 MsgFilterMin, 1071 MsgFilterMax, 1072 RemoveMsg, 1073 &ExtraInfo, 1074 bGMSG ); 1075 if (Present) 1076 { 1077 /* GetMessage or PostMessage must never get messages that contain pointers */ 1078 ASSERT(FindMsgMemory(pMsg->message) == NULL); 1079 1080 if ( pMsg->message >= WM_DDE_FIRST && pMsg->message <= WM_DDE_LAST ) 1081 { 1082 if (!IntDdeGetMessageHook(pMsg, ExtraInfo)) 1083 { 1084 TRACE("DDE Get return ERROR\n"); 1085 continue; 1086 } 1087 } 1088 1089 if (pMsg->message != WM_PAINT && pMsg->message != WM_QUIT) 1090 { 1091 if (!RtlEqualMemory(&pti->ptLast, &pMsg->pt, sizeof(POINT))) 1092 { 1093 pti->TIF_flags |= TIF_MSGPOSCHANGED; 1094 } 1095 pti->timeLast = pMsg->time; 1096 pti->ptLast = pMsg->pt; 1097 } 1098 1099 // The WH_GETMESSAGE hook enables an application to monitor messages about to 1100 // be returned by the GetMessage or PeekMessage function. 1101 1102 co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)pMsg); 1103 1104 if ( bGMSG || pMsg->message == WM_PAINT) break; 1105 } 1106 1107 if ( bGMSG ) 1108 { 1109 Status = co_MsqWaitForNewMessages( pti, 1110 Window, 1111 MsgFilterMin, 1112 MsgFilterMax); 1113 if ( !NT_SUCCESS(Status) || 1114 Status == STATUS_USER_APC || 1115 Status == STATUS_TIMEOUT ) 1116 { 1117 Present = -1; 1118 break; 1119 } 1120 } 1121 else 1122 { 1123 if (!(RemoveMsg & PM_NOYIELD)) 1124 { 1125 IdlePing(); 1126 // Yield this thread! 1127 UserLeave(); 1128 ZwYieldExecution(); 1129 UserEnterExclusive(); 1130 // Fall through to exit. 1131 IdlePong(); 1132 } 1133 break; 1134 } 1135 } 1136 while( bGMSG && !Present ); 1137 1138 // Been spinning, time to swap vinyl... 1139 if (pti->pClientInfo->cSpins >= 100) 1140 { 1141 // Clear the spin cycle to fix the mix. 1142 pti->pClientInfo->cSpins = 0; 1143 //if (!(pti->TIF_flags & TIF_SPINNING)) // FIXME: Need to swap vinyl... 1144 } 1145 return Present; 1146 } 1147 1148 BOOL FASTCALL 1149 UserPostThreadMessage( PTHREADINFO pti, 1150 UINT Msg, 1151 WPARAM wParam, 1152 LPARAM lParam ) 1153 { 1154 MSG Message; 1155 LARGE_INTEGER LargeTickCount; 1156 1157 if (is_pointer_message(Msg)) 1158 { 1159 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY ); 1160 return FALSE; 1161 } 1162 Message.hwnd = NULL; 1163 Message.message = Msg; 1164 Message.wParam = wParam; 1165 Message.lParam = lParam; 1166 Message.pt = gpsi->ptCursor; 1167 1168 KeQueryTickCount(&LargeTickCount); 1169 Message.time = MsqCalculateMessageTime(&LargeTickCount); 1170 MsqPostMessage(pti, &Message, FALSE, QS_POSTMESSAGE, 0, 0); 1171 return TRUE; 1172 } 1173 1174 PTHREADINFO FASTCALL 1175 IntSendTo(PWND Window, PTHREADINFO ptiCur, UINT Msg) 1176 { 1177 if ( ptiCur ) 1178 { 1179 if (!Window || 1180 Window->head.pti == ptiCur ) 1181 { 1182 return NULL; 1183 } 1184 } 1185 return Window ? Window->head.pti : NULL; 1186 } 1187 1188 BOOL FASTCALL 1189 UserPostMessage( HWND Wnd, 1190 UINT Msg, 1191 WPARAM wParam, 1192 LPARAM lParam ) 1193 { 1194 PTHREADINFO pti; 1195 MSG Message; 1196 LARGE_INTEGER LargeTickCount; 1197 LONG_PTR ExtraInfo = 0; 1198 1199 Message.hwnd = Wnd; 1200 Message.message = Msg; 1201 Message.wParam = wParam; 1202 Message.lParam = lParam; 1203 Message.pt = gpsi->ptCursor; 1204 KeQueryTickCount(&LargeTickCount); 1205 Message.time = MsqCalculateMessageTime(&LargeTickCount); 1206 1207 if (is_pointer_message(Message.message)) 1208 { 1209 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY ); 1210 return FALSE; 1211 } 1212 1213 if (Wnd == HWND_BROADCAST || Wnd == HWND_TOPMOST) 1214 { 1215 HWND *List; 1216 PWND DesktopWindow; 1217 ULONG i; 1218 1219 if (!is_message_broadcastable(Msg)) return TRUE; 1220 1221 DesktopWindow = UserGetDesktopWindow(); 1222 List = IntWinListChildren(DesktopWindow); 1223 1224 if (List != NULL) 1225 { 1226 UserPostMessage(DesktopWindow->head.h, Msg, wParam, lParam); 1227 for (i = 0; List[i]; i++) 1228 { 1229 PWND pwnd = UserGetWindowObject(List[i]); 1230 if (!pwnd) continue; 1231 1232 if ( pwnd->fnid == FNID_MENU || // Also need pwnd->pcls->atomClassName == gaOleMainThreadWndClass 1233 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 1234 continue; 1235 1236 UserPostMessage(List[i], Msg, wParam, lParam); 1237 } 1238 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 1239 } 1240 } 1241 else 1242 { 1243 PWND Window; 1244 1245 if (!Wnd) 1246 { 1247 return UserPostThreadMessage( gptiCurrent, 1248 Msg, 1249 wParam, 1250 lParam); 1251 } 1252 1253 Window = UserGetWindowObject(Wnd); 1254 if ( !Window ) 1255 { 1256 ERR("UserPostMessage: Invalid handle 0x%p Msg 0x%x!\n", Wnd, Msg); 1257 return FALSE; 1258 } 1259 1260 pti = Window->head.pti; 1261 1262 if ( pti->TIF_flags & TIF_INCLEANUP ) 1263 { 1264 ERR("Attempted to post message to window %p when the thread is in cleanup!\n", Wnd); 1265 return FALSE; 1266 } 1267 1268 if ( Window->state & WNDS_DESTROYED ) 1269 { 1270 ERR("Attempted to post message to window %p that is being destroyed!\n", Wnd); 1271 /* FIXME: Last error code? */ 1272 return FALSE; 1273 } 1274 1275 if ( Msg >= WM_DDE_FIRST && Msg <= WM_DDE_LAST ) 1276 { 1277 if (!IntDdePostMessageHook(Window, Msg, wParam, &lParam, &ExtraInfo)) 1278 { 1279 TRACE("Posting Exit DDE 0x%x\n",Msg); 1280 return FALSE; 1281 } 1282 Message.lParam = lParam; 1283 } 1284 1285 MsqPostMessage(pti, &Message, FALSE, QS_POSTMESSAGE, 0, ExtraInfo); 1286 } 1287 return TRUE; 1288 } 1289 1290 LRESULT FASTCALL 1291 co_IntSendMessage( HWND hWnd, 1292 UINT Msg, 1293 WPARAM wParam, 1294 LPARAM lParam ) 1295 { 1296 ULONG_PTR Result = 0; 1297 1298 if (co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result)) 1299 { 1300 return (LRESULT)Result; 1301 } 1302 return 0; 1303 } 1304 1305 static LRESULT FASTCALL 1306 co_IntSendMessageTimeoutSingle( HWND hWnd, 1307 UINT Msg, 1308 WPARAM wParam, 1309 LPARAM lParam, 1310 UINT uFlags, 1311 UINT uTimeout, 1312 ULONG_PTR *uResult ) 1313 { 1314 NTSTATUS Status = STATUS_SUCCESS; 1315 PWND Window = NULL; 1316 PMSGMEMORY MsgMemoryEntry; 1317 INT lParamBufferSize; 1318 LPARAM lParamPacked; 1319 PTHREADINFO Win32Thread, ptiSendTo = NULL; 1320 ULONG_PTR Result = 0; 1321 DECLARE_RETURN(LRESULT); 1322 USER_REFERENCE_ENTRY Ref; 1323 BOOL DoCallBack = TRUE; 1324 1325 if (!(Window = UserGetWindowObject(hWnd))) 1326 { 1327 TRACE("SendMessageTimeoutSingle: Invalid handle 0x%p!\n",hWnd); 1328 RETURN( FALSE); 1329 } 1330 1331 UserRefObjectCo(Window, &Ref); 1332 1333 Win32Thread = PsGetCurrentThreadWin32Thread(); 1334 1335 ptiSendTo = IntSendTo(Window, Win32Thread, Msg); 1336 1337 if ( Msg >= WM_DDE_FIRST && Msg <= WM_DDE_LAST ) 1338 { 1339 if (!IntDdeSendMessageHook(Window, Msg, wParam, lParam)) 1340 { 1341 ERR("Sending Exit DDE 0x%x\n",Msg); 1342 RETURN( FALSE); 1343 } 1344 } 1345 1346 if ( !ptiSendTo ) 1347 { 1348 if (Win32Thread->TIF_flags & TIF_INCLEANUP) 1349 { 1350 /* Never send messages to exiting threads */ 1351 RETURN( FALSE); 1352 } 1353 1354 if (Msg & 0x80000000) 1355 { 1356 TRACE("SMTS: Internal Message!\n"); 1357 Result = (ULONG_PTR)handle_internal_message( Window, Msg, wParam, lParam ); 1358 if (uResult) *uResult = Result; 1359 RETURN( TRUE); 1360 } 1361 1362 // Only happens when calling the client! 1363 IntCallWndProc( Window, hWnd, Msg, wParam, lParam); 1364 1365 if ( Window->state & WNDS_SERVERSIDEWINDOWPROC ) 1366 { 1367 TRACE("SMT: Server Side Window Procedure\n"); 1368 // Handle it here. Safeguard against excessive recursions. 1369 if (IoGetRemainingStackSize() < PAGE_SIZE) 1370 { 1371 ERR("Server Callback Exceeded Stack!\n"); 1372 RETURN( FALSE); 1373 } 1374 /* Return after server side call, IntCallWndProcRet will not be called. */ 1375 switch(Window->fnid) 1376 { 1377 case FNID_DESKTOP: 1378 DoCallBack = !DesktopWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result); 1379 break; 1380 case FNID_MESSAGEWND: 1381 DoCallBack = !UserMessageWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result); 1382 break; 1383 case FNID_MENU: 1384 DoCallBack = !PopupMenuWndProc( Window, Msg, wParam, lParam,(LRESULT*)&Result); 1385 break; 1386 } 1387 if (!DoCallBack) 1388 { 1389 if (uResult) *uResult = Result; 1390 RETURN( TRUE); 1391 } 1392 } 1393 /* See if this message type is present in the table */ 1394 MsgMemoryEntry = FindMsgMemory(Msg); 1395 if (NULL == MsgMemoryEntry) 1396 { 1397 lParamBufferSize = -1; 1398 } 1399 else 1400 { 1401 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam); 1402 // If zero, do not allow callback on client side to allocate a buffer!!!!! See CORE-7695. 1403 if (!lParamBufferSize) lParamBufferSize = -1; 1404 } 1405 1406 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, FALSE))) 1407 { 1408 ERR("Failed to pack message parameters\n"); 1409 RETURN( FALSE); 1410 } 1411 1412 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc, 1413 !Window->Unicode, 1414 hWnd, 1415 Msg, 1416 wParam, 1417 lParamPacked, 1418 lParamBufferSize ); 1419 if (uResult) 1420 { 1421 *uResult = Result; 1422 } 1423 1424 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE))) 1425 { 1426 ERR("Failed to unpack message parameters\n"); 1427 RETURN( TRUE); 1428 } 1429 1430 // Only happens when calling the client! 1431 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult); 1432 1433 RETURN( TRUE); 1434 } 1435 1436 if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(ptiSendTo)) 1437 { 1438 // FIXME: Set window hung and add to a list. 1439 /* FIXME: Set a LastError? */ 1440 RETURN( FALSE); 1441 } 1442 1443 if (Window->state & WNDS_DESTROYED) 1444 { 1445 /* FIXME: Last error? */ 1446 ERR("Attempted to send message to window %p that is being destroyed!\n", hWnd); 1447 RETURN( FALSE); 1448 } 1449 1450 do 1451 { 1452 Status = co_MsqSendMessage( ptiSendTo, 1453 hWnd, 1454 Msg, 1455 wParam, 1456 lParam, 1457 uTimeout, 1458 (uFlags & SMTO_BLOCK), 1459 MSQ_NORMAL, 1460 uResult ); 1461 } 1462 while ((STATUS_TIMEOUT == Status) && 1463 (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) && 1464 !MsqIsHung(ptiSendTo)); // FIXME: Set window hung and add to a list. 1465 1466 if (Status == STATUS_TIMEOUT) 1467 { 1468 /* 1469 * MSDN says: 1470 * Microsoft Windows 2000: If GetLastError returns zero, then the function 1471 * timed out. 1472 * XP+ : If the function fails or times out, the return value is zero. 1473 * To get extended error information, call GetLastError. If GetLastError 1474 * returns ERROR_TIMEOUT, then the function timed out. 1475 */ 1476 EngSetLastError(ERROR_TIMEOUT); 1477 RETURN( FALSE); 1478 } 1479 else if (!NT_SUCCESS(Status)) 1480 { 1481 SetLastNtError(Status); 1482 RETURN( FALSE); 1483 } 1484 1485 RETURN( TRUE); 1486 1487 CLEANUP: 1488 if (Window) UserDerefObjectCo(Window); 1489 END_CLEANUP; 1490 } 1491 1492 LRESULT FASTCALL 1493 co_IntSendMessageTimeout( HWND hWnd, 1494 UINT Msg, 1495 WPARAM wParam, 1496 LPARAM lParam, 1497 UINT uFlags, 1498 UINT uTimeout, 1499 ULONG_PTR *uResult ) 1500 { 1501 PWND DesktopWindow; 1502 HWND *Children; 1503 HWND *Child; 1504 1505 if (hWnd != HWND_BROADCAST && hWnd != HWND_TOPMOST) 1506 { 1507 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult); 1508 } 1509 1510 if (!is_message_broadcastable(Msg)) return TRUE; 1511 1512 DesktopWindow = UserGetDesktopWindow(); 1513 if (NULL == DesktopWindow) 1514 { 1515 EngSetLastError(ERROR_INTERNAL_ERROR); 1516 return 0; 1517 } 1518 1519 if (hWnd != HWND_TOPMOST) 1520 { 1521 /* Send message to the desktop window too! */ 1522 co_IntSendMessageTimeoutSingle(DesktopWindow->head.h, Msg, wParam, lParam, uFlags, uTimeout, uResult); 1523 } 1524 1525 Children = IntWinListChildren(DesktopWindow); 1526 if (NULL == Children) 1527 { 1528 return 0; 1529 } 1530 1531 for (Child = Children; NULL != *Child; Child++) 1532 { 1533 PWND pwnd = UserGetWindowObject(*Child); 1534 if (!pwnd) continue; 1535 1536 if ( pwnd->fnid == FNID_MENU || 1537 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 1538 continue; 1539 1540 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult); 1541 } 1542 1543 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST); 1544 1545 return (LRESULT) TRUE; 1546 } 1547 1548 LRESULT FASTCALL 1549 co_IntSendMessageNoWait(HWND hWnd, 1550 UINT Msg, 1551 WPARAM wParam, 1552 LPARAM lParam) 1553 { 1554 ULONG_PTR Result = 0; 1555 return co_IntSendMessageWithCallBack( hWnd, 1556 Msg, 1557 wParam, 1558 lParam, 1559 NULL, 1560 0, 1561 &Result); 1562 } 1563 /* MSDN: 1564 If you send a message in the range below WM_USER to the asynchronous message 1565 functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its 1566 message parameters cannot include pointers. Otherwise, the operation will fail. 1567 The functions will return before the receiving thread has had a chance to 1568 process the message and the sender will free the memory before it is used. 1569 */ 1570 LRESULT FASTCALL 1571 co_IntSendMessageWithCallBack( HWND hWnd, 1572 UINT Msg, 1573 WPARAM wParam, 1574 LPARAM lParam, 1575 SENDASYNCPROC CompletionCallback, 1576 ULONG_PTR CompletionCallbackContext, 1577 ULONG_PTR *uResult) 1578 { 1579 ULONG_PTR Result; 1580 PWND Window = NULL; 1581 PMSGMEMORY MsgMemoryEntry; 1582 INT lParamBufferSize; 1583 LPARAM lParamPacked; 1584 PTHREADINFO Win32Thread, ptiSendTo = NULL; 1585 DECLARE_RETURN(LRESULT); 1586 USER_REFERENCE_ENTRY Ref; 1587 PUSER_SENT_MESSAGE Message; 1588 BOOL DoCallBack = TRUE; 1589 1590 if (!(Window = UserGetWindowObject(hWnd))) 1591 { 1592 TRACE("SendMessageWithCallBack: Invalid handle 0x%p!\n",hWnd); 1593 RETURN(FALSE); 1594 } 1595 1596 UserRefObjectCo(Window, &Ref); 1597 1598 if (Window->state & WNDS_DESTROYED) 1599 { 1600 /* FIXME: last error? */ 1601 ERR("Attempted to send message to window %p that is being destroyed!\n", hWnd); 1602 RETURN(FALSE); 1603 } 1604 1605 Win32Thread = PsGetCurrentThreadWin32Thread(); 1606 1607 if (Win32Thread == NULL || 1608 Win32Thread->TIF_flags & TIF_INCLEANUP) 1609 { 1610 RETURN(FALSE); 1611 } 1612 1613 ptiSendTo = IntSendTo(Window, Win32Thread, Msg); 1614 1615 if (Msg & 0x80000000 && 1616 !ptiSendTo) 1617 { 1618 if (Win32Thread->TIF_flags & TIF_INCLEANUP) RETURN( FALSE); 1619 1620 TRACE("SMWCB: Internal Message!\n"); 1621 Result = (ULONG_PTR)handle_internal_message( Window, Msg, wParam, lParam ); 1622 if (uResult) *uResult = Result; 1623 RETURN( TRUE); 1624 } 1625 1626 /* See if this message type is present in the table */ 1627 MsgMemoryEntry = FindMsgMemory(Msg); 1628 if (NULL == MsgMemoryEntry) 1629 { 1630 lParamBufferSize = -1; 1631 } 1632 else 1633 { 1634 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam); 1635 if (!lParamBufferSize) lParamBufferSize = -1; 1636 } 1637 1638 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, !!ptiSendTo))) 1639 { 1640 ERR("Failed to pack message parameters\n"); 1641 RETURN( FALSE); 1642 } 1643 1644 /* If it can be sent now, then send it. */ 1645 if ( !ptiSendTo ) 1646 { 1647 if (Win32Thread->TIF_flags & TIF_INCLEANUP) 1648 { 1649 UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE); 1650 /* Never send messages to exiting threads */ 1651 RETURN(FALSE); 1652 } 1653 1654 IntCallWndProc( Window, hWnd, Msg, wParam, lParam); 1655 1656 if ( Window->state & WNDS_SERVERSIDEWINDOWPROC ) 1657 { 1658 TRACE("SMWCB: Server Side Window Procedure\n"); 1659 switch(Window->fnid) 1660 { 1661 case FNID_DESKTOP: 1662 DoCallBack = !DesktopWindowProc(Window, Msg, wParam, lParamPacked, (LRESULT*)&Result); 1663 break; 1664 case FNID_MESSAGEWND: 1665 DoCallBack = !UserMessageWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result); 1666 break; 1667 case FNID_MENU: 1668 DoCallBack = !PopupMenuWndProc( Window, Msg, wParam, lParam,(LRESULT*)&Result); 1669 break; 1670 } 1671 } 1672 1673 if (DoCallBack) 1674 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc, 1675 !Window->Unicode, 1676 hWnd, 1677 Msg, 1678 wParam, 1679 lParamPacked, 1680 lParamBufferSize ); 1681 if(uResult) 1682 { 1683 *uResult = Result; 1684 } 1685 1686 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult); 1687 1688 if (CompletionCallback) 1689 { 1690 co_IntCallSentMessageCallback(CompletionCallback, 1691 hWnd, 1692 Msg, 1693 CompletionCallbackContext, 1694 Result); 1695 } 1696 } 1697 1698 if ( !ptiSendTo) 1699 { 1700 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE))) 1701 { 1702 ERR("Failed to unpack message parameters\n"); 1703 } 1704 RETURN(TRUE); 1705 } 1706 1707 if(!(Message = AllocateUserMessage(FALSE))) 1708 { 1709 ERR("MsqSendMessage(): Not enough memory to allocate a message"); 1710 RETURN( FALSE); 1711 } 1712 1713 Message->Msg.hwnd = hWnd; 1714 Message->Msg.message = Msg; 1715 Message->Msg.wParam = wParam; 1716 Message->Msg.lParam = lParamPacked; 1717 Message->pkCompletionEvent = NULL; // No event needed. 1718 Message->lResult = 0; 1719 Message->QS_Flags = 0; 1720 Message->ptiReceiver = ptiSendTo; 1721 Message->ptiSender = NULL; // mjmartin, you are right! This is null. 1722 Message->ptiCallBackSender = Win32Thread; 1723 Message->CompletionCallback = CompletionCallback; 1724 Message->CompletionCallbackContext = CompletionCallbackContext; 1725 Message->HookMessage = MSQ_NORMAL; 1726 Message->HasPackedLParam = (lParamBufferSize > 0); 1727 Message->QS_Flags = QS_SENDMESSAGE; 1728 Message->flags = SMF_RECEIVERFREE; 1729 1730 if (Msg & 0x80000000) // Higher priority event message! 1731 InsertHeadList(&ptiSendTo->SentMessagesListHead, &Message->ListEntry); 1732 else 1733 InsertTailList(&ptiSendTo->SentMessagesListHead, &Message->ListEntry); 1734 MsqWakeQueue(ptiSendTo, QS_SENDMESSAGE, TRUE); 1735 1736 RETURN(TRUE); 1737 1738 CLEANUP: 1739 if (Window) UserDerefObjectCo(Window); 1740 END_CLEANUP; 1741 } 1742 1743 #if 0 1744 /* 1745 This HACK function posts a message if the destination's message queue belongs to 1746 another thread, otherwise it sends the message. It does not support broadcast 1747 messages! 1748 */ 1749 LRESULT FASTCALL 1750 co_IntPostOrSendMessage( HWND hWnd, 1751 UINT Msg, 1752 WPARAM wParam, 1753 LPARAM lParam ) 1754 { 1755 ULONG_PTR Result; 1756 PTHREADINFO pti; 1757 PWND Window; 1758 1759 if ( hWnd == HWND_BROADCAST ) 1760 { 1761 return 0; 1762 } 1763 1764 if(!(Window = UserGetWindowObject(hWnd))) 1765 { 1766 TRACE("PostOrSendMessage: Invalid handle 0x%p!\n",hWnd); 1767 return 0; 1768 } 1769 1770 pti = PsGetCurrentThreadWin32Thread(); 1771 1772 if ( IntSendTo(Window, pti, Msg) && 1773 FindMsgMemory(Msg) == 0 ) 1774 { 1775 Result = UserPostMessage(hWnd, Msg, wParam, lParam); 1776 } 1777 else 1778 { 1779 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) ) 1780 { 1781 Result = 0; 1782 } 1783 } 1784 1785 return (LRESULT)Result; 1786 } 1787 #endif 1788 1789 static LRESULT FASTCALL 1790 co_IntDoSendMessage( HWND hWnd, 1791 UINT Msg, 1792 WPARAM wParam, 1793 LPARAM lParam, 1794 PDOSENDMESSAGE dsm) 1795 { 1796 LRESULT Result = TRUE; 1797 NTSTATUS Status; 1798 PWND Window = NULL; 1799 MSG UserModeMsg, KernelModeMsg; 1800 PMSGMEMORY MsgMemoryEntry; 1801 PTHREADINFO ptiSendTo; 1802 1803 if (hWnd != HWND_BROADCAST && hWnd != HWND_TOPMOST) 1804 { 1805 Window = UserGetWindowObject(hWnd); 1806 if ( !Window ) 1807 { 1808 return 0; 1809 } 1810 } 1811 1812 /* Check for an exiting window. */ 1813 if (Window && Window->state & WNDS_DESTROYED) 1814 { 1815 ERR("co_IntDoSendMessage Window Exiting!\n"); 1816 } 1817 1818 /* See if the current thread can handle this message */ 1819 ptiSendTo = IntSendTo(Window, gptiCurrent, Msg); 1820 1821 // If broadcasting or sending to another thread, save the users data. 1822 if (!Window || ptiSendTo ) 1823 { 1824 UserModeMsg.hwnd = hWnd; 1825 UserModeMsg.message = Msg; 1826 UserModeMsg.wParam = wParam; 1827 UserModeMsg.lParam = lParam; 1828 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message); 1829 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry); 1830 if (!NT_SUCCESS(Status)) 1831 { 1832 EngSetLastError(ERROR_INVALID_PARAMETER); 1833 return (dsm ? 0 : -1); 1834 } 1835 } 1836 else 1837 { 1838 KernelModeMsg.hwnd = hWnd; 1839 KernelModeMsg.message = Msg; 1840 KernelModeMsg.wParam = wParam; 1841 KernelModeMsg.lParam = lParam; 1842 } 1843 1844 if (!dsm) 1845 { 1846 Result = co_IntSendMessage( KernelModeMsg.hwnd, 1847 KernelModeMsg.message, 1848 KernelModeMsg.wParam, 1849 KernelModeMsg.lParam ); 1850 } 1851 else 1852 { 1853 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd, 1854 KernelModeMsg.message, 1855 KernelModeMsg.wParam, 1856 KernelModeMsg.lParam, 1857 dsm->uFlags, 1858 dsm->uTimeout, 1859 &dsm->Result ); 1860 } 1861 1862 if (!Window || ptiSendTo ) 1863 { 1864 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg); 1865 if (!NT_SUCCESS(Status)) 1866 { 1867 EngSetLastError(ERROR_INVALID_PARAMETER); 1868 return(dsm ? 0 : -1); 1869 } 1870 } 1871 1872 return (LRESULT)Result; 1873 } 1874 1875 BOOL FASTCALL 1876 UserSendNotifyMessage( HWND hWnd, 1877 UINT Msg, 1878 WPARAM wParam, 1879 LPARAM lParam ) 1880 { 1881 BOOL Ret = TRUE; 1882 1883 if (is_pointer_message(Msg)) 1884 { 1885 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY ); 1886 return FALSE; 1887 } 1888 1889 // Basicly the same as IntPostOrSendMessage 1890 if (hWnd == HWND_BROADCAST) // Handle Broadcast 1891 { 1892 HWND *List; 1893 PWND DesktopWindow; 1894 ULONG i; 1895 1896 DesktopWindow = UserGetDesktopWindow(); 1897 List = IntWinListChildren(DesktopWindow); 1898 1899 if (List != NULL) 1900 { 1901 UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam); 1902 for (i = 0; List[i]; i++) 1903 { 1904 PWND pwnd = UserGetWindowObject(List[i]); 1905 if (!pwnd) continue; 1906 1907 if ( pwnd->fnid == FNID_MENU || 1908 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 1909 continue; 1910 1911 Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam); 1912 } 1913 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 1914 } 1915 } 1916 else 1917 { 1918 Ret = co_IntSendMessageNoWait( hWnd, Msg, wParam, lParam); 1919 } 1920 return Ret; 1921 } 1922 1923 1924 DWORD APIENTRY 1925 IntGetQueueStatus(DWORD Changes) 1926 { 1927 PTHREADINFO pti; 1928 DWORD Result; 1929 1930 pti = PsGetCurrentThreadWin32Thread(); 1931 // wine: 1932 Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT); 1933 1934 /* High word, types of messages currently in the queue. 1935 Low word, types of messages that have been added to the queue and that 1936 are still in the queue 1937 */ 1938 Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes); 1939 1940 pti->pcti->fsChangeBits &= ~Changes; 1941 1942 return Result; 1943 } 1944 1945 BOOL APIENTRY 1946 IntInitMessagePumpHook(VOID) 1947 { 1948 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1949 1950 if (pti->pcti) 1951 { 1952 pti->pcti->dwcPumpHook++; 1953 return TRUE; 1954 } 1955 return FALSE; 1956 } 1957 1958 BOOL APIENTRY 1959 IntUninitMessagePumpHook(VOID) 1960 { 1961 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1962 1963 if (pti->pcti) 1964 { 1965 if (pti->pcti->dwcPumpHook <= 0) 1966 { 1967 return FALSE; 1968 } 1969 pti->pcti->dwcPumpHook--; 1970 return TRUE; 1971 } 1972 return FALSE; 1973 } 1974 1975 BOOL FASTCALL 1976 IntCallMsgFilter( LPMSG lpmsg, INT code) 1977 { 1978 BOOL Ret = FALSE; 1979 1980 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)lpmsg)) 1981 { 1982 Ret = TRUE; 1983 } 1984 else 1985 { 1986 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)lpmsg); 1987 } 1988 return Ret; 1989 } 1990 1991 /** Functions ******************************************************************/ 1992 1993 BOOL 1994 APIENTRY 1995 NtUserDragDetect( 1996 HWND hWnd, 1997 POINT pt) // Just like the User call. 1998 { 1999 MSG msg; 2000 RECT rect; 2001 ULONG wDragWidth, wDragHeight; 2002 DECLARE_RETURN(BOOL); 2003 2004 TRACE("Enter NtUserDragDetect(%p)\n", hWnd); 2005 UserEnterExclusive(); 2006 2007 wDragWidth = UserGetSystemMetrics(SM_CXDRAG); 2008 wDragHeight= UserGetSystemMetrics(SM_CYDRAG); 2009 2010 rect.left = pt.x - wDragWidth; 2011 rect.right = pt.x + wDragWidth; 2012 2013 rect.top = pt.y - wDragHeight; 2014 rect.bottom = pt.y + wDragHeight; 2015 2016 co_UserSetCapture(hWnd); 2017 2018 for (;;) 2019 { 2020 while (co_IntGetPeekMessage( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, FALSE ) || 2021 co_IntGetPeekMessage( &msg, 0, WM_QUEUESYNC, WM_QUEUESYNC, PM_REMOVE, FALSE ) || 2022 co_IntGetPeekMessage( &msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE, FALSE ) ) 2023 { 2024 if ( msg.message == WM_LBUTTONUP ) 2025 { 2026 co_UserSetCapture(NULL); 2027 RETURN( FALSE); 2028 } 2029 if ( msg.message == WM_MOUSEMOVE ) 2030 { 2031 POINT tmp; 2032 tmp.x = (short)LOWORD(msg.lParam); 2033 tmp.y = (short)HIWORD(msg.lParam); 2034 if( !RECTL_bPointInRect( &rect, tmp.x, tmp.y ) ) 2035 { 2036 co_UserSetCapture(NULL); 2037 RETURN( TRUE); 2038 } 2039 } 2040 if ( msg.message == WM_KEYDOWN ) 2041 { 2042 if ( msg.wParam == VK_ESCAPE ) 2043 { 2044 co_UserSetCapture(NULL); 2045 RETURN( TRUE); 2046 } 2047 } 2048 if ( msg.message == WM_QUEUESYNC ) 2049 { 2050 co_HOOK_CallHooks( WH_CBT, HCBT_QS, 0, 0 ); 2051 } 2052 } 2053 co_IntWaitMessage(NULL, 0, 0); 2054 } 2055 RETURN( FALSE); 2056 2057 CLEANUP: 2058 TRACE("Leave NtUserDragDetect, ret=%i\n",_ret_); 2059 UserLeave(); 2060 END_CLEANUP; 2061 } 2062 2063 BOOL APIENTRY 2064 NtUserPostMessage(HWND hWnd, 2065 UINT Msg, 2066 WPARAM wParam, 2067 LPARAM lParam) 2068 { 2069 BOOL ret; 2070 2071 UserEnterExclusive(); 2072 2073 ret = UserPostMessage(hWnd, Msg, wParam, lParam); 2074 2075 UserLeave(); 2076 2077 return ret; 2078 } 2079 2080 BOOL APIENTRY 2081 NtUserPostThreadMessage(DWORD idThread, 2082 UINT Msg, 2083 WPARAM wParam, 2084 LPARAM lParam) 2085 { 2086 BOOL ret = FALSE; 2087 PETHREAD peThread; 2088 PTHREADINFO pThread; 2089 NTSTATUS Status; 2090 2091 UserEnterExclusive(); 2092 2093 Status = PsLookupThreadByThreadId(UlongToHandle(idThread), &peThread); 2094 2095 if ( Status == STATUS_SUCCESS ) 2096 { 2097 pThread = (PTHREADINFO)peThread->Tcb.Win32Thread; 2098 if( !pThread || 2099 !pThread->MessageQueue || 2100 (pThread->TIF_flags & TIF_INCLEANUP)) 2101 { 2102 ObDereferenceObject( peThread ); 2103 goto exit; 2104 } 2105 ret = UserPostThreadMessage( pThread, Msg, wParam, lParam); 2106 ObDereferenceObject( peThread ); 2107 } 2108 else 2109 { 2110 SetLastNtError( Status ); 2111 } 2112 exit: 2113 UserLeave(); 2114 return ret; 2115 } 2116 2117 BOOL APIENTRY 2118 NtUserWaitMessage(VOID) 2119 { 2120 BOOL ret; 2121 2122 UserEnterExclusive(); 2123 TRACE("NtUserWaitMessage Enter\n"); 2124 ret = co_IntWaitMessage(NULL, 0, 0); 2125 TRACE("NtUserWaitMessage Leave\n"); 2126 UserLeave(); 2127 2128 return ret; 2129 } 2130 2131 BOOL APIENTRY 2132 NtUserGetMessage(PMSG pMsg, 2133 HWND hWnd, 2134 UINT MsgFilterMin, 2135 UINT MsgFilterMax ) 2136 { 2137 MSG Msg; 2138 BOOL Ret; 2139 2140 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM ) 2141 { 2142 EngSetLastError(ERROR_INVALID_PARAMETER); 2143 return FALSE; 2144 } 2145 2146 UserEnterExclusive(); 2147 2148 RtlZeroMemory(&Msg, sizeof(MSG)); 2149 2150 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE); 2151 2152 UserLeave(); 2153 2154 if (Ret) 2155 { 2156 _SEH2_TRY 2157 { 2158 ProbeForWrite(pMsg, sizeof(MSG), 1); 2159 RtlCopyMemory(pMsg, &Msg, sizeof(MSG)); 2160 } 2161 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2162 { 2163 SetLastNtError(_SEH2_GetExceptionCode()); 2164 Ret = FALSE; 2165 } 2166 _SEH2_END; 2167 } 2168 2169 if ((INT)Ret != -1) 2170 Ret = Ret ? (WM_QUIT != pMsg->message) : FALSE; 2171 2172 return Ret; 2173 } 2174 2175 BOOL APIENTRY 2176 NtUserPeekMessage( PMSG pMsg, 2177 HWND hWnd, 2178 UINT MsgFilterMin, 2179 UINT MsgFilterMax, 2180 UINT RemoveMsg) 2181 { 2182 MSG Msg; 2183 BOOL Ret; 2184 2185 if ( RemoveMsg & PM_BADMSGFLAGS ) 2186 { 2187 EngSetLastError(ERROR_INVALID_FLAGS); 2188 return FALSE; 2189 } 2190 2191 UserEnterExclusive(); 2192 2193 RtlZeroMemory(&Msg, sizeof(MSG)); 2194 2195 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE); 2196 2197 UserLeave(); 2198 2199 if (Ret) 2200 { 2201 _SEH2_TRY 2202 { 2203 ProbeForWrite(pMsg, sizeof(MSG), 1); 2204 RtlCopyMemory(pMsg, &Msg, sizeof(MSG)); 2205 } 2206 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2207 { 2208 SetLastNtError(_SEH2_GetExceptionCode()); 2209 Ret = FALSE; 2210 } 2211 _SEH2_END; 2212 } 2213 2214 return Ret; 2215 } 2216 2217 BOOL APIENTRY 2218 NtUserCallMsgFilter( LPMSG lpmsg, INT code) 2219 { 2220 BOOL Ret = FALSE; 2221 MSG Msg; 2222 2223 _SEH2_TRY 2224 { 2225 ProbeForRead(lpmsg, sizeof(MSG), 1); 2226 RtlCopyMemory( &Msg, lpmsg, sizeof(MSG)); 2227 } 2228 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2229 { 2230 _SEH2_YIELD(return FALSE); 2231 } 2232 _SEH2_END; 2233 2234 UserEnterExclusive(); 2235 2236 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg)) 2237 { 2238 Ret = TRUE; 2239 } 2240 else 2241 { 2242 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg); 2243 } 2244 2245 UserLeave(); 2246 2247 _SEH2_TRY 2248 { 2249 ProbeForWrite(lpmsg, sizeof(MSG), 1); 2250 RtlCopyMemory(lpmsg, &Msg, sizeof(MSG)); 2251 } 2252 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2253 { 2254 Ret = FALSE; 2255 } 2256 _SEH2_END; 2257 2258 return Ret; 2259 } 2260 2261 LRESULT APIENTRY 2262 NtUserDispatchMessage(PMSG UnsafeMsgInfo) 2263 { 2264 LRESULT Res = 0; 2265 MSG SafeMsg; 2266 2267 _SEH2_TRY 2268 { 2269 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1); 2270 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG)); 2271 } 2272 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2273 { 2274 SetLastNtError(_SEH2_GetExceptionCode()); 2275 _SEH2_YIELD(return FALSE); 2276 } 2277 _SEH2_END; 2278 2279 UserEnterExclusive(); 2280 2281 Res = IntDispatchMessage(&SafeMsg); 2282 2283 UserLeave(); 2284 return Res; 2285 } 2286 2287 BOOL APIENTRY 2288 NtUserTranslateMessage(LPMSG lpMsg, UINT flags) 2289 { 2290 MSG SafeMsg; 2291 BOOL Ret; 2292 PWND pWnd; 2293 2294 _SEH2_TRY 2295 { 2296 ProbeForRead(lpMsg, sizeof(MSG), 1); 2297 RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG)); 2298 } 2299 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2300 { 2301 SetLastNtError(_SEH2_GetExceptionCode()); 2302 _SEH2_YIELD(return FALSE); 2303 } 2304 _SEH2_END; 2305 2306 UserEnterExclusive(); 2307 pWnd = UserGetWindowObject(SafeMsg.hwnd); 2308 if (pWnd) // Must have a window! 2309 { 2310 Ret = IntTranslateKbdMessage(&SafeMsg, flags); 2311 } 2312 else 2313 { 2314 TRACE("No Window for Translate. hwnd 0x%p Msg %u\n", SafeMsg.hwnd, SafeMsg.message); 2315 Ret = FALSE; 2316 } 2317 UserLeave(); 2318 2319 return Ret; 2320 } 2321 2322 LRESULT APIENTRY ScrollBarWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam); 2323 2324 BOOL APIENTRY 2325 NtUserMessageCall( HWND hWnd, 2326 UINT Msg, 2327 WPARAM wParam, 2328 LPARAM lParam, 2329 ULONG_PTR ResultInfo, 2330 DWORD dwType, // fnID? 2331 BOOL Ansi) 2332 { 2333 LRESULT lResult = 0; 2334 BOOL Ret = FALSE; 2335 PWND Window = NULL; 2336 USER_REFERENCE_ENTRY Ref; 2337 2338 UserEnterExclusive(); 2339 2340 switch(dwType) 2341 { 2342 case FNID_SCROLLBAR: 2343 { 2344 lResult = ScrollBarWndProc(hWnd, Msg, wParam, lParam); 2345 break; 2346 } 2347 case FNID_DESKTOP: 2348 { 2349 Window = UserGetWindowObject(hWnd); 2350 if (Window) 2351 { 2352 //ERR("FNID_DESKTOP IN\n"); 2353 Ret = DesktopWindowProc(Window, Msg, wParam, lParam, &lResult); 2354 //ERR("FNID_DESKTOP OUT\n"); 2355 } 2356 break; 2357 } 2358 case FNID_MENU: 2359 { 2360 Window = UserGetWindowObject(hWnd); 2361 if (Window) 2362 { 2363 Ret = PopupMenuWndProc( Window, Msg, wParam, lParam, &lResult); 2364 } 2365 break; 2366 } 2367 case FNID_MESSAGEWND: 2368 { 2369 Window = UserGetWindowObject(hWnd); 2370 if (Window) 2371 { 2372 Ret = !UserMessageWindowProc(Window, Msg, wParam, lParam, &lResult); 2373 } 2374 break; 2375 } 2376 case FNID_DEFWINDOWPROC: 2377 /* Validate input */ 2378 if (hWnd) 2379 { 2380 Window = UserGetWindowObject(hWnd); 2381 if (!Window) 2382 { 2383 UserLeave(); 2384 return FALSE; 2385 } 2386 UserRefObjectCo(Window, &Ref); 2387 } 2388 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi); 2389 Ret = TRUE; 2390 if (hWnd) 2391 UserDerefObjectCo(Window); 2392 break; 2393 case FNID_SENDNOTIFYMESSAGE: 2394 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam); 2395 break; 2396 case FNID_BROADCASTSYSTEMMESSAGE: 2397 { 2398 BROADCASTPARM parm, *retparam; 2399 DWORD_PTR RetVal = 0; 2400 2401 if (ResultInfo) 2402 { 2403 _SEH2_TRY 2404 { 2405 ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1); 2406 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM)); 2407 } 2408 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2409 { 2410 _SEH2_YIELD(break); 2411 } 2412 _SEH2_END; 2413 } 2414 else 2415 break; 2416 2417 if ( parm.recipients & BSM_ALLDESKTOPS || 2418 parm.recipients == BSM_ALLCOMPONENTS ) 2419 { 2420 PLIST_ENTRY DesktopEntry; 2421 PDESKTOP rpdesk; 2422 HWND *List, hwndDenied = NULL; 2423 HDESK hDesk = NULL; 2424 PWND pwnd, pwndDesk; 2425 ULONG i; 2426 UINT fuFlags; 2427 2428 for (DesktopEntry = InputWindowStation->DesktopListHead.Flink; 2429 DesktopEntry != &InputWindowStation->DesktopListHead; 2430 DesktopEntry = DesktopEntry->Flink) 2431 { 2432 rpdesk = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry); 2433 pwndDesk = rpdesk->pDeskInfo->spwnd; 2434 List = IntWinListChildren(pwndDesk); 2435 2436 if (parm.flags & BSF_QUERY) 2437 { 2438 if (List != NULL) 2439 { 2440 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG) 2441 { 2442 fuFlags = SMTO_ABORTIFHUNG; 2443 } 2444 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG) 2445 { 2446 fuFlags = SMTO_NOTIMEOUTIFNOTHUNG; 2447 } 2448 else 2449 { 2450 fuFlags = SMTO_NORMAL; 2451 } 2452 co_IntSendMessageTimeout( UserHMGetHandle(pwndDesk), 2453 Msg, 2454 wParam, 2455 lParam, 2456 fuFlags, 2457 2000, 2458 &RetVal); 2459 Ret = TRUE; 2460 for (i = 0; List[i]; i++) 2461 { 2462 pwnd = UserGetWindowObject(List[i]); 2463 if (!pwnd) continue; 2464 2465 if ( pwnd->fnid == FNID_MENU || 2466 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 2467 continue; 2468 2469 if ( parm.flags & BSF_IGNORECURRENTTASK ) 2470 { 2471 if ( pwnd->head.pti == gptiCurrent ) 2472 continue; 2473 } 2474 co_IntSendMessageTimeout( List[i], 2475 Msg, 2476 wParam, 2477 lParam, 2478 fuFlags, 2479 2000, 2480 &RetVal); 2481 2482 if (!RetVal && EngGetLastError() == ERROR_TIMEOUT) 2483 { 2484 if (!(parm.flags & BSF_FORCEIFHUNG)) 2485 Ret = FALSE; 2486 } 2487 if (RetVal == BROADCAST_QUERY_DENY) 2488 { 2489 hwndDenied = List[i]; 2490 hDesk = UserHMGetHandle(pwndDesk); 2491 Ret = FALSE; 2492 } 2493 } 2494 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2495 _SEH2_TRY 2496 { 2497 retparam = (PBROADCASTPARM) ResultInfo; 2498 retparam->hDesk = hDesk; 2499 retparam->hWnd = hwndDenied; 2500 } 2501 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2502 { 2503 _SEH2_YIELD(break); 2504 } 2505 _SEH2_END; 2506 if (!Ret) break; // Have a hit! Let everyone know! 2507 } 2508 } 2509 else if (parm.flags & BSF_POSTMESSAGE) 2510 { 2511 if (List != NULL) 2512 { 2513 UserPostMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam); 2514 2515 for (i = 0; List[i]; i++) 2516 { 2517 pwnd = UserGetWindowObject(List[i]); 2518 if (!pwnd) continue; 2519 2520 if ( pwnd->fnid == FNID_MENU || 2521 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 2522 continue; 2523 2524 if ( parm.flags & BSF_IGNORECURRENTTASK ) 2525 { 2526 if ( pwnd->head.pti == gptiCurrent ) 2527 continue; 2528 } 2529 UserPostMessage(List[i], Msg, wParam, lParam); 2530 } 2531 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2532 } 2533 Ret = TRUE; 2534 } 2535 else 2536 { 2537 if (List != NULL) 2538 { 2539 UserSendNotifyMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam); 2540 2541 for (i = 0; List[i]; i++) 2542 { 2543 pwnd = UserGetWindowObject(List[i]); 2544 if (!pwnd) continue; 2545 2546 if ( pwnd->fnid == FNID_MENU || 2547 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 2548 continue; 2549 2550 if ( parm.flags & BSF_IGNORECURRENTTASK ) 2551 { 2552 if ( pwnd->head.pti == gptiCurrent ) 2553 continue; 2554 } 2555 UserSendNotifyMessage(List[i], Msg, wParam, lParam); 2556 } 2557 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2558 } 2559 Ret = TRUE; 2560 } 2561 } 2562 } 2563 else if (parm.recipients & BSM_APPLICATIONS) 2564 { 2565 HWND *List, hwndDenied = NULL; 2566 HDESK hDesk = NULL; 2567 PWND pwnd, pwndDesk; 2568 ULONG i; 2569 UINT fuFlags; 2570 2571 pwndDesk = UserGetDesktopWindow(); 2572 List = IntWinListChildren(pwndDesk); 2573 2574 if (parm.flags & BSF_QUERY) 2575 { 2576 if (List != NULL) 2577 { 2578 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG) 2579 { 2580 fuFlags = SMTO_ABORTIFHUNG; 2581 } 2582 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG) 2583 { 2584 fuFlags = SMTO_NOTIMEOUTIFNOTHUNG; 2585 } 2586 else 2587 { 2588 fuFlags = SMTO_NORMAL; 2589 } 2590 co_IntSendMessageTimeout( UserHMGetHandle(pwndDesk), 2591 Msg, 2592 wParam, 2593 lParam, 2594 fuFlags, 2595 2000, 2596 &RetVal); 2597 Ret = TRUE; 2598 for (i = 0; List[i]; i++) 2599 { 2600 pwnd = UserGetWindowObject(List[i]); 2601 if (!pwnd) continue; 2602 2603 if ( pwnd->fnid == FNID_MENU || 2604 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 2605 continue; 2606 2607 if ( parm.flags & BSF_IGNORECURRENTTASK ) 2608 { 2609 if ( pwnd->head.pti == gptiCurrent ) 2610 continue; 2611 } 2612 co_IntSendMessageTimeout( List[i], 2613 Msg, 2614 wParam, 2615 lParam, 2616 fuFlags, 2617 2000, 2618 &RetVal); 2619 2620 if (!RetVal && EngGetLastError() == ERROR_TIMEOUT) 2621 { 2622 if (!(parm.flags & BSF_FORCEIFHUNG)) 2623 Ret = FALSE; 2624 } 2625 if (RetVal == BROADCAST_QUERY_DENY) 2626 { 2627 hwndDenied = List[i]; 2628 hDesk = UserHMGetHandle(pwndDesk); 2629 Ret = FALSE; 2630 } 2631 } 2632 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2633 _SEH2_TRY 2634 { 2635 retparam = (PBROADCASTPARM) ResultInfo; 2636 retparam->hDesk = hDesk; 2637 retparam->hWnd = hwndDenied; 2638 } 2639 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2640 { 2641 _SEH2_YIELD(break); 2642 } 2643 _SEH2_END; 2644 } 2645 } 2646 else if (parm.flags & BSF_POSTMESSAGE) 2647 { 2648 if (List != NULL) 2649 { 2650 UserPostMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam); 2651 2652 for (i = 0; List[i]; i++) 2653 { 2654 pwnd = UserGetWindowObject(List[i]); 2655 if (!pwnd) continue; 2656 2657 if ( pwnd->fnid == FNID_MENU || 2658 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 2659 continue; 2660 2661 if ( parm.flags & BSF_IGNORECURRENTTASK ) 2662 { 2663 if ( pwnd->head.pti == gptiCurrent ) 2664 continue; 2665 } 2666 UserPostMessage(List[i], Msg, wParam, lParam); 2667 } 2668 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2669 } 2670 Ret = TRUE; 2671 } 2672 else 2673 { 2674 if (List != NULL) 2675 { 2676 UserSendNotifyMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam); 2677 2678 for (i = 0; List[i]; i++) 2679 { 2680 pwnd = UserGetWindowObject(List[i]); 2681 if (!pwnd) continue; 2682 2683 if ( pwnd->fnid == FNID_MENU || 2684 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 2685 continue; 2686 2687 if ( parm.flags & BSF_IGNORECURRENTTASK ) 2688 { 2689 if ( pwnd->head.pti == gptiCurrent ) 2690 continue; 2691 } 2692 UserSendNotifyMessage(List[i], Msg, wParam, lParam); 2693 } 2694 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2695 } 2696 Ret = TRUE; 2697 } 2698 } 2699 } 2700 break; 2701 case FNID_SENDMESSAGECALLBACK: 2702 { 2703 CALL_BACK_INFO CallBackInfo; 2704 ULONG_PTR uResult; 2705 2706 _SEH2_TRY 2707 { 2708 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1); 2709 RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO)); 2710 } 2711 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2712 { 2713 _SEH2_YIELD(break); 2714 } 2715 _SEH2_END; 2716 2717 if (is_pointer_message(Msg)) 2718 { 2719 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY ); 2720 break; 2721 } 2722 2723 if (!(Ret = co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam, 2724 CallBackInfo.CallBack, CallBackInfo.Context, &uResult))) 2725 { 2726 ERR("Callback failure!\n"); 2727 } 2728 } 2729 break; 2730 case FNID_SENDMESSAGE: 2731 { 2732 lResult = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0); 2733 Ret = TRUE; 2734 2735 if (ResultInfo) 2736 { 2737 _SEH2_TRY 2738 { 2739 ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1); 2740 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(ULONG_PTR)); 2741 } 2742 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2743 { 2744 Ret = FALSE; 2745 _SEH2_YIELD(break); 2746 } 2747 _SEH2_END; 2748 } 2749 break; 2750 } 2751 case FNID_SENDMESSAGEFF: 2752 case FNID_SENDMESSAGEWTOOPTION: 2753 { 2754 DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo; 2755 if (ResultInfo) 2756 { 2757 _SEH2_TRY 2758 { 2759 ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1); 2760 RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE)); 2761 } 2762 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2763 { 2764 _SEH2_YIELD(break); 2765 } 2766 _SEH2_END; 2767 } 2768 2769 Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, pdsm ? &dsm : NULL ); 2770 2771 if (pdsm) 2772 { 2773 _SEH2_TRY 2774 { 2775 ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1); 2776 RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE)); 2777 } 2778 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2779 { 2780 Ret = FALSE; 2781 _SEH2_YIELD(break); 2782 } 2783 _SEH2_END; 2784 } 2785 break; 2786 } 2787 // CallNextHook bypass. 2788 case FNID_CALLWNDPROC: 2789 case FNID_CALLWNDPROCRET: 2790 { 2791 PTHREADINFO pti; 2792 PCLIENTINFO ClientInfo; 2793 PHOOK NextObj, Hook; 2794 2795 pti = GetW32ThreadInfo(); 2796 2797 Hook = pti->sphkCurrent; 2798 2799 if (!Hook) break; 2800 2801 NextObj = Hook->phkNext; 2802 ClientInfo = pti->pClientInfo; 2803 _SEH2_TRY 2804 { 2805 ClientInfo->phkCurrent = NextObj; 2806 } 2807 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2808 { 2809 ClientInfo = NULL; 2810 } 2811 _SEH2_END; 2812 2813 if (!ClientInfo || !NextObj) break; 2814 2815 NextObj->phkNext = IntGetNextHook(NextObj); 2816 2817 if ( Hook->HookId == WH_CALLWNDPROC) 2818 { 2819 CWPSTRUCT CWP; 2820 CWP.hwnd = hWnd; 2821 CWP.message = Msg; 2822 CWP.wParam = wParam; 2823 CWP.lParam = lParam; 2824 TRACE("WH_CALLWNDPROC: Hook %p NextHook %p\n", Hook, NextObj); 2825 2826 lResult = co_IntCallHookProc( Hook->HookId, 2827 HC_ACTION, 2828 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0), 2829 (LPARAM)&CWP, 2830 Hook->Proc, 2831 Hook->ihmod, 2832 Hook->offPfn, 2833 Hook->Ansi, 2834 &Hook->ModuleName); 2835 } 2836 else 2837 { 2838 CWPRETSTRUCT CWPR; 2839 CWPR.hwnd = hWnd; 2840 CWPR.message = Msg; 2841 CWPR.wParam = wParam; 2842 CWPR.lParam = lParam; 2843 CWPR.lResult = ClientInfo->dwHookData; 2844 2845 lResult = co_IntCallHookProc( Hook->HookId, 2846 HC_ACTION, 2847 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0), 2848 (LPARAM)&CWPR, 2849 Hook->Proc, 2850 Hook->ihmod, 2851 Hook->offPfn, 2852 Hook->Ansi, 2853 &Hook->ModuleName); 2854 } 2855 } 2856 break; 2857 } 2858 2859 switch(dwType) 2860 { 2861 case FNID_DEFWINDOWPROC: 2862 case FNID_CALLWNDPROC: 2863 case FNID_CALLWNDPROCRET: 2864 case FNID_SCROLLBAR: 2865 case FNID_DESKTOP: 2866 case FNID_MENU: 2867 if (ResultInfo) 2868 { 2869 _SEH2_TRY 2870 { 2871 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1); 2872 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT)); 2873 } 2874 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2875 { 2876 Ret = FALSE; 2877 } 2878 _SEH2_END; 2879 } 2880 break; 2881 default: 2882 break; 2883 } 2884 2885 UserLeave(); 2886 2887 return Ret; 2888 } 2889 2890 #define INFINITE 0xFFFFFFFF 2891 #define WAIT_FAILED ((DWORD)0xFFFFFFFF) 2892 2893 DWORD 2894 APIENTRY 2895 NtUserWaitForInputIdle( IN HANDLE hProcess, 2896 IN DWORD dwMilliseconds, 2897 IN BOOL Unknown2) 2898 { 2899 PEPROCESS Process; 2900 PPROCESSINFO W32Process; 2901 PTHREADINFO pti; 2902 NTSTATUS Status; 2903 HANDLE Handles[3]; 2904 LARGE_INTEGER Timeout; 2905 KAPC_STATE ApcState; 2906 2907 UserEnterExclusive(); 2908 2909 Status = ObReferenceObjectByHandle(hProcess, 2910 PROCESS_QUERY_INFORMATION, 2911 *PsProcessType, 2912 UserMode, 2913 (PVOID*)&Process, 2914 NULL); 2915 2916 if (!NT_SUCCESS(Status)) 2917 { 2918 UserLeave(); 2919 SetLastNtError(Status); 2920 return WAIT_FAILED; 2921 } 2922 2923 pti = PsGetCurrentThreadWin32Thread(); 2924 2925 W32Process = (PPROCESSINFO)Process->Win32Process; 2926 2927 if ( PsGetProcessExitProcessCalled(Process) || 2928 !W32Process || 2929 pti->ppi == W32Process) 2930 { 2931 ObDereferenceObject(Process); 2932 UserLeave(); 2933 EngSetLastError(ERROR_INVALID_PARAMETER); 2934 return WAIT_FAILED; 2935 } 2936 2937 Handles[0] = Process; 2938 Handles[1] = W32Process->InputIdleEvent; 2939 Handles[2] = pti->pEventQueueServer; // IntMsqSetWakeMask returns hEventQueueClient 2940 2941 if (!Handles[1]) 2942 { 2943 ObDereferenceObject(Process); 2944 UserLeave(); 2945 return STATUS_SUCCESS; /* no event to wait on */ 2946 } 2947 2948 if (dwMilliseconds != INFINITE) 2949 Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000; 2950 2951 KeStackAttachProcess(&Process->Pcb, &ApcState); 2952 2953 W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE; 2954 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling) 2955 { 2956 pti->TIF_flags |= TIF_WAITFORINPUTIDLE; 2957 pti->pClientInfo->dwTIFlags = pti->TIF_flags; 2958 } 2959 2960 KeUnstackDetachProcess(&ApcState); 2961 2962 TRACE("WFII: ppi %p\n", W32Process); 2963 TRACE("WFII: waiting for %p\n", Handles[1] ); 2964 2965 /* 2966 * We must add a refcount to our current PROCESSINFO, 2967 * because anything could happen (including process death) we're leaving win32k 2968 */ 2969 IntReferenceProcessInfo(W32Process); 2970 2971 do 2972 { 2973 UserLeave(); 2974 Status = KeWaitForMultipleObjects( 3, 2975 Handles, 2976 WaitAny, 2977 UserRequest, 2978 UserMode, 2979 FALSE, 2980 dwMilliseconds == INFINITE ? NULL : &Timeout, 2981 NULL); 2982 UserEnterExclusive(); 2983 2984 if (!NT_SUCCESS(Status)) 2985 { 2986 SetLastNtError(Status); 2987 Status = WAIT_FAILED; 2988 goto WaitExit; 2989 } 2990 2991 switch (Status) 2992 { 2993 case STATUS_WAIT_0: 2994 goto WaitExit; 2995 2996 case STATUS_WAIT_2: 2997 { 2998 MSG Msg; 2999 co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE); 3000 ERR("WFII: WAIT 2\n"); 3001 } 3002 break; 3003 3004 case STATUS_TIMEOUT: 3005 ERR("WFII: timeout\n"); 3006 case WAIT_FAILED: 3007 goto WaitExit; 3008 3009 default: 3010 ERR("WFII: finished\n"); 3011 Status = STATUS_SUCCESS; 3012 goto WaitExit; 3013 } 3014 } 3015 while (TRUE); 3016 3017 WaitExit: 3018 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling) 3019 { 3020 pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE; 3021 pti->pClientInfo->dwTIFlags = pti->TIF_flags; 3022 } 3023 W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE; 3024 IntDereferenceProcessInfo(W32Process); 3025 ObDereferenceObject(Process); 3026 UserLeave(); 3027 return Status; 3028 } 3029 3030 /* EOF */ 3031