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