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