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, pWnd->head.h); 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(DesktopWindow->head.h, 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 = NULL; 1470 PMSGMEMORY MsgMemoryEntry; 1471 INT lParamBufferSize; 1472 LPARAM lParamPacked; 1473 PTHREADINFO Win32Thread, ptiSendTo = NULL; 1474 ULONG_PTR Result = 0; 1475 DECLARE_RETURN(LRESULT); 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 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 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 RETURN( TRUE); 1514 } 1515 1516 // Only happens when calling the client! 1517 IntCallWndProc( Window, hWnd, Msg, wParam, lParam); 1518 1519 if ( Window->state & WNDS_SERVERSIDEWINDOWPROC ) 1520 { 1521 TRACE("SMT: Server Side Window Procedure\n"); 1522 // Handle it here. Safeguard against excessive recursions. 1523 if (IoGetRemainingStackSize() < PAGE_SIZE) 1524 { 1525 ERR("Server Callback Exceeded Stack!\n"); 1526 RETURN( FALSE); 1527 } 1528 /* Return after server side call, IntCallWndProcRet will not be called. */ 1529 switch(Window->fnid) 1530 { 1531 case FNID_DESKTOP: 1532 DoCallBack = !DesktopWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result); 1533 break; 1534 case FNID_MESSAGEWND: 1535 DoCallBack = !UserMessageWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result); 1536 break; 1537 case FNID_MENU: 1538 DoCallBack = !PopupMenuWndProc( Window, Msg, wParam, lParam,(LRESULT*)&Result); 1539 break; 1540 } 1541 if (!DoCallBack) 1542 { 1543 if (uResult) *uResult = Result; 1544 RETURN( TRUE); 1545 } 1546 } 1547 /* See if this message type is present in the table */ 1548 MsgMemoryEntry = FindMsgMemory(Msg); 1549 if (NULL == MsgMemoryEntry) 1550 { 1551 lParamBufferSize = -1; 1552 } 1553 else 1554 { 1555 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam); 1556 // If zero, do not allow callback on client side to allocate a buffer!!!!! See CORE-7695. 1557 if (!lParamBufferSize) lParamBufferSize = -1; 1558 } 1559 1560 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, FALSE))) 1561 { 1562 ERR("Failed to pack message parameters\n"); 1563 RETURN( FALSE); 1564 } 1565 1566 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc, 1567 !Window->Unicode, 1568 hWnd, 1569 Msg, 1570 wParam, 1571 lParamPacked, 1572 lParamBufferSize ); 1573 if (uResult) 1574 { 1575 *uResult = Result; 1576 } 1577 1578 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE))) 1579 { 1580 ERR("Failed to unpack message parameters\n"); 1581 RETURN( TRUE); 1582 } 1583 1584 // Only happens when calling the client! 1585 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult); 1586 1587 RETURN( TRUE); 1588 } 1589 1590 if (Window->state & WNDS_DESTROYED) 1591 { 1592 /* FIXME: Last error? */ 1593 ERR("Attempted to send message to window %p that is being destroyed!\n", hWnd); 1594 RETURN( FALSE); 1595 } 1596 1597 if ((uFlags & SMTO_ABORTIFHUNG) && MsqIsHung(ptiSendTo, 4 * MSQ_HUNG)) 1598 { 1599 // FIXME: Set window hung and add to a list. 1600 /* FIXME: Set a LastError? */ 1601 ERR("Window %p (%p) (pti %p) is hung!\n", hWnd, Window, ptiSendTo); 1602 RETURN( FALSE); 1603 } 1604 1605 do 1606 { 1607 Status = co_MsqSendMessage( ptiSendTo, 1608 hWnd, 1609 Msg, 1610 wParam, 1611 lParam, 1612 uTimeout, 1613 (uFlags & SMTO_BLOCK), 1614 MSQ_NORMAL, 1615 uResult ); 1616 } 1617 while ((Status == STATUS_TIMEOUT) && 1618 (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) && 1619 !MsqIsHung(ptiSendTo, MSQ_HUNG)); // FIXME: Set window hung and add to a list. 1620 1621 if (Status == STATUS_TIMEOUT) 1622 { 1623 if (0 && MsqIsHung(ptiSendTo, MSQ_HUNG)) 1624 { 1625 TRACE("Let's go Ghost!\n"); 1626 IntMakeHungWindowGhosted(hWnd); 1627 } 1628 /* 1629 * MSDN says: 1630 * Microsoft Windows 2000: If GetLastError returns zero, then the function 1631 * timed out. 1632 * XP+ : If the function fails or times out, the return value is zero. 1633 * To get extended error information, call GetLastError. If GetLastError 1634 * returns ERROR_TIMEOUT, then the function timed out. 1635 */ 1636 EngSetLastError(ERROR_TIMEOUT); 1637 RETURN( FALSE); 1638 } 1639 else if (!NT_SUCCESS(Status)) 1640 { 1641 SetLastNtError(Status); 1642 RETURN( FALSE); 1643 } 1644 1645 RETURN( TRUE); 1646 1647 CLEANUP: 1648 if (Window) UserDerefObjectCo(Window); 1649 END_CLEANUP; 1650 } 1651 1652 LRESULT FASTCALL 1653 co_IntSendMessageTimeout( HWND hWnd, 1654 UINT Msg, 1655 WPARAM wParam, 1656 LPARAM lParam, 1657 UINT uFlags, 1658 UINT uTimeout, 1659 ULONG_PTR *uResult ) 1660 { 1661 PWND DesktopWindow; 1662 HWND *Children; 1663 HWND *Child; 1664 1665 if (hWnd != HWND_BROADCAST && hWnd != HWND_TOPMOST) 1666 { 1667 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult); 1668 } 1669 1670 if (!is_message_broadcastable(Msg)) return TRUE; 1671 1672 DesktopWindow = UserGetDesktopWindow(); 1673 if (NULL == DesktopWindow) 1674 { 1675 EngSetLastError(ERROR_INTERNAL_ERROR); 1676 return 0; 1677 } 1678 1679 if (hWnd != HWND_TOPMOST) 1680 { 1681 /* Send message to the desktop window too! */ 1682 co_IntSendMessageTimeoutSingle(DesktopWindow->head.h, Msg, wParam, lParam, uFlags, uTimeout, uResult); 1683 } 1684 1685 Children = IntWinListChildren(DesktopWindow); 1686 if (NULL == Children) 1687 { 1688 return 0; 1689 } 1690 1691 for (Child = Children; NULL != *Child; Child++) 1692 { 1693 PWND pwnd = UserGetWindowObject(*Child); 1694 if (!pwnd) continue; 1695 1696 if ( pwnd->fnid == FNID_MENU || 1697 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 1698 continue; 1699 1700 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult); 1701 } 1702 1703 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST); 1704 1705 return (LRESULT) TRUE; 1706 } 1707 1708 LRESULT FASTCALL 1709 co_IntSendMessageNoWait(HWND hWnd, 1710 UINT Msg, 1711 WPARAM wParam, 1712 LPARAM lParam) 1713 { 1714 ULONG_PTR Result = 0; 1715 return co_IntSendMessageWithCallBack(hWnd, 1716 Msg, 1717 wParam, 1718 lParam, 1719 NULL, 1720 0, 1721 &Result); 1722 } 1723 /* MSDN: 1724 If you send a message in the range below WM_USER to the asynchronous message 1725 functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its 1726 message parameters cannot include pointers. Otherwise, the operation will fail. 1727 The functions will return before the receiving thread has had a chance to 1728 process the message and the sender will free the memory before it is used. 1729 */ 1730 LRESULT FASTCALL 1731 co_IntSendMessageWithCallBack(HWND hWnd, 1732 UINT Msg, 1733 WPARAM wParam, 1734 LPARAM lParam, 1735 SENDASYNCPROC CompletionCallback, 1736 ULONG_PTR CompletionCallbackContext, 1737 ULONG_PTR *uResult) 1738 { 1739 ULONG_PTR Result; 1740 PWND Window = NULL; 1741 PMSGMEMORY MsgMemoryEntry; 1742 INT lParamBufferSize; 1743 LPARAM lParamPacked; 1744 PTHREADINFO Win32Thread, ptiSendTo = NULL; 1745 DECLARE_RETURN(LRESULT); 1746 USER_REFERENCE_ENTRY Ref; 1747 PUSER_SENT_MESSAGE Message; 1748 BOOL DoCallBack = TRUE; 1749 1750 if (!(Window = UserGetWindowObject(hWnd))) 1751 { 1752 TRACE("SendMessageWithCallBack: Invalid handle 0x%p\n",hWnd); 1753 RETURN(FALSE); 1754 } 1755 1756 UserRefObjectCo(Window, &Ref); 1757 1758 if (Window->state & WNDS_DESTROYED) 1759 { 1760 /* FIXME: last error? */ 1761 ERR("Attempted to send message to window %p that is being destroyed\n", hWnd); 1762 RETURN(FALSE); 1763 } 1764 1765 Win32Thread = PsGetCurrentThreadWin32Thread(); 1766 1767 if (Win32Thread == NULL || Win32Thread->TIF_flags & TIF_INCLEANUP) 1768 RETURN(FALSE); 1769 1770 ptiSendTo = IntSendTo(Window, Win32Thread, Msg); 1771 1772 if (Msg & 0x80000000 && 1773 !ptiSendTo) 1774 { 1775 if (Win32Thread->TIF_flags & TIF_INCLEANUP) RETURN(FALSE); 1776 1777 TRACE("SMWCB: Internal Message\n"); 1778 Result = (ULONG_PTR)handle_internal_message(Window, Msg, wParam, lParam); 1779 if (uResult) *uResult = Result; 1780 RETURN(TRUE); 1781 } 1782 1783 /* See if this message type is present in the table */ 1784 MsgMemoryEntry = FindMsgMemory(Msg); 1785 if (NULL == MsgMemoryEntry) 1786 { 1787 lParamBufferSize = -1; 1788 } 1789 else 1790 { 1791 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam); 1792 if (!lParamBufferSize) lParamBufferSize = -1; 1793 } 1794 1795 if (!NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, !!ptiSendTo))) 1796 { 1797 ERR("Failed to pack message parameters\n"); 1798 RETURN(FALSE); 1799 } 1800 1801 /* If it can be sent now, then send it. */ 1802 if (!ptiSendTo) 1803 { 1804 if (Win32Thread->TIF_flags & TIF_INCLEANUP) 1805 { 1806 UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE); 1807 /* Never send messages to exiting threads */ 1808 RETURN(FALSE); 1809 } 1810 1811 IntCallWndProc(Window, hWnd, Msg, wParam, lParam); 1812 1813 if (Window->state & WNDS_SERVERSIDEWINDOWPROC) 1814 { 1815 TRACE("SMWCB: Server Side Window Procedure\n"); 1816 switch(Window->fnid) 1817 { 1818 case FNID_DESKTOP: 1819 DoCallBack = !DesktopWindowProc(Window, Msg, wParam, lParamPacked, (LRESULT*)&Result); 1820 break; 1821 case FNID_MESSAGEWND: 1822 DoCallBack = !UserMessageWindowProc(Window, Msg, wParam, lParam, (LRESULT*)&Result); 1823 break; 1824 case FNID_MENU: 1825 DoCallBack = !PopupMenuWndProc(Window, Msg, wParam, lParam, (LRESULT*)&Result); 1826 break; 1827 } 1828 } 1829 1830 if (DoCallBack) 1831 Result = (ULONG_PTR)co_IntCallWindowProc(Window->lpfnWndProc, 1832 !Window->Unicode, 1833 hWnd, 1834 Msg, 1835 wParam, 1836 lParamPacked, 1837 lParamBufferSize); 1838 if(uResult) 1839 { 1840 *uResult = Result; 1841 } 1842 1843 IntCallWndProcRet(Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult); 1844 1845 if (CompletionCallback) 1846 { 1847 co_IntCallSentMessageCallback(CompletionCallback, 1848 hWnd, 1849 Msg, 1850 CompletionCallbackContext, 1851 Result); 1852 } 1853 } 1854 1855 if (!ptiSendTo) 1856 { 1857 if (!NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE))) 1858 { 1859 ERR("Failed to unpack message parameters\n"); 1860 } 1861 RETURN(TRUE); 1862 } 1863 1864 if(!(Message = AllocateUserMessage(FALSE))) 1865 { 1866 ERR("Failed to allocate message\n"); 1867 RETURN(FALSE); 1868 } 1869 1870 Message->Msg.hwnd = hWnd; 1871 Message->Msg.message = Msg; 1872 Message->Msg.wParam = wParam; 1873 Message->Msg.lParam = lParamPacked; 1874 Message->pkCompletionEvent = NULL; // No event needed. 1875 Message->lResult = 0; 1876 Message->QS_Flags = 0; 1877 Message->ptiReceiver = ptiSendTo; 1878 Message->ptiSender = NULL; 1879 Message->ptiCallBackSender = Win32Thread; 1880 Message->CompletionCallback = CompletionCallback; 1881 Message->CompletionCallbackContext = CompletionCallbackContext; 1882 Message->HookMessage = MSQ_NORMAL; 1883 Message->HasPackedLParam = (lParamBufferSize > 0); 1884 Message->QS_Flags = QS_SENDMESSAGE; 1885 Message->flags = SMF_RECEIVERFREE; 1886 1887 if (Msg & 0x80000000) // Higher priority event message! 1888 InsertHeadList(&ptiSendTo->SentMessagesListHead, &Message->ListEntry); 1889 else 1890 InsertTailList(&ptiSendTo->SentMessagesListHead, &Message->ListEntry); 1891 MsqWakeQueue(ptiSendTo, QS_SENDMESSAGE, TRUE); 1892 1893 RETURN(TRUE); 1894 1895 CLEANUP: 1896 if (Window) UserDerefObjectCo(Window); 1897 END_CLEANUP; 1898 } 1899 1900 #if 0 1901 /* 1902 This HACK function posts a message if the destination's message queue belongs to 1903 another thread, otherwise it sends the message. It does not support broadcast 1904 messages! 1905 */ 1906 LRESULT FASTCALL 1907 co_IntPostOrSendMessage( HWND hWnd, 1908 UINT Msg, 1909 WPARAM wParam, 1910 LPARAM lParam ) 1911 { 1912 ULONG_PTR Result; 1913 PTHREADINFO pti; 1914 PWND Window; 1915 1916 if ( hWnd == HWND_BROADCAST ) 1917 { 1918 return 0; 1919 } 1920 1921 if(!(Window = UserGetWindowObject(hWnd))) 1922 { 1923 TRACE("PostOrSendMessage: Invalid handle 0x%p!\n",hWnd); 1924 return 0; 1925 } 1926 1927 pti = PsGetCurrentThreadWin32Thread(); 1928 1929 if ( IntSendTo(Window, pti, Msg) && 1930 FindMsgMemory(Msg) == 0 ) 1931 { 1932 Result = UserPostMessage(hWnd, Msg, wParam, lParam); 1933 } 1934 else 1935 { 1936 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) ) 1937 { 1938 Result = 0; 1939 } 1940 } 1941 1942 return (LRESULT)Result; 1943 } 1944 #endif 1945 1946 static LRESULT FASTCALL 1947 co_IntDoSendMessage( HWND hWnd, 1948 UINT Msg, 1949 WPARAM wParam, 1950 LPARAM lParam, 1951 PDOSENDMESSAGE dsm) 1952 { 1953 LRESULT Result = TRUE; 1954 NTSTATUS Status; 1955 PWND Window = NULL; 1956 MSG UserModeMsg, KernelModeMsg; 1957 PMSGMEMORY MsgMemoryEntry; 1958 PTHREADINFO ptiSendTo; 1959 1960 if (hWnd != HWND_BROADCAST && hWnd != HWND_TOPMOST) 1961 { 1962 Window = UserGetWindowObject(hWnd); 1963 if ( !Window ) 1964 { 1965 return 0; 1966 } 1967 } 1968 1969 /* Check for an exiting window. */ 1970 if (Window && Window->state & WNDS_DESTROYED) 1971 { 1972 ERR("co_IntDoSendMessage Window Exiting!\n"); 1973 } 1974 1975 /* See if the current thread can handle this message */ 1976 ptiSendTo = IntSendTo(Window, gptiCurrent, Msg); 1977 1978 // If broadcasting or sending to another thread, save the users data. 1979 if (!Window || ptiSendTo ) 1980 { 1981 UserModeMsg.hwnd = hWnd; 1982 UserModeMsg.message = Msg; 1983 UserModeMsg.wParam = wParam; 1984 UserModeMsg.lParam = lParam; 1985 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message); 1986 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry); 1987 if (!NT_SUCCESS(Status)) 1988 { 1989 EngSetLastError(ERROR_INVALID_PARAMETER); 1990 return (dsm ? 0 : -1); 1991 } 1992 } 1993 else 1994 { 1995 KernelModeMsg.hwnd = hWnd; 1996 KernelModeMsg.message = Msg; 1997 KernelModeMsg.wParam = wParam; 1998 KernelModeMsg.lParam = lParam; 1999 } 2000 2001 if (!dsm) 2002 { 2003 Result = co_IntSendMessage( KernelModeMsg.hwnd, 2004 KernelModeMsg.message, 2005 KernelModeMsg.wParam, 2006 KernelModeMsg.lParam ); 2007 } 2008 else 2009 { 2010 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd, 2011 KernelModeMsg.message, 2012 KernelModeMsg.wParam, 2013 KernelModeMsg.lParam, 2014 dsm->uFlags, 2015 dsm->uTimeout, 2016 &dsm->Result ); 2017 } 2018 2019 if (!Window || ptiSendTo ) 2020 { 2021 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg); 2022 if (!NT_SUCCESS(Status)) 2023 { 2024 EngSetLastError(ERROR_INVALID_PARAMETER); 2025 return(dsm ? 0 : -1); 2026 } 2027 } 2028 2029 return (LRESULT)Result; 2030 } 2031 2032 BOOL FASTCALL 2033 UserSendNotifyMessage( HWND hWnd, 2034 UINT Msg, 2035 WPARAM wParam, 2036 LPARAM lParam ) 2037 { 2038 BOOL Ret = TRUE; 2039 2040 if (is_pointer_message(Msg, wParam)) 2041 { 2042 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY ); 2043 return FALSE; 2044 } 2045 2046 // Basicly the same as IntPostOrSendMessage 2047 if (hWnd == HWND_BROADCAST) // Handle Broadcast 2048 { 2049 HWND *List; 2050 PWND DesktopWindow; 2051 ULONG i; 2052 2053 DesktopWindow = UserGetDesktopWindow(); 2054 List = IntWinListChildren(DesktopWindow); 2055 2056 if (List != NULL) 2057 { 2058 UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam); 2059 for (i = 0; List[i]; i++) 2060 { 2061 PWND pwnd = UserGetWindowObject(List[i]); 2062 if (!pwnd) continue; 2063 2064 if ( pwnd->fnid == FNID_MENU || 2065 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 2066 continue; 2067 2068 Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam); 2069 } 2070 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2071 } 2072 } 2073 else 2074 { 2075 Ret = co_IntSendMessageNoWait( hWnd, Msg, wParam, lParam); 2076 } 2077 return Ret; 2078 } 2079 2080 2081 DWORD APIENTRY 2082 IntGetQueueStatus(DWORD Changes) 2083 { 2084 PTHREADINFO pti; 2085 DWORD Result; 2086 2087 pti = PsGetCurrentThreadWin32Thread(); 2088 // wine: 2089 Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT); 2090 2091 /* High word, types of messages currently in the queue. 2092 Low word, types of messages that have been added to the queue and that 2093 are still in the queue 2094 */ 2095 Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes); 2096 2097 pti->pcti->fsChangeBits &= ~Changes; 2098 2099 return Result; 2100 } 2101 2102 BOOL APIENTRY 2103 IntInitMessagePumpHook(VOID) 2104 { 2105 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 2106 2107 if (pti->pcti) 2108 { 2109 pti->pcti->dwcPumpHook++; 2110 return TRUE; 2111 } 2112 return FALSE; 2113 } 2114 2115 BOOL APIENTRY 2116 IntUninitMessagePumpHook(VOID) 2117 { 2118 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 2119 2120 if (pti->pcti) 2121 { 2122 if (pti->pcti->dwcPumpHook <= 0) 2123 { 2124 return FALSE; 2125 } 2126 pti->pcti->dwcPumpHook--; 2127 return TRUE; 2128 } 2129 return FALSE; 2130 } 2131 2132 BOOL FASTCALL 2133 IntCallMsgFilter( LPMSG lpmsg, INT code) 2134 { 2135 BOOL Ret = FALSE; 2136 2137 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)lpmsg)) 2138 { 2139 Ret = TRUE; 2140 } 2141 else 2142 { 2143 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)lpmsg); 2144 } 2145 return Ret; 2146 } 2147 2148 /** Functions ******************************************************************/ 2149 2150 BOOL 2151 APIENTRY 2152 NtUserDragDetect( 2153 HWND hWnd, 2154 POINT pt) // Just like the User call. 2155 { 2156 MSG msg; 2157 RECT rect; 2158 ULONG wDragWidth, wDragHeight; 2159 DECLARE_RETURN(BOOL); 2160 2161 TRACE("Enter NtUserDragDetect(%p)\n", hWnd); 2162 UserEnterExclusive(); 2163 2164 wDragWidth = UserGetSystemMetrics(SM_CXDRAG); 2165 wDragHeight= UserGetSystemMetrics(SM_CYDRAG); 2166 2167 rect.left = pt.x - wDragWidth; 2168 rect.right = pt.x + wDragWidth; 2169 2170 rect.top = pt.y - wDragHeight; 2171 rect.bottom = pt.y + wDragHeight; 2172 2173 co_UserSetCapture(hWnd); 2174 2175 for (;;) 2176 { 2177 while (co_IntGetPeekMessage( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, FALSE ) || 2178 co_IntGetPeekMessage( &msg, 0, WM_QUEUESYNC, WM_QUEUESYNC, PM_REMOVE, FALSE ) || 2179 co_IntGetPeekMessage( &msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE, FALSE ) ) 2180 { 2181 if ( msg.message == WM_LBUTTONUP ) 2182 { 2183 co_UserSetCapture(NULL); 2184 RETURN( FALSE); 2185 } 2186 if ( msg.message == WM_MOUSEMOVE ) 2187 { 2188 POINT tmp; 2189 tmp.x = (short)LOWORD(msg.lParam); 2190 tmp.y = (short)HIWORD(msg.lParam); 2191 if( !RECTL_bPointInRect( &rect, tmp.x, tmp.y ) ) 2192 { 2193 co_UserSetCapture(NULL); 2194 RETURN( TRUE); 2195 } 2196 } 2197 if ( msg.message == WM_KEYDOWN ) 2198 { 2199 if ( msg.wParam == VK_ESCAPE ) 2200 { 2201 co_UserSetCapture(NULL); 2202 RETURN( TRUE); 2203 } 2204 } 2205 if ( msg.message == WM_QUEUESYNC ) 2206 { 2207 co_HOOK_CallHooks( WH_CBT, HCBT_QS, 0, 0 ); 2208 } 2209 } 2210 co_IntWaitMessage(NULL, 0, 0); 2211 } 2212 RETURN( FALSE); 2213 2214 CLEANUP: 2215 TRACE("Leave NtUserDragDetect, ret=%i\n",_ret_); 2216 UserLeave(); 2217 END_CLEANUP; 2218 } 2219 2220 BOOL APIENTRY 2221 NtUserPostMessage(HWND hWnd, 2222 UINT Msg, 2223 WPARAM wParam, 2224 LPARAM lParam) 2225 { 2226 BOOL ret; 2227 2228 UserEnterExclusive(); 2229 2230 ret = UserPostMessage(hWnd, Msg, wParam, lParam); 2231 2232 UserLeave(); 2233 2234 return ret; 2235 } 2236 2237 BOOL APIENTRY 2238 NtUserPostThreadMessage(DWORD idThread, 2239 UINT Msg, 2240 WPARAM wParam, 2241 LPARAM lParam) 2242 { 2243 BOOL ret = FALSE; 2244 PETHREAD peThread; 2245 PTHREADINFO pThread; 2246 NTSTATUS Status; 2247 2248 UserEnterExclusive(); 2249 2250 Status = PsLookupThreadByThreadId(UlongToHandle(idThread), &peThread); 2251 2252 if ( Status == STATUS_SUCCESS ) 2253 { 2254 pThread = (PTHREADINFO)peThread->Tcb.Win32Thread; 2255 if( !pThread || 2256 !pThread->MessageQueue || 2257 (pThread->TIF_flags & TIF_INCLEANUP)) 2258 { 2259 ObDereferenceObject( peThread ); 2260 goto exit; 2261 } 2262 ret = UserPostThreadMessage( pThread, Msg, wParam, lParam); 2263 ObDereferenceObject( peThread ); 2264 } 2265 else 2266 { 2267 SetLastNtError( Status ); 2268 } 2269 exit: 2270 UserLeave(); 2271 return ret; 2272 } 2273 2274 BOOL APIENTRY 2275 NtUserWaitMessage(VOID) 2276 { 2277 BOOL ret; 2278 2279 UserEnterExclusive(); 2280 TRACE("NtUserWaitMessage Enter\n"); 2281 ret = co_IntWaitMessage(NULL, 0, 0); 2282 TRACE("NtUserWaitMessage Leave\n"); 2283 UserLeave(); 2284 2285 return ret; 2286 } 2287 2288 BOOL APIENTRY 2289 NtUserGetMessage(PMSG pMsg, 2290 HWND hWnd, 2291 UINT MsgFilterMin, 2292 UINT MsgFilterMax ) 2293 { 2294 MSG Msg; 2295 BOOL Ret; 2296 2297 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM ) 2298 { 2299 EngSetLastError(ERROR_INVALID_PARAMETER); 2300 return FALSE; 2301 } 2302 2303 UserEnterExclusive(); 2304 2305 RtlZeroMemory(&Msg, sizeof(MSG)); 2306 2307 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE); 2308 2309 UserLeave(); 2310 2311 if (Ret) 2312 { 2313 _SEH2_TRY 2314 { 2315 ProbeForWrite(pMsg, sizeof(MSG), 1); 2316 RtlCopyMemory(pMsg, &Msg, sizeof(MSG)); 2317 } 2318 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2319 { 2320 SetLastNtError(_SEH2_GetExceptionCode()); 2321 Ret = FALSE; 2322 } 2323 _SEH2_END; 2324 } 2325 2326 if ((INT)Ret != -1) 2327 Ret = Ret ? (WM_QUIT != pMsg->message) : FALSE; 2328 2329 return Ret; 2330 } 2331 2332 BOOL APIENTRY 2333 NtUserPeekMessage( PMSG pMsg, 2334 HWND hWnd, 2335 UINT MsgFilterMin, 2336 UINT MsgFilterMax, 2337 UINT RemoveMsg) 2338 { 2339 MSG Msg; 2340 BOOL Ret; 2341 2342 if ( RemoveMsg & PM_BADMSGFLAGS ) 2343 { 2344 EngSetLastError(ERROR_INVALID_FLAGS); 2345 return FALSE; 2346 } 2347 2348 UserEnterExclusive(); 2349 2350 RtlZeroMemory(&Msg, sizeof(MSG)); 2351 2352 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE); 2353 2354 UserLeave(); 2355 2356 if (Ret) 2357 { 2358 _SEH2_TRY 2359 { 2360 ProbeForWrite(pMsg, sizeof(MSG), 1); 2361 RtlCopyMemory(pMsg, &Msg, sizeof(MSG)); 2362 } 2363 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2364 { 2365 SetLastNtError(_SEH2_GetExceptionCode()); 2366 Ret = FALSE; 2367 } 2368 _SEH2_END; 2369 } 2370 2371 return Ret; 2372 } 2373 2374 BOOL APIENTRY 2375 NtUserCallMsgFilter( LPMSG lpmsg, INT code) 2376 { 2377 BOOL Ret = FALSE; 2378 MSG Msg; 2379 2380 _SEH2_TRY 2381 { 2382 ProbeForRead(lpmsg, sizeof(MSG), 1); 2383 RtlCopyMemory( &Msg, lpmsg, sizeof(MSG)); 2384 } 2385 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2386 { 2387 _SEH2_YIELD(return FALSE); 2388 } 2389 _SEH2_END; 2390 2391 UserEnterExclusive(); 2392 2393 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg)) 2394 { 2395 Ret = TRUE; 2396 } 2397 else 2398 { 2399 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg); 2400 } 2401 2402 UserLeave(); 2403 2404 _SEH2_TRY 2405 { 2406 ProbeForWrite(lpmsg, sizeof(MSG), 1); 2407 RtlCopyMemory(lpmsg, &Msg, sizeof(MSG)); 2408 } 2409 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2410 { 2411 Ret = FALSE; 2412 } 2413 _SEH2_END; 2414 2415 return Ret; 2416 } 2417 2418 LRESULT APIENTRY 2419 NtUserDispatchMessage(PMSG UnsafeMsgInfo) 2420 { 2421 LRESULT Res = 0; 2422 MSG SafeMsg; 2423 2424 _SEH2_TRY 2425 { 2426 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1); 2427 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG)); 2428 } 2429 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2430 { 2431 SetLastNtError(_SEH2_GetExceptionCode()); 2432 _SEH2_YIELD(return FALSE); 2433 } 2434 _SEH2_END; 2435 2436 UserEnterExclusive(); 2437 2438 Res = IntDispatchMessage(&SafeMsg); 2439 2440 UserLeave(); 2441 return Res; 2442 } 2443 2444 BOOL APIENTRY 2445 NtUserTranslateMessage(LPMSG lpMsg, UINT flags) 2446 { 2447 MSG SafeMsg; 2448 BOOL Ret; 2449 PWND pWnd; 2450 2451 _SEH2_TRY 2452 { 2453 ProbeForRead(lpMsg, sizeof(MSG), 1); 2454 RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG)); 2455 } 2456 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2457 { 2458 SetLastNtError(_SEH2_GetExceptionCode()); 2459 _SEH2_YIELD(return FALSE); 2460 } 2461 _SEH2_END; 2462 2463 UserEnterExclusive(); 2464 pWnd = UserGetWindowObject(SafeMsg.hwnd); 2465 if (pWnd) // Must have a window! 2466 { 2467 Ret = IntTranslateKbdMessage(&SafeMsg, flags); 2468 } 2469 else 2470 { 2471 TRACE("No Window for Translate. hwnd 0x%p Msg %u\n", SafeMsg.hwnd, SafeMsg.message); 2472 Ret = FALSE; 2473 } 2474 UserLeave(); 2475 2476 return Ret; 2477 } 2478 2479 LRESULT APIENTRY ScrollBarWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam); 2480 2481 BOOL APIENTRY 2482 NtUserMessageCall( HWND hWnd, 2483 UINT Msg, 2484 WPARAM wParam, 2485 LPARAM lParam, 2486 ULONG_PTR ResultInfo, 2487 DWORD dwType, // fnID? 2488 BOOL Ansi) 2489 { 2490 LRESULT lResult = 0; 2491 BOOL Ret = FALSE; 2492 PWND Window = NULL; 2493 USER_REFERENCE_ENTRY Ref; 2494 2495 UserEnterExclusive(); 2496 2497 switch(dwType) 2498 { 2499 case FNID_SCROLLBAR: 2500 { 2501 lResult = ScrollBarWndProc(hWnd, Msg, wParam, lParam); 2502 break; 2503 } 2504 case FNID_DESKTOP: 2505 { 2506 Window = UserGetWindowObject(hWnd); 2507 if (Window) 2508 { 2509 //ERR("FNID_DESKTOP IN\n"); 2510 Ret = DesktopWindowProc(Window, Msg, wParam, lParam, &lResult); 2511 //ERR("FNID_DESKTOP OUT\n"); 2512 } 2513 break; 2514 } 2515 case FNID_MENU: 2516 { 2517 Window = UserGetWindowObject(hWnd); 2518 if (Window) 2519 { 2520 Ret = PopupMenuWndProc( Window, Msg, wParam, lParam, &lResult); 2521 } 2522 break; 2523 } 2524 case FNID_MESSAGEWND: 2525 { 2526 Window = UserGetWindowObject(hWnd); 2527 if (Window) 2528 { 2529 Ret = !UserMessageWindowProc(Window, Msg, wParam, lParam, &lResult); 2530 } 2531 break; 2532 } 2533 case FNID_DEFWINDOWPROC: 2534 /* Validate input */ 2535 if (hWnd) 2536 { 2537 Window = UserGetWindowObject(hWnd); 2538 if (!Window) 2539 { 2540 UserLeave(); 2541 return FALSE; 2542 } 2543 UserRefObjectCo(Window, &Ref); 2544 } 2545 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi); 2546 Ret = TRUE; 2547 if (hWnd) 2548 UserDerefObjectCo(Window); 2549 break; 2550 case FNID_SENDNOTIFYMESSAGE: 2551 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam); 2552 break; 2553 case FNID_BROADCASTSYSTEMMESSAGE: 2554 { 2555 BROADCASTPARM parm, *retparam; 2556 DWORD_PTR RetVal = 0; 2557 2558 if (ResultInfo) 2559 { 2560 _SEH2_TRY 2561 { 2562 ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1); 2563 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM)); 2564 } 2565 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2566 { 2567 _SEH2_YIELD(break); 2568 } 2569 _SEH2_END; 2570 } 2571 else 2572 break; 2573 2574 if ( parm.recipients & BSM_ALLDESKTOPS || 2575 parm.recipients == BSM_ALLCOMPONENTS ) 2576 { 2577 PLIST_ENTRY DesktopEntry; 2578 PDESKTOP rpdesk; 2579 HWND *List, hwndDenied = NULL; 2580 HDESK hDesk = NULL; 2581 PWND pwnd, pwndDesk; 2582 ULONG i; 2583 UINT fuFlags; 2584 2585 for (DesktopEntry = InputWindowStation->DesktopListHead.Flink; 2586 DesktopEntry != &InputWindowStation->DesktopListHead; 2587 DesktopEntry = DesktopEntry->Flink) 2588 { 2589 rpdesk = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry); 2590 pwndDesk = rpdesk->pDeskInfo->spwnd; 2591 List = IntWinListChildren(pwndDesk); 2592 2593 if (parm.flags & BSF_QUERY) 2594 { 2595 if (List != NULL) 2596 { 2597 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG) 2598 { 2599 fuFlags = SMTO_ABORTIFHUNG; 2600 } 2601 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG) 2602 { 2603 fuFlags = SMTO_NOTIMEOUTIFNOTHUNG; 2604 } 2605 else 2606 { 2607 fuFlags = SMTO_NORMAL; 2608 } 2609 co_IntSendMessageTimeout( UserHMGetHandle(pwndDesk), 2610 Msg, 2611 wParam, 2612 lParam, 2613 fuFlags, 2614 2000, 2615 &RetVal); 2616 Ret = TRUE; 2617 for (i = 0; List[i]; i++) 2618 { 2619 pwnd = UserGetWindowObject(List[i]); 2620 if (!pwnd) continue; 2621 2622 if ( pwnd->fnid == FNID_MENU || 2623 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 2624 continue; 2625 2626 if ( parm.flags & BSF_IGNORECURRENTTASK ) 2627 { 2628 if ( pwnd->head.pti == gptiCurrent ) 2629 continue; 2630 } 2631 co_IntSendMessageTimeout( List[i], 2632 Msg, 2633 wParam, 2634 lParam, 2635 fuFlags, 2636 2000, 2637 &RetVal); 2638 2639 if (!RetVal && EngGetLastError() == ERROR_TIMEOUT) 2640 { 2641 if (!(parm.flags & BSF_FORCEIFHUNG)) 2642 Ret = FALSE; 2643 } 2644 if (RetVal == BROADCAST_QUERY_DENY) 2645 { 2646 hwndDenied = List[i]; 2647 hDesk = UserHMGetHandle(pwndDesk); 2648 Ret = FALSE; 2649 } 2650 } 2651 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2652 _SEH2_TRY 2653 { 2654 retparam = (PBROADCASTPARM) ResultInfo; 2655 retparam->hDesk = hDesk; 2656 retparam->hWnd = hwndDenied; 2657 } 2658 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2659 { 2660 _SEH2_YIELD(break); 2661 } 2662 _SEH2_END; 2663 if (!Ret) break; // Have a hit! Let everyone know! 2664 } 2665 } 2666 else if (parm.flags & BSF_POSTMESSAGE) 2667 { 2668 if (List != NULL) 2669 { 2670 UserPostMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam); 2671 2672 for (i = 0; List[i]; i++) 2673 { 2674 pwnd = UserGetWindowObject(List[i]); 2675 if (!pwnd) continue; 2676 2677 if ( pwnd->fnid == FNID_MENU || 2678 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 2679 continue; 2680 2681 if ( parm.flags & BSF_IGNORECURRENTTASK ) 2682 { 2683 if ( pwnd->head.pti == gptiCurrent ) 2684 continue; 2685 } 2686 UserPostMessage(List[i], Msg, wParam, lParam); 2687 } 2688 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2689 } 2690 Ret = TRUE; 2691 } 2692 else 2693 { 2694 if (List != NULL) 2695 { 2696 UserSendNotifyMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam); 2697 2698 for (i = 0; List[i]; i++) 2699 { 2700 pwnd = UserGetWindowObject(List[i]); 2701 if (!pwnd) continue; 2702 2703 if ( pwnd->fnid == FNID_MENU || 2704 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 2705 continue; 2706 2707 if ( parm.flags & BSF_IGNORECURRENTTASK ) 2708 { 2709 if ( pwnd->head.pti == gptiCurrent ) 2710 continue; 2711 } 2712 UserSendNotifyMessage(List[i], Msg, wParam, lParam); 2713 } 2714 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2715 } 2716 Ret = TRUE; 2717 } 2718 } 2719 } 2720 else if (parm.recipients & BSM_APPLICATIONS) 2721 { 2722 HWND *List, hwndDenied = NULL; 2723 HDESK hDesk = NULL; 2724 PWND pwnd, pwndDesk; 2725 ULONG i; 2726 UINT fuFlags; 2727 2728 pwndDesk = UserGetDesktopWindow(); 2729 List = IntWinListChildren(pwndDesk); 2730 2731 if (parm.flags & BSF_QUERY) 2732 { 2733 if (List != NULL) 2734 { 2735 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG) 2736 { 2737 fuFlags = SMTO_ABORTIFHUNG; 2738 } 2739 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG) 2740 { 2741 fuFlags = SMTO_NOTIMEOUTIFNOTHUNG; 2742 } 2743 else 2744 { 2745 fuFlags = SMTO_NORMAL; 2746 } 2747 co_IntSendMessageTimeout( UserHMGetHandle(pwndDesk), 2748 Msg, 2749 wParam, 2750 lParam, 2751 fuFlags, 2752 2000, 2753 &RetVal); 2754 Ret = TRUE; 2755 for (i = 0; List[i]; i++) 2756 { 2757 pwnd = UserGetWindowObject(List[i]); 2758 if (!pwnd) continue; 2759 2760 if ( pwnd->fnid == FNID_MENU || 2761 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 2762 continue; 2763 2764 if ( parm.flags & BSF_IGNORECURRENTTASK ) 2765 { 2766 if ( pwnd->head.pti == gptiCurrent ) 2767 continue; 2768 } 2769 co_IntSendMessageTimeout( List[i], 2770 Msg, 2771 wParam, 2772 lParam, 2773 fuFlags, 2774 2000, 2775 &RetVal); 2776 2777 if (!RetVal && EngGetLastError() == ERROR_TIMEOUT) 2778 { 2779 if (!(parm.flags & BSF_FORCEIFHUNG)) 2780 Ret = FALSE; 2781 } 2782 if (RetVal == BROADCAST_QUERY_DENY) 2783 { 2784 hwndDenied = List[i]; 2785 hDesk = UserHMGetHandle(pwndDesk); 2786 Ret = FALSE; 2787 } 2788 } 2789 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2790 _SEH2_TRY 2791 { 2792 retparam = (PBROADCASTPARM) ResultInfo; 2793 retparam->hDesk = hDesk; 2794 retparam->hWnd = hwndDenied; 2795 } 2796 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2797 { 2798 _SEH2_YIELD(break); 2799 } 2800 _SEH2_END; 2801 } 2802 } 2803 else if (parm.flags & BSF_POSTMESSAGE) 2804 { 2805 if (List != NULL) 2806 { 2807 UserPostMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam); 2808 2809 for (i = 0; List[i]; i++) 2810 { 2811 pwnd = UserGetWindowObject(List[i]); 2812 if (!pwnd) continue; 2813 2814 if ( pwnd->fnid == FNID_MENU || 2815 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 2816 continue; 2817 2818 if ( parm.flags & BSF_IGNORECURRENTTASK ) 2819 { 2820 if ( pwnd->head.pti == gptiCurrent ) 2821 continue; 2822 } 2823 UserPostMessage(List[i], Msg, wParam, lParam); 2824 } 2825 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2826 } 2827 Ret = TRUE; 2828 } 2829 else 2830 { 2831 if (List != NULL) 2832 { 2833 UserSendNotifyMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam); 2834 2835 for (i = 0; List[i]; i++) 2836 { 2837 pwnd = UserGetWindowObject(List[i]); 2838 if (!pwnd) continue; 2839 2840 if ( pwnd->fnid == FNID_MENU || 2841 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] ) 2842 continue; 2843 2844 if ( parm.flags & BSF_IGNORECURRENTTASK ) 2845 { 2846 if ( pwnd->head.pti == gptiCurrent ) 2847 continue; 2848 } 2849 UserSendNotifyMessage(List[i], Msg, wParam, lParam); 2850 } 2851 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2852 } 2853 Ret = TRUE; 2854 } 2855 } 2856 } 2857 break; 2858 case FNID_SENDMESSAGECALLBACK: 2859 { 2860 CALL_BACK_INFO CallBackInfo; 2861 ULONG_PTR uResult; 2862 2863 _SEH2_TRY 2864 { 2865 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1); 2866 RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO)); 2867 } 2868 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2869 { 2870 _SEH2_YIELD(break); 2871 } 2872 _SEH2_END; 2873 2874 if (is_pointer_message(Msg, wParam)) 2875 { 2876 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY ); 2877 break; 2878 } 2879 2880 if (!(Ret = co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam, 2881 CallBackInfo.CallBack, CallBackInfo.Context, &uResult))) 2882 { 2883 ERR("Callback failure!\n"); 2884 } 2885 } 2886 break; 2887 case FNID_SENDMESSAGE: 2888 { 2889 lResult = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0); 2890 Ret = TRUE; 2891 2892 if (ResultInfo) 2893 { 2894 _SEH2_TRY 2895 { 2896 ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1); 2897 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(ULONG_PTR)); 2898 } 2899 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2900 { 2901 Ret = FALSE; 2902 _SEH2_YIELD(break); 2903 } 2904 _SEH2_END; 2905 } 2906 break; 2907 } 2908 case FNID_SENDMESSAGEFF: 2909 case FNID_SENDMESSAGEWTOOPTION: 2910 { 2911 DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo; 2912 if (ResultInfo) 2913 { 2914 _SEH2_TRY 2915 { 2916 ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1); 2917 RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE)); 2918 } 2919 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2920 { 2921 _SEH2_YIELD(break); 2922 } 2923 _SEH2_END; 2924 } 2925 2926 Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, pdsm ? &dsm : NULL ); 2927 2928 if (pdsm) 2929 { 2930 _SEH2_TRY 2931 { 2932 ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1); 2933 RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE)); 2934 } 2935 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2936 { 2937 Ret = FALSE; 2938 _SEH2_YIELD(break); 2939 } 2940 _SEH2_END; 2941 } 2942 break; 2943 } 2944 // CallNextHook bypass. 2945 case FNID_CALLWNDPROC: 2946 case FNID_CALLWNDPROCRET: 2947 { 2948 PTHREADINFO pti; 2949 PCLIENTINFO ClientInfo; 2950 PHOOK NextObj, Hook; 2951 2952 pti = GetW32ThreadInfo(); 2953 2954 Hook = pti->sphkCurrent; 2955 2956 if (!Hook) break; 2957 2958 NextObj = Hook->phkNext; 2959 ClientInfo = pti->pClientInfo; 2960 _SEH2_TRY 2961 { 2962 ClientInfo->phkCurrent = NextObj; 2963 } 2964 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2965 { 2966 ClientInfo = NULL; 2967 } 2968 _SEH2_END; 2969 2970 if (!ClientInfo || !NextObj) break; 2971 2972 NextObj->phkNext = IntGetNextHook(NextObj); 2973 2974 if ( Hook->HookId == WH_CALLWNDPROC) 2975 { 2976 CWPSTRUCT CWP; 2977 CWP.hwnd = hWnd; 2978 CWP.message = Msg; 2979 CWP.wParam = wParam; 2980 CWP.lParam = lParam; 2981 TRACE("WH_CALLWNDPROC: Hook %p NextHook %p\n", Hook, NextObj); 2982 2983 lResult = co_IntCallHookProc( Hook->HookId, 2984 HC_ACTION, 2985 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0), 2986 (LPARAM)&CWP, 2987 Hook->Proc, 2988 Hook->ihmod, 2989 Hook->offPfn, 2990 Hook->Ansi, 2991 &Hook->ModuleName); 2992 } 2993 else 2994 { 2995 CWPRETSTRUCT CWPR; 2996 CWPR.hwnd = hWnd; 2997 CWPR.message = Msg; 2998 CWPR.wParam = wParam; 2999 CWPR.lParam = lParam; 3000 CWPR.lResult = ClientInfo->dwHookData; 3001 3002 lResult = co_IntCallHookProc( Hook->HookId, 3003 HC_ACTION, 3004 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0), 3005 (LPARAM)&CWPR, 3006 Hook->Proc, 3007 Hook->ihmod, 3008 Hook->offPfn, 3009 Hook->Ansi, 3010 &Hook->ModuleName); 3011 } 3012 } 3013 break; 3014 } 3015 3016 switch(dwType) 3017 { 3018 case FNID_DEFWINDOWPROC: 3019 case FNID_CALLWNDPROC: 3020 case FNID_CALLWNDPROCRET: 3021 case FNID_SCROLLBAR: 3022 case FNID_DESKTOP: 3023 case FNID_MENU: 3024 if (ResultInfo) 3025 { 3026 _SEH2_TRY 3027 { 3028 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1); 3029 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT)); 3030 } 3031 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3032 { 3033 Ret = FALSE; 3034 } 3035 _SEH2_END; 3036 } 3037 break; 3038 default: 3039 break; 3040 } 3041 3042 UserLeave(); 3043 3044 return Ret; 3045 } 3046 3047 #define INFINITE 0xFFFFFFFF 3048 #define WAIT_FAILED ((DWORD)0xFFFFFFFF) 3049 3050 DWORD 3051 APIENTRY 3052 NtUserWaitForInputIdle( IN HANDLE hProcess, 3053 IN DWORD dwMilliseconds, 3054 IN BOOL bSharedWow) 3055 { 3056 PEPROCESS Process; 3057 PPROCESSINFO W32Process; 3058 PTHREADINFO pti; 3059 NTSTATUS Status; 3060 HANDLE Handles[3]; 3061 LARGE_INTEGER Timeout; 3062 KAPC_STATE ApcState; 3063 3064 UserEnterExclusive(); 3065 3066 Status = ObReferenceObjectByHandle(hProcess, 3067 PROCESS_QUERY_INFORMATION, 3068 *PsProcessType, 3069 UserMode, 3070 (PVOID*)&Process, 3071 NULL); 3072 3073 if (!NT_SUCCESS(Status)) 3074 { 3075 UserLeave(); 3076 SetLastNtError(Status); 3077 return WAIT_FAILED; 3078 } 3079 3080 pti = PsGetCurrentThreadWin32Thread(); 3081 3082 W32Process = (PPROCESSINFO)Process->Win32Process; 3083 3084 if ( PsGetProcessExitProcessCalled(Process) || 3085 !W32Process || 3086 pti->ppi == W32Process) 3087 { 3088 ObDereferenceObject(Process); 3089 UserLeave(); 3090 EngSetLastError(ERROR_INVALID_PARAMETER); 3091 return WAIT_FAILED; 3092 } 3093 3094 Handles[0] = Process; 3095 Handles[1] = W32Process->InputIdleEvent; 3096 Handles[2] = pti->pEventQueueServer; // IntMsqSetWakeMask returns hEventQueueClient 3097 3098 if (!Handles[1]) 3099 { 3100 ObDereferenceObject(Process); 3101 UserLeave(); 3102 return STATUS_SUCCESS; /* no event to wait on */ 3103 } 3104 3105 if (dwMilliseconds != INFINITE) 3106 Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000; 3107 3108 KeStackAttachProcess(&Process->Pcb, &ApcState); 3109 W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE; 3110 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling) 3111 { 3112 pti->TIF_flags |= TIF_WAITFORINPUTIDLE; 3113 pti->pClientInfo->dwTIFlags = pti->TIF_flags; 3114 } 3115 KeUnstackDetachProcess(&ApcState); 3116 3117 TRACE("WFII: ppi %p\n", W32Process); 3118 TRACE("WFII: waiting for %p\n", Handles[1] ); 3119 3120 /* 3121 * We must add a refcount to our current PROCESSINFO, 3122 * because anything could happen (including process death) we're leaving win32k 3123 */ 3124 IntReferenceProcessInfo(W32Process); 3125 3126 do 3127 { 3128 UserLeave(); 3129 Status = KeWaitForMultipleObjects( 3, 3130 Handles, 3131 WaitAny, 3132 UserRequest, 3133 UserMode, 3134 FALSE, 3135 dwMilliseconds == INFINITE ? NULL : &Timeout, 3136 NULL); 3137 UserEnterExclusive(); 3138 3139 if (!NT_SUCCESS(Status)) 3140 { 3141 SetLastNtError(Status); 3142 Status = WAIT_FAILED; 3143 goto WaitExit; 3144 } 3145 3146 switch (Status) 3147 { 3148 case STATUS_WAIT_0: 3149 goto WaitExit; 3150 3151 case STATUS_WAIT_2: 3152 { 3153 MSG Msg; 3154 co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE); 3155 ERR("WFII: WAIT 2\n"); 3156 } 3157 break; 3158 3159 case STATUS_TIMEOUT: 3160 ERR("WFII: timeout\n"); 3161 case WAIT_FAILED: 3162 goto WaitExit; 3163 3164 default: 3165 ERR("WFII: finished\n"); 3166 Status = STATUS_SUCCESS; 3167 goto WaitExit; 3168 } 3169 } 3170 while (TRUE); 3171 3172 WaitExit: 3173 KeStackAttachProcess(&Process->Pcb, &ApcState); 3174 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling) 3175 { 3176 pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE; 3177 pti->pClientInfo->dwTIFlags = pti->TIF_flags; 3178 } 3179 W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE; 3180 KeUnstackDetachProcess(&ApcState); 3181 3182 IntDereferenceProcessInfo(W32Process); 3183 ObDereferenceObject(Process); 3184 UserLeave(); 3185 return Status; 3186 } 3187 3188 /* EOF */ 3189