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