1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Message queues
5 * FILE: win32ss/user/ntuser/msgqueue.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 Alexandre Julliard
8 Maarten Lankhorst
9 */
10
11 #include <win32k.h>
12 DBG_DEFAULT_CHANNEL(UserMsgQ);
13
14 /* GLOBALS *******************************************************************/
15
16 static PPAGED_LOOKASIDE_LIST pgMessageLookasideList;
17 static PPAGED_LOOKASIDE_LIST pgSendMsgLookasideList;
18 INT PostMsgCount = 0;
19 INT SendMsgCount = 0;
20 PUSER_MESSAGE_QUEUE gpqCursor;
21 ULONG_PTR gdwMouseMoveExtraInfo = 0;
22 DWORD gdwMouseMoveTimeStamp = 0;
23 LIST_ENTRY usmList;
24
25 /* FUNCTIONS *****************************************************************/
26
27 CODE_SEG("INIT")
28 NTSTATUS
29 NTAPI
MsqInitializeImpl(VOID)30 MsqInitializeImpl(VOID)
31 {
32 // Setup Post Messages
33 pgMessageLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG);
34 if (!pgMessageLookasideList)
35 return STATUS_NO_MEMORY;
36 ExInitializePagedLookasideList(pgMessageLookasideList,
37 NULL,
38 NULL,
39 0,
40 sizeof(USER_MESSAGE),
41 TAG_USRMSG,
42 256);
43 // Setup Send Messages
44 pgSendMsgLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG);
45 if (!pgSendMsgLookasideList)
46 return STATUS_NO_MEMORY;
47 ExInitializePagedLookasideList(pgSendMsgLookasideList,
48 NULL,
49 NULL,
50 0,
51 sizeof(USER_SENT_MESSAGE),
52 TAG_USRMSG,
53 16);
54
55 InitializeListHead(&usmList);
56
57 return(STATUS_SUCCESS);
58 }
59
60 PWND FASTCALL
IntTopLevelWindowFromPoint(INT x,INT y)61 IntTopLevelWindowFromPoint(INT x, INT y)
62 {
63 PWND pWnd, pwndDesktop;
64
65 /* Get the desktop window */
66 pwndDesktop = UserGetDesktopWindow();
67 if (!pwndDesktop)
68 return NULL;
69
70 /* Loop all top level windows */
71 for (pWnd = pwndDesktop->spwndChild;
72 pWnd != NULL;
73 pWnd = pWnd->spwndNext)
74 {
75 if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED)
76 {
77 TRACE("The Window is in DESTROY!\n");
78 continue;
79 }
80
81 if ((pWnd->style & WS_VISIBLE) &&
82 (pWnd->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) != (WS_EX_LAYERED|WS_EX_TRANSPARENT) &&
83 IntPtInWindow(pWnd, x, y))
84 return pWnd;
85 }
86
87 /* Window has not been found */
88 return pwndDesktop;
89 }
90
91 PCURICON_OBJECT
92 FASTCALL
UserSetCursor(PCURICON_OBJECT NewCursor,BOOL ForceChange)93 UserSetCursor(
94 PCURICON_OBJECT NewCursor,
95 BOOL ForceChange)
96 {
97 PCURICON_OBJECT OldCursor;
98 HDC hdcScreen;
99 PTHREADINFO pti;
100 PUSER_MESSAGE_QUEUE MessageQueue;
101 PWND pWnd;
102
103 pti = PsGetCurrentThreadWin32Thread();
104 MessageQueue = pti->MessageQueue;
105
106 OldCursor = MessageQueue->CursorObject;
107
108 /* Check if cursors are different */
109 if (OldCursor == NewCursor)
110 return OldCursor;
111
112 /* Update cursor for this message queue */
113 MessageQueue->CursorObject = NewCursor;
114
115 /* If cursor is not visible we have nothing to do */
116 if (MessageQueue->iCursorLevel < 0)
117 return OldCursor;
118
119 // Fixes the error message "Not the same cursor!".
120 if (gpqCursor == NULL)
121 {
122 gpqCursor = MessageQueue;
123 }
124
125 /* Update cursor if this message queue controls it */
126 pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y);
127 if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue)
128 {
129 /* Get the screen DC */
130 if (!(hdcScreen = IntGetScreenDC()))
131 {
132 return NULL;
133 }
134
135 if (NewCursor)
136 {
137 /* Call GDI to set the new screen cursor */
138 PCURICON_OBJECT CursorFrame = NewCursor;
139 if(NewCursor->CURSORF_flags & CURSORF_ACON)
140 {
141 FIXME("Should animate the cursor, using only the first frame now.\n");
142 CursorFrame = ((PACON)NewCursor)->aspcur[0];
143 }
144 GreSetPointerShape(hdcScreen,
145 CursorFrame->hbmAlpha ? NULL : NewCursor->hbmMask,
146 CursorFrame->hbmAlpha ? NewCursor->hbmAlpha : NewCursor->hbmColor,
147 CursorFrame->xHotspot,
148 CursorFrame->yHotspot,
149 gpsi->ptCursor.x,
150 gpsi->ptCursor.y,
151 CursorFrame->hbmAlpha ? SPS_ALPHA : 0);
152 }
153 else /* Note: OldCursor != NewCursor so we have to hide cursor */
154 {
155 /* Remove the cursor */
156 GreMovePointer(hdcScreen, -1, -1);
157 TRACE("Removing pointer!\n");
158 }
159 IntGetSysCursorInfo()->CurrentCursorObject = NewCursor;
160 }
161
162 /* Return the old cursor */
163 return OldCursor;
164 }
165
166 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
167 * User32 macro NtUserShowCursor */
UserShowCursor(BOOL bShow)168 int UserShowCursor(BOOL bShow)
169 {
170 HDC hdcScreen;
171 PTHREADINFO pti;
172 PUSER_MESSAGE_QUEUE MessageQueue;
173 PWND pWnd;
174
175 if (!(hdcScreen = IntGetScreenDC()))
176 {
177 return -1; /* No mouse */
178 }
179
180 pti = PsGetCurrentThreadWin32Thread();
181 MessageQueue = pti->MessageQueue;
182
183 /* Update counter */
184 MessageQueue->iCursorLevel += bShow ? 1 : -1;
185 pti->iCursorLevel += bShow ? 1 : -1;
186
187 /* Check for trivial cases */
188 if ((bShow && MessageQueue->iCursorLevel != 0) ||
189 (!bShow && MessageQueue->iCursorLevel != -1))
190 {
191 /* Note: w don't update global info here because it is used only
192 internally to check if cursor is visible */
193 return MessageQueue->iCursorLevel;
194 }
195
196 /* Check if cursor is above window owned by this MessageQueue */
197 pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y);
198 if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue)
199 {
200 if (bShow)
201 {
202 /* Show the pointer */
203 GreMovePointer(hdcScreen, gpsi->ptCursor.x, gpsi->ptCursor.y);
204 TRACE("Showing pointer!\n");
205 }
206 else
207 {
208 /* Remove the pointer */
209 GreMovePointer(hdcScreen, -1, -1);
210 TRACE("Removing pointer!\n");
211 }
212
213 /* Update global info */
214 IntGetSysCursorInfo()->ShowingCursor = MessageQueue->iCursorLevel;
215 }
216
217 return MessageQueue->iCursorLevel;
218 }
219
220 DWORD FASTCALL
UserGetKeyState(DWORD dwKey)221 UserGetKeyState(DWORD dwKey)
222 {
223 DWORD dwRet = 0;
224 PTHREADINFO pti;
225 PUSER_MESSAGE_QUEUE MessageQueue;
226
227 pti = PsGetCurrentThreadWin32Thread();
228 MessageQueue = pti->MessageQueue;
229
230 if (dwKey < 0x100)
231 {
232 if (IS_KEY_DOWN(MessageQueue->afKeyState, dwKey))
233 dwRet |= 0xFF80; // If down, windows returns 0xFF80.
234 if (IS_KEY_LOCKED(MessageQueue->afKeyState, dwKey))
235 dwRet |= 0x1;
236 }
237 else
238 {
239 EngSetLastError(ERROR_INVALID_PARAMETER);
240 }
241 return dwRet;
242 }
243
244 /* change the input key state for a given key */
245 static VOID
UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue,WORD wVk,BOOL bIsDown)246 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue, WORD wVk, BOOL bIsDown)
247 {
248 TRACE("UpdateKeyState wVk: %u, bIsDown: %d\n", wVk, bIsDown);
249
250 if (bIsDown)
251 {
252 /* If it's first key down event, xor lock bit */
253 if (!IS_KEY_DOWN(MessageQueue->afKeyState, wVk))
254 SET_KEY_LOCKED(MessageQueue->afKeyState, wVk, !IS_KEY_LOCKED(MessageQueue->afKeyState, wVk));
255
256 SET_KEY_DOWN(MessageQueue->afKeyState, wVk, TRUE);
257 MessageQueue->afKeyRecentDown[wVk / 8] |= (1 << (wVk % 8));
258 }
259 else
260 SET_KEY_DOWN(MessageQueue->afKeyState, wVk, FALSE);
261 }
262
263 /* update the input key state for a keyboard message */
264 static VOID
UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue,MSG * msg)265 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue, MSG* msg)
266 {
267 UCHAR key;
268 BOOL down = FALSE;
269
270 TRACE("UpdateKeyStateFromMsg message:%u\n", msg->message);
271
272 switch (msg->message)
273 {
274 case WM_LBUTTONDOWN:
275 down = TRUE;
276 /* fall through */
277 case WM_LBUTTONUP:
278 UpdateKeyState(MessageQueue, VK_LBUTTON, down);
279 break;
280 case WM_MBUTTONDOWN:
281 down = TRUE;
282 /* fall through */
283 case WM_MBUTTONUP:
284 UpdateKeyState(MessageQueue, VK_MBUTTON, down);
285 break;
286 case WM_RBUTTONDOWN:
287 down = TRUE;
288 /* fall through */
289 case WM_RBUTTONUP:
290 UpdateKeyState(MessageQueue, VK_RBUTTON, down);
291 break;
292 case WM_XBUTTONDOWN:
293 down = TRUE;
294 /* fall through */
295 case WM_XBUTTONUP:
296 if (msg->wParam == XBUTTON1)
297 UpdateKeyState(MessageQueue, VK_XBUTTON1, down);
298 else if (msg->wParam == XBUTTON2)
299 UpdateKeyState(MessageQueue, VK_XBUTTON2, down);
300 break;
301 case WM_KEYDOWN:
302 case WM_SYSKEYDOWN:
303 down = TRUE;
304 /* fall through */
305 case WM_KEYUP:
306 case WM_SYSKEYUP:
307 key = (UCHAR)msg->wParam;
308 UpdateKeyState(MessageQueue, key, down);
309 switch(key)
310 {
311 case VK_LCONTROL:
312 case VK_RCONTROL:
313 down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LCONTROL) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RCONTROL);
314 UpdateKeyState(MessageQueue, VK_CONTROL, down);
315 break;
316 case VK_LMENU:
317 case VK_RMENU:
318 down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LMENU) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RMENU);
319 UpdateKeyState(MessageQueue, VK_MENU, down);
320 break;
321 case VK_LSHIFT:
322 case VK_RSHIFT:
323 down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LSHIFT) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RSHIFT);
324 UpdateKeyState(MessageQueue, VK_SHIFT, down);
325 break;
326 }
327 break;
328 }
329 }
330
331 /*
332 Get down key states from the queue of prior processed input message key states.
333
334 This fixes the left button dragging on the desktop and release sticking outline issue.
335 USB Tablet pointer seems to stick the most and leaves the box outline displayed.
336 */
337 WPARAM FASTCALL
MsqGetDownKeyState(PUSER_MESSAGE_QUEUE MessageQueue)338 MsqGetDownKeyState(PUSER_MESSAGE_QUEUE MessageQueue)
339 {
340 WPARAM ret = 0;
341
342 if (gspv.bMouseBtnSwap)
343 {
344 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_RBUTTON)) ret |= MK_LBUTTON;
345 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_LBUTTON)) ret |= MK_RBUTTON;
346 }
347 else
348 {
349 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_LBUTTON)) ret |= MK_LBUTTON;
350 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_RBUTTON)) ret |= MK_RBUTTON;
351 }
352
353 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_MBUTTON)) ret |= MK_MBUTTON;
354 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_SHIFT)) ret |= MK_SHIFT;
355 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_CONTROL)) ret |= MK_CONTROL;
356 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_XBUTTON1)) ret |= MK_XBUTTON1;
357 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_XBUTTON2)) ret |= MK_XBUTTON2;
358 return ret;
359 }
360
361 HANDLE FASTCALL
IntMsqSetWakeMask(DWORD WakeMask)362 IntMsqSetWakeMask(DWORD WakeMask)
363 {
364 PTHREADINFO Win32Thread;
365 HANDLE MessageEventHandle;
366 DWORD dwFlags = HIWORD(WakeMask);
367
368 Win32Thread = PsGetCurrentThreadWin32Thread();
369 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
370 return 0;
371
372 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
373 MessageEventHandle = Win32Thread->hEventQueueClient;
374
375 if (Win32Thread->pcti)
376 {
377 if ( (Win32Thread->pcti->fsChangeBits & LOWORD(WakeMask)) ||
378 ( (dwFlags & MWMO_INPUTAVAILABLE) && (Win32Thread->pcti->fsWakeBits & LOWORD(WakeMask)) ) )
379 {
380 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread->pcti->fsChangeBits, Win32Thread->pcti->fsWakeBits, WakeMask);
381 KeSetEvent(Win32Thread->pEventQueueServer, IO_NO_INCREMENT, FALSE); // Wake it up!
382 return MessageEventHandle;
383 }
384 }
385
386 IdlePing();
387
388 return MessageEventHandle;
389 }
390
391 BOOL FASTCALL
IntMsqClearWakeMask(VOID)392 IntMsqClearWakeMask(VOID)
393 {
394 PTHREADINFO Win32Thread;
395
396 Win32Thread = PsGetCurrentThreadWin32Thread();
397 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
398 return FALSE;
399 // Very hacky, but that is what they do.
400 Win32Thread->pcti->fsWakeBits = 0;
401
402 IdlePong();
403
404 return TRUE;
405 }
406
407 /*
408 Due to the uncertainty of knowing what was set in our multilevel message queue,
409 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
410 I think this is the best solution... (jt) */
411 VOID FASTCALL
MsqWakeQueue(PTHREADINFO pti,DWORD MessageBits,BOOL KeyEvent)412 MsqWakeQueue(PTHREADINFO pti, DWORD MessageBits, BOOL KeyEvent)
413 {
414 PUSER_MESSAGE_QUEUE Queue;
415
416 Queue = pti->MessageQueue;
417
418 if (Queue->QF_flags & QF_INDESTROY)
419 {
420 ERR("This Message Queue is in Destroy!\n");
421 }
422 pti->pcti->fsWakeBits |= MessageBits;
423 pti->pcti->fsChangeBits |= MessageBits;
424
425 // Start bit accounting to help clear the main set of bits.
426 if (MessageBits & QS_KEY)
427 {
428 pti->nCntsQBits[QSRosKey]++;
429 }
430 if (MessageBits & QS_MOUSE)
431 {
432 if (MessageBits & QS_MOUSEMOVE) pti->nCntsQBits[QSRosMouseMove]++;
433 if (MessageBits & QS_MOUSEBUTTON) pti->nCntsQBits[QSRosMouseButton]++;
434 }
435 if (MessageBits & QS_POSTMESSAGE) pti->nCntsQBits[QSRosPostMessage]++;
436 if (MessageBits & QS_SENDMESSAGE) pti->nCntsQBits[QSRosSendMessage]++;
437 if (MessageBits & QS_HOTKEY) pti->nCntsQBits[QSRosHotKey]++;
438 if (MessageBits & QS_EVENT) pti->nCntsQBits[QSRosEvent]++;
439
440 if (KeyEvent)
441 KeSetEvent(pti->pEventQueueServer, IO_NO_INCREMENT, FALSE);
442 }
443
444 VOID FASTCALL
ClearMsgBitsMask(PTHREADINFO pti,UINT MessageBits)445 ClearMsgBitsMask(PTHREADINFO pti, UINT MessageBits)
446 {
447 UINT ClrMask = 0;
448
449 if (MessageBits & QS_KEY)
450 {
451 if (--pti->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY;
452 }
453 if (MessageBits & QS_MOUSEMOVE)
454 { // Account for tracking mouse moves..
455 if (pti->nCntsQBits[QSRosMouseMove])
456 {
457 pti->nCntsQBits[QSRosMouseMove] = 0; // Throttle down count. Up to > 3:1 entries are ignored.
458 ClrMask |= QS_MOUSEMOVE;
459 }
460 }
461 if (MessageBits & QS_MOUSEBUTTON)
462 {
463 if (--pti->nCntsQBits[QSRosMouseButton] == 0) ClrMask |= QS_MOUSEBUTTON;
464 }
465 if (MessageBits & QS_POSTMESSAGE)
466 {
467 if (--pti->nCntsQBits[QSRosPostMessage] == 0) ClrMask |= QS_POSTMESSAGE;
468 }
469 if (MessageBits & QS_TIMER) // ReactOS hard coded.
470 { // Handle timer bits here.
471 if ( pti->cTimersReady )
472 {
473 if (--pti->cTimersReady == 0) ClrMask |= QS_TIMER;
474 }
475 }
476 if (MessageBits & QS_PAINT) // ReactOS hard coded.
477 { // Handle paint bits here.
478 if ( pti->cPaintsReady )
479 {
480 if (--pti->cPaintsReady == 0) ClrMask |= QS_PAINT;
481 }
482 }
483 if (MessageBits & QS_SENDMESSAGE)
484 {
485 if (--pti->nCntsQBits[QSRosSendMessage] == 0) ClrMask |= QS_SENDMESSAGE;
486 }
487 if (MessageBits & QS_HOTKEY)
488 {
489 if (--pti->nCntsQBits[QSRosHotKey] == 0) ClrMask |= QS_HOTKEY;
490 }
491 if (MessageBits & QS_EVENT)
492 {
493 if (--pti->nCntsQBits[QSRosEvent] == 0) ClrMask |= QS_EVENT;
494 }
495
496 pti->pcti->fsWakeBits &= ~ClrMask;
497 pti->pcti->fsChangeBits &= ~ClrMask;
498 }
499
500 VOID FASTCALL
MsqIncPaintCountQueue(PTHREADINFO pti)501 MsqIncPaintCountQueue(PTHREADINFO pti)
502 {
503 pti->cPaintsReady++;
504 MsqWakeQueue(pti, QS_PAINT, TRUE);
505 }
506
507 VOID FASTCALL
MsqDecPaintCountQueue(PTHREADINFO pti)508 MsqDecPaintCountQueue(PTHREADINFO pti)
509 {
510 ClearMsgBitsMask(pti, QS_PAINT);
511 }
512
513 /*
514 Post the move or update the message still pending to be processed.
515 Do not overload the queue with mouse move messages.
516 */
517 VOID FASTCALL
MsqPostMouseMove(PTHREADINFO pti,MSG * Msg,LONG_PTR ExtraInfo)518 MsqPostMouseMove(PTHREADINFO pti, MSG* Msg, LONG_PTR ExtraInfo)
519 {
520 PUSER_MESSAGE Message;
521 PLIST_ENTRY ListHead;
522 PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
523
524 ListHead = &MessageQueue->HardwareMessagesListHead;
525
526 // Do nothing if empty.
527 if (!IsListEmpty(ListHead->Flink))
528 {
529 // Look at the end of the list,
530 Message = CONTAINING_RECORD(ListHead->Blink, USER_MESSAGE, ListEntry);
531
532 // If the mouse move message is existing on the list,
533 if (Message->Msg.message == WM_MOUSEMOVE)
534 {
535 // Overwrite the message with updated data!
536 Message->Msg = *Msg;
537
538 MsqWakeQueue(pti, QS_MOUSEMOVE, TRUE);
539 return;
540 }
541 }
542
543 MsqPostMessage(pti, Msg, TRUE, QS_MOUSEMOVE, 0, ExtraInfo);
544 }
545
546 /*
547 Bring together the mouse move message.
548 Named "Coalesce" from Amine email ;^) (jt).
549 */
550 VOID FASTCALL
IntCoalesceMouseMove(PTHREADINFO pti)551 IntCoalesceMouseMove(PTHREADINFO pti)
552 {
553 MSG Msg;
554
555 // Force time stamp to update, keeping message time in sync.
556 if (gdwMouseMoveTimeStamp == 0)
557 {
558 gdwMouseMoveTimeStamp = EngGetTickCount32();
559 }
560
561 // Build mouse move message.
562 Msg.hwnd = NULL;
563 Msg.message = WM_MOUSEMOVE;
564 Msg.wParam = 0;
565 Msg.lParam = MAKELONG(gpsi->ptCursor.x, gpsi->ptCursor.y);
566 Msg.time = gdwMouseMoveTimeStamp;
567 Msg.pt = gpsi->ptCursor;
568
569 // Post the move.
570 MsqPostMouseMove(pti, &Msg, gdwMouseMoveExtraInfo);
571
572 // Zero the time stamp.
573 gdwMouseMoveTimeStamp = 0;
574
575 // Clear flag since the move was posted.
576 pti->MessageQueue->QF_flags &= ~QF_MOUSEMOVED;
577 }
578
579 VOID FASTCALL
co_MsqInsertMouseMessage(MSG * Msg,DWORD flags,ULONG_PTR dwExtraInfo,BOOL Hook)580 co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
581 {
582 MSLLHOOKSTRUCT MouseHookData;
583 // PDESKTOP pDesk;
584 PWND pwnd, pwndDesktop;
585 HDC hdcScreen;
586 PTHREADINFO pti;
587 PUSER_MESSAGE_QUEUE MessageQueue;
588 PSYSTEM_CURSORINFO CurInfo;
589
590 Msg->time = EngGetTickCount32();
591
592 MouseHookData.pt.x = LOWORD(Msg->lParam);
593 MouseHookData.pt.y = HIWORD(Msg->lParam);
594 switch (Msg->message)
595 {
596 case WM_MOUSEWHEEL:
597 MouseHookData.mouseData = MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg->wParam));
598 break;
599 case WM_XBUTTONDOWN:
600 case WM_XBUTTONUP:
601 case WM_XBUTTONDBLCLK:
602 case WM_NCXBUTTONDOWN:
603 case WM_NCXBUTTONUP:
604 case WM_NCXBUTTONDBLCLK:
605 MouseHookData.mouseData = MAKELONG(0, HIWORD(Msg->wParam));
606 break;
607 default:
608 MouseHookData.mouseData = 0;
609 break;
610 }
611
612 MouseHookData.flags = flags; // LLMHF_INJECTED
613 MouseHookData.time = Msg->time;
614 MouseHookData.dwExtraInfo = dwExtraInfo;
615
616 /* If the hook procedure returned non zero, dont send the message */
617 if (Hook)
618 {
619 if (co_HOOK_CallHooks(WH_MOUSE_LL, HC_ACTION, Msg->message, (LPARAM) &MouseHookData))
620 return;
621 }
622
623 /* Get the desktop window */
624 pwndDesktop = UserGetDesktopWindow();
625 if (!pwndDesktop) return;
626 // pDesk = pwndDesktop->head.rpdesk;
627
628 /* Check if the mouse is captured */
629 Msg->hwnd = IntGetCaptureWindow();
630 if (Msg->hwnd != NULL)
631 {
632 pwnd = UserGetWindowObject(Msg->hwnd);
633 }
634 else
635 {
636 pwnd = IntTopLevelWindowFromPoint(Msg->pt.x, Msg->pt.y);
637 if (pwnd) Msg->hwnd = UserHMGetHandle(pwnd);
638 }
639
640 hdcScreen = IntGetScreenDC();
641 CurInfo = IntGetSysCursorInfo();
642
643 /* Check if we found a window */
644 if (Msg->hwnd != NULL && pwnd != NULL)
645 {
646 pti = pwnd->head.pti;
647 MessageQueue = pti->MessageQueue;
648
649 if (MessageQueue->QF_flags & QF_INDESTROY)
650 {
651 ERR("Mouse is over a Window with a Dead Message Queue!\n");
652 return;
653 }
654
655 // Check to see if this is attached.
656 if ( pti != MessageQueue->ptiMouse &&
657 MessageQueue->cThreads > 1 )
658 {
659 // Set the send pti to the message queue mouse pti.
660 pti = MessageQueue->ptiMouse;
661 }
662
663 if (Msg->message == WM_MOUSEMOVE)
664 {
665 /* Check if cursor should be visible */
666 if(hdcScreen &&
667 MessageQueue->CursorObject &&
668 MessageQueue->iCursorLevel >= 0)
669 {
670 /* Check if shape has changed */
671 if(CurInfo->CurrentCursorObject != MessageQueue->CursorObject)
672 {
673 /* Call GDI to set the new screen cursor */
674 GreSetPointerShape(hdcScreen,
675 MessageQueue->CursorObject->hbmAlpha ?
676 NULL : MessageQueue->CursorObject->hbmMask,
677 MessageQueue->CursorObject->hbmAlpha ?
678 MessageQueue->CursorObject->hbmAlpha : MessageQueue->CursorObject->hbmColor,
679 MessageQueue->CursorObject->xHotspot,
680 MessageQueue->CursorObject->yHotspot,
681 gpsi->ptCursor.x,
682 gpsi->ptCursor.y,
683 MessageQueue->CursorObject->hbmAlpha ? SPS_ALPHA : 0);
684
685 } else
686 GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
687 }
688 /* Check if we have to hide cursor */
689 else if (CurInfo->ShowingCursor >= 0)
690 GreMovePointer(hdcScreen, -1, -1);
691
692 /* Update global cursor info */
693 CurInfo->ShowingCursor = MessageQueue->iCursorLevel;
694 CurInfo->CurrentCursorObject = MessageQueue->CursorObject;
695 gpqCursor = MessageQueue;
696
697 /* Mouse move is a special case */
698 MessageQueue->QF_flags |= QF_MOUSEMOVED;
699 gdwMouseMoveExtraInfo = dwExtraInfo;
700 gdwMouseMoveTimeStamp = Msg->time;
701 MsqWakeQueue(pti, QS_MOUSEMOVE, TRUE);
702 }
703 else
704 {
705 if (!IntGetCaptureWindow())
706 {
707 // ERR("ptiLastInput is set\n");
708 // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground.
709 // Find all the Move Mouse calls and fix mouse set active focus issues......
710 }
711
712 // Post mouse move before posting mouse buttons, keep it in sync.
713 if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED)
714 {
715 IntCoalesceMouseMove(pti);
716 }
717
718 TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd));
719 MsqPostMessage(pti, Msg, TRUE, QS_MOUSEBUTTON, 0, dwExtraInfo);
720 }
721 }
722 else if (hdcScreen)
723 {
724 /* always show cursor on background; FIXME: set default pointer */
725 GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
726 CurInfo->ShowingCursor = 0;
727 }
728 }
729
730 PUSER_MESSAGE FASTCALL
MsqCreateMessage(LPMSG Msg)731 MsqCreateMessage(LPMSG Msg)
732 {
733 PUSER_MESSAGE Message;
734
735 Message = ExAllocateFromPagedLookasideList(pgMessageLookasideList);
736 if (!Message)
737 {
738 return NULL;
739 }
740
741 RtlZeroMemory(Message, sizeof(*Message));
742 RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG));
743 PostMsgCount++;
744 return Message;
745 }
746
747 VOID FASTCALL
MsqDestroyMessage(PUSER_MESSAGE Message)748 MsqDestroyMessage(PUSER_MESSAGE Message)
749 {
750 TRACE("Post Destroy %d\n",PostMsgCount);
751 if (Message->pti == NULL)
752 {
753 ERR("Double Free Message\n");
754 return;
755 }
756 RemoveEntryList(&Message->ListEntry);
757 Message->pti = NULL;
758 ExFreeToPagedLookasideList(pgMessageLookasideList, Message);
759 PostMsgCount--;
760 }
761
762 PUSER_SENT_MESSAGE FASTCALL
AllocateUserMessage(BOOL KEvent)763 AllocateUserMessage(BOOL KEvent)
764 {
765 PUSER_SENT_MESSAGE Message;
766
767 if(!(Message = ExAllocateFromPagedLookasideList(pgSendMsgLookasideList)))
768 {
769 ERR("AllocateUserMessage(): Not enough memory to allocate a message\n");
770 return NULL;
771 }
772 RtlZeroMemory(Message, sizeof(USER_SENT_MESSAGE));
773
774 if (KEvent)
775 {
776 Message->pkCompletionEvent = &Message->CompletionEvent;
777
778 KeInitializeEvent(Message->pkCompletionEvent, NotificationEvent, FALSE);
779 }
780 SendMsgCount++;
781 TRACE("AUM pti %p msg %p\n",PsGetCurrentThreadWin32Thread(),Message);
782 return Message;
783 }
784
785 VOID FASTCALL
FreeUserMessage(PUSER_SENT_MESSAGE Message)786 FreeUserMessage(PUSER_SENT_MESSAGE Message)
787 {
788 Message->pkCompletionEvent = NULL;
789
790 /* Remove it from the list */
791 RemoveEntryList(&Message->ListEntry);
792
793 ExFreeToPagedLookasideList(pgSendMsgLookasideList, Message);
794 SendMsgCount--;
795 }
796
797 VOID APIENTRY
MsqRemoveWindowMessagesFromQueue(PWND Window)798 MsqRemoveWindowMessagesFromQueue(PWND Window)
799 {
800 PTHREADINFO pti;
801 PUSER_SENT_MESSAGE SentMessage;
802 PUSER_MESSAGE PostedMessage;
803 PLIST_ENTRY CurrentEntry, ListHead;
804
805 ASSERT(Window);
806
807 pti = Window->head.pti;
808
809 /* remove the posted messages for this window */
810 CurrentEntry = pti->PostedMessagesListHead.Flink;
811 ListHead = &pti->PostedMessagesListHead;
812 while (CurrentEntry != ListHead)
813 {
814 PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
815
816 if (PostedMessage->Msg.hwnd == UserHMGetHandle(Window))
817 {
818 if (PostedMessage->Msg.message == WM_QUIT && pti->QuitPosted == 0)
819 {
820 pti->QuitPosted = 1;
821 pti->exitCode = PostedMessage->Msg.wParam;
822 }
823 ClearMsgBitsMask(pti, PostedMessage->QS_Flags);
824 MsqDestroyMessage(PostedMessage);
825 CurrentEntry = pti->PostedMessagesListHead.Flink;
826 }
827 else
828 {
829 CurrentEntry = CurrentEntry->Flink;
830 }
831 }
832
833 /* remove the sent messages for this window */
834 CurrentEntry = pti->SentMessagesListHead.Flink;
835 ListHead = &pti->SentMessagesListHead;
836 while (CurrentEntry != ListHead)
837 {
838 SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
839
840 if(SentMessage->Msg.hwnd == UserHMGetHandle(Window))
841 {
842 ERR("Remove Window Messages %p From Sent Queue\n",SentMessage);
843 #if 0 // Should mark these as invalid and allow the rest clean up, so far no harm by just commenting out. See CORE-9210.
844 ClearMsgBitsMask(pti, SentMessage->QS_Flags);
845
846 /* wake the sender's thread */
847 if (SentMessage->pkCompletionEvent != NULL)
848 {
849 KeSetEvent(SentMessage->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
850 }
851
852 if (SentMessage->HasPackedLParam)
853 {
854 if (SentMessage->Msg.lParam)
855 ExFreePool((PVOID)SentMessage->Msg.lParam);
856 }
857
858 /* free the message */
859 FreeUserMessage(SentMessage);
860
861 CurrentEntry = pti->SentMessagesListHead.Flink;
862 #endif
863 CurrentEntry = CurrentEntry->Flink;
864 }
865 else
866 {
867 CurrentEntry = CurrentEntry->Flink;
868 }
869 }
870 }
871
872 BOOLEAN FASTCALL
co_MsqDispatchOneSentMessage(_In_ PTHREADINFO pti)873 co_MsqDispatchOneSentMessage(
874 _In_ PTHREADINFO pti)
875 {
876 PUSER_SENT_MESSAGE SaveMsg, Message;
877 PLIST_ENTRY Entry;
878 BOOL Ret;
879 LRESULT Result = 0;
880
881 ASSERT(pti == PsGetCurrentThreadWin32Thread());
882
883 if (IsListEmpty(&pti->SentMessagesListHead))
884 {
885 return(FALSE);
886 }
887
888 /* remove it from the list of pending messages */
889 Entry = RemoveHeadList(&pti->SentMessagesListHead);
890 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
891
892 // Signal this message is being processed.
893 Message->flags |= SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE;
894
895 SaveMsg = pti->pusmCurrent;
896 pti->pusmCurrent = Message;
897
898 // Processing a message sent to it from another thread.
899 if ( ( Message->ptiSender && pti != Message->ptiSender) ||
900 ( Message->ptiCallBackSender && pti != Message->ptiCallBackSender ))
901 { // most likely, but, to be sure.
902 pti->pcti->CTI_flags |= CTI_INSENDMESSAGE; // Let the user know...
903 }
904
905 /* Now insert it to the global list of messages that can be removed Justin Case there's Trouble */
906 InsertTailList(&usmList, &Message->ListEntry);
907
908 ClearMsgBitsMask(pti, Message->QS_Flags);
909
910 if (Message->HookMessage == MSQ_ISHOOK)
911 { // Direct Hook Call processor
912 Result = co_CallHook( Message->Msg.message, // HookId
913 HandleToLong(Message->Msg.hwnd), // Code
914 Message->Msg.wParam,
915 Message->Msg.lParam);
916 }
917 else if(Message->HookMessage == MSQ_INJECTMODULE)
918 {
919 Result = IntLoadHookModule(Message->Msg.message,
920 (HHOOK)Message->Msg.lParam,
921 Message->Msg.wParam);
922 }
923 else if ((Message->CompletionCallback) &&
924 (Message->ptiCallBackSender == pti))
925 { /* Call the callback routine */
926 if (Message->QS_Flags & QS_SMRESULT)
927 {
928 co_IntCallSentMessageCallback(Message->CompletionCallback,
929 Message->Msg.hwnd,
930 Message->Msg.message,
931 Message->CompletionCallbackContext,
932 Message->lResult);
933 /* Set callback to NULL to prevent reentry */
934 Message->CompletionCallback = NULL;
935 }
936 else
937 {
938 /* The message has not been processed yet, reinsert it. */
939 RemoveEntryList(&Message->ListEntry);
940 InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry);
941 // List is occupied need to set the bit.
942 MsqWakeQueue(Message->ptiCallBackSender, QS_SENDMESSAGE, TRUE);
943 ERR("Callback Message not processed yet. Requeuing the message\n"); //// <---- Need to see if this happens.
944 Ret = FALSE;
945 goto Exit;
946 }
947 }
948 else
949 { /* Call the window procedure. */
950 Result = co_IntSendMessage( Message->Msg.hwnd,
951 Message->Msg.message,
952 Message->Msg.wParam,
953 Message->Msg.lParam);
954 }
955
956 /* If the message is a callback, insert it in the callback senders MessageQueue */
957 if (Message->CompletionCallback)
958 {
959 if (Message->ptiCallBackSender)
960 {
961 Message->lResult = Result;
962 Message->QS_Flags |= QS_SMRESULT;
963
964 /* insert it in the callers message queue */
965 RemoveEntryList(&Message->ListEntry);
966 InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry);
967 MsqWakeQueue(Message->ptiCallBackSender, QS_SENDMESSAGE, TRUE);
968 }
969 Ret = TRUE;
970 goto Exit;
971 }
972
973 // Retrieve the result from callback.
974 if (Message->QS_Flags & QS_SMRESULT)
975 {
976 Result = Message->lResult;
977 }
978
979 /* Let the sender know the result. */
980 Message->lResult = Result;
981
982 if (Message->HasPackedLParam)
983 {
984 if (Message->Msg.lParam)
985 ExFreePool((PVOID)Message->Msg.lParam);
986 }
987
988 // Clear busy signal.
989 Message->flags &= ~SMF_RECEIVERBUSY;
990
991 /* Notify the sender. */
992 if (Message->pkCompletionEvent != NULL)
993 {
994 KeSetEvent(Message->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
995 }
996
997 /* free the message */
998 if (Message->flags & SMF_RECEIVERFREE)
999 {
1000 TRACE("Receiver Freeing Message %p\n",Message);
1001 FreeUserMessage(Message);
1002 }
1003
1004 Ret = TRUE;
1005 Exit:
1006 /* do not hangup on the user if this is reentering */
1007 if (!SaveMsg) pti->pcti->CTI_flags &= ~CTI_INSENDMESSAGE;
1008 pti->pusmCurrent = SaveMsg;
1009
1010 return Ret;
1011 }
1012
1013 BOOL FASTCALL
co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,HWND hwnd,UINT Msg,WPARAM wParam,LPARAM lParam,SENDASYNCPROC CompletionCallback,ULONG_PTR CompletionCallbackContext,BOOL HasPackedLParam,INT HookMessage)1014 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,
1015 HWND hwnd,
1016 UINT Msg,
1017 WPARAM wParam,
1018 LPARAM lParam,
1019 SENDASYNCPROC CompletionCallback,
1020 ULONG_PTR CompletionCallbackContext,
1021 BOOL HasPackedLParam,
1022 INT HookMessage)
1023 {
1024 PTHREADINFO ptiSender;
1025 PUSER_SENT_MESSAGE Message;
1026
1027 if(!(Message = AllocateUserMessage(FALSE)))
1028 {
1029 ERR("MsqSendMessageAsync(): Not enough memory to allocate a message\n");
1030 return FALSE;
1031 }
1032
1033 ptiSender = PsGetCurrentThreadWin32Thread();
1034
1035 Message->Msg.hwnd = hwnd;
1036 Message->Msg.message = Msg;
1037 Message->Msg.wParam = wParam;
1038 Message->Msg.lParam = lParam;
1039 Message->pkCompletionEvent = NULL; // No event needed.
1040 Message->ptiReceiver = ptiReceiver;
1041 Message->ptiCallBackSender = ptiSender;
1042 Message->CompletionCallback = CompletionCallback;
1043 Message->CompletionCallbackContext = CompletionCallbackContext;
1044 Message->HookMessage = HookMessage;
1045 Message->HasPackedLParam = HasPackedLParam;
1046 Message->QS_Flags = QS_SENDMESSAGE;
1047 Message->flags = SMF_RECEIVERFREE;
1048
1049 InsertTailList(&ptiReceiver->SentMessagesListHead, &Message->ListEntry);
1050 MsqWakeQueue(ptiReceiver, QS_SENDMESSAGE, TRUE);
1051
1052 return TRUE;
1053 }
1054
1055 NTSTATUS FASTCALL
co_MsqSendMessage(PTHREADINFO ptirec,HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam,UINT uTimeout,BOOL Block,INT HookMessage,ULONG_PTR * uResult)1056 co_MsqSendMessage(PTHREADINFO ptirec,
1057 HWND Wnd,
1058 UINT Msg,
1059 WPARAM wParam,
1060 LPARAM lParam,
1061 UINT uTimeout,
1062 BOOL Block,
1063 INT HookMessage,
1064 ULONG_PTR *uResult)
1065 {
1066 PTHREADINFO pti;
1067 PUSER_SENT_MESSAGE SaveMsg, Message;
1068 NTSTATUS WaitStatus;
1069 LARGE_INTEGER Timeout;
1070 PLIST_ENTRY Entry;
1071 PWND pWnd;
1072 BOOLEAN SwapStateEnabled;
1073 LRESULT Result = 0; //// Result could be trashed. ////
1074
1075 pti = PsGetCurrentThreadWin32Thread();
1076 ASSERT(pti != ptirec);
1077 ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!!
1078
1079 /* Don't send from or to a dying thread */
1080 if (pti->TIF_flags & TIF_INCLEANUP || ptirec->TIF_flags & TIF_INCLEANUP)
1081 {
1082 // Unless we are dying and need to tell our parents.
1083 if (pti->TIF_flags & TIF_INCLEANUP && !(ptirec->TIF_flags & TIF_INCLEANUP))
1084 {
1085 // Parent notify is the big one. Fire and forget!
1086 TRACE("Send message from dying thread %u\n", Msg);
1087 co_MsqSendMessageAsync(ptirec, Wnd, Msg, wParam, lParam, NULL, 0, FALSE, HookMessage);
1088 }
1089 if (uResult) *uResult = -1;
1090 TRACE("MsqSM: Msg %u Current pti %lu or Rec pti %lu\n", Msg, pti->TIF_flags & TIF_INCLEANUP, ptirec->TIF_flags & TIF_INCLEANUP);
1091 return STATUS_UNSUCCESSFUL;
1092 }
1093
1094 if (IsThreadSuspended(ptirec))
1095 {
1096 ERR("Sending to Suspended Thread Msg %lx\n",Msg);
1097 if (uResult) *uResult = -1;
1098 return STATUS_UNSUCCESSFUL;
1099 }
1100
1101 // Should we do the same for No Wait?
1102 if ( HookMessage == MSQ_NORMAL )
1103 {
1104 pWnd = ValidateHwndNoErr(Wnd);
1105
1106 // These can not cross International Border lines!
1107 if ( pti->ppi != ptirec->ppi && pWnd )
1108 {
1109 switch(Msg)
1110 {
1111 // Handle the special case when working with password transfers across bordering processes.
1112 case EM_GETLINE:
1113 case EM_SETPASSWORDCHAR:
1114 case WM_GETTEXT:
1115 // Look for edit controls setup for passwords.
1116 if ( gpsi->atomSysClass[ICLS_EDIT] == pWnd->pcls->atomClassName && // Use atomNVClassName.
1117 pWnd->style & ES_PASSWORD )
1118 {
1119 if (uResult) *uResult = -1;
1120 ERR("Running across the border without a passport!\n");
1121 EngSetLastError(ERROR_ACCESS_DENIED);
1122 return STATUS_UNSUCCESSFUL;
1123 }
1124 break;
1125 case WM_NOTIFY:
1126 if (uResult) *uResult = -1;
1127 ERR("Running across the border without a passport!\n");
1128 return STATUS_UNSUCCESSFUL;
1129 }
1130 }
1131
1132 // These can not cross State lines!
1133 if ( Msg == WM_CREATE || Msg == WM_NCCREATE )
1134 {
1135 if (uResult) *uResult = -1;
1136 ERR("Can not tell the other State we have Create!\n");
1137 return STATUS_UNSUCCESSFUL;
1138 }
1139 }
1140
1141 if(!(Message = AllocateUserMessage(TRUE)))
1142 {
1143 ERR("MsqSendMessage(): Not enough memory to allocate a message\n");
1144 if (uResult) *uResult = -1;
1145 return STATUS_INSUFFICIENT_RESOURCES;
1146 }
1147
1148 Timeout.QuadPart = Int32x32To64(-10000,uTimeout); // Pass SMTO test with a TO of 0x80000000.
1149 TRACE("Timeout val %lld\n",Timeout.QuadPart);
1150
1151 Message->Msg.hwnd = Wnd;
1152 Message->Msg.message = Msg;
1153 Message->Msg.wParam = wParam;
1154 Message->Msg.lParam = lParam;
1155 Message->ptiReceiver = ptirec;
1156 Message->ptiSender = pti;
1157 Message->HookMessage = HookMessage;
1158 Message->QS_Flags = QS_SENDMESSAGE;
1159
1160 SaveMsg = pti->pusmSent;
1161 pti->pusmSent = Message;
1162
1163 /* Queue it in the destination's message queue */
1164 InsertTailList(&ptirec->SentMessagesListHead, &Message->ListEntry);
1165
1166 MsqWakeQueue(ptirec, QS_SENDMESSAGE, TRUE);
1167
1168 // First time in, turn off swapping of the stack.
1169 if (pti->cEnterCount == 0)
1170 {
1171 SwapStateEnabled = KeSetKernelStackSwapEnable(FALSE);
1172 }
1173 pti->cEnterCount++;
1174
1175 if (Block)
1176 {
1177 PVOID WaitObjects[2];
1178
1179 WaitObjects[0] = Message->pkCompletionEvent; // Wait 0
1180 WaitObjects[1] = ptirec->pEThread; // Wait 1
1181
1182 UserLeaveCo();
1183
1184 WaitStatus = KeWaitForMultipleObjects( 2,
1185 WaitObjects,
1186 WaitAny,
1187 UserRequest,
1188 UserMode,
1189 FALSE,
1190 (uTimeout ? &Timeout : NULL),
1191 NULL );
1192
1193 UserEnterCo();
1194
1195 if (WaitStatus == STATUS_TIMEOUT)
1196 {
1197 /* Look up if the message has not yet dispatched, if so
1198 make sure it can't pass a result and it must not set the completion event anymore */
1199 Entry = ptirec->SentMessagesListHead.Flink;
1200 while (Entry != &ptirec->SentMessagesListHead)
1201 {
1202 if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message)
1203 {
1204 Message->pkCompletionEvent = NULL;
1205 RemoveEntryList(&Message->ListEntry);
1206 ClearMsgBitsMask(ptirec, Message->QS_Flags);
1207 InsertTailList(&usmList, &Message->ListEntry);
1208 break;
1209 }
1210 Entry = Entry->Flink;
1211 }
1212
1213 ERR("MsqSendMessage (blocked) timed out 1 Status %lx\n", WaitStatus);
1214 }
1215 // Receiving thread passed on and left us hanging with issues still pending.
1216 else if (WaitStatus == STATUS_WAIT_1)
1217 {
1218 ERR("Bk Receiving Thread woken up dead!\n");
1219 Message->flags |= SMF_RECEIVERDIED;
1220 }
1221
1222 while (co_MsqDispatchOneSentMessage(pti))
1223 ;
1224 }
1225 else
1226 {
1227 PVOID WaitObjects[3];
1228
1229 WaitObjects[0] = Message->pkCompletionEvent; // Wait 0
1230 WaitObjects[1] = pti->pEventQueueServer; // Wait 1
1231 WaitObjects[2] = ptirec->pEThread; // Wait 2
1232
1233 do
1234 {
1235 UserLeaveCo();
1236
1237 WaitStatus = KeWaitForMultipleObjects( 3,
1238 WaitObjects,
1239 WaitAny,
1240 UserRequest,
1241 UserMode,
1242 FALSE,
1243 (uTimeout ? &Timeout : NULL),
1244 NULL);
1245
1246 UserEnterCo();
1247
1248 if (WaitStatus == STATUS_TIMEOUT)
1249 {
1250 /* Look up if the message has not yet been dispatched, if so
1251 make sure it can't pass a result and it must not set the completion event anymore */
1252 Entry = ptirec->SentMessagesListHead.Flink;
1253 while (Entry != &ptirec->SentMessagesListHead)
1254 {
1255 if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message)
1256 {
1257 Message->pkCompletionEvent = NULL;
1258 RemoveEntryList(&Message->ListEntry);
1259 ClearMsgBitsMask(ptirec, Message->QS_Flags);
1260 InsertTailList(&usmList, &Message->ListEntry);
1261 break;
1262 }
1263 Entry = Entry->Flink;
1264 }
1265
1266 WARN("MsqSendMessage timed out 2 Status %lx\n", WaitStatus);
1267 break;
1268 }
1269 // Receiving thread passed on and left us hanging with issues still pending.
1270 else if (WaitStatus == STATUS_WAIT_2)
1271 {
1272 ERR("NB Receiving Thread woken up dead!\n");
1273 Message->flags |= SMF_RECEIVERDIED;
1274 break;
1275 }
1276
1277 if (WaitStatus == STATUS_USER_APC) break;
1278
1279 while (co_MsqDispatchOneSentMessage(pti))
1280 ;
1281 } while (WaitStatus == STATUS_WAIT_1);
1282 }
1283
1284 // Count is nil, restore swapping of the stack.
1285 if (--pti->cEnterCount == 0 )
1286 {
1287 KeSetKernelStackSwapEnable(SwapStateEnabled);
1288 }
1289
1290 // Handle User APC
1291 if (WaitStatus == STATUS_USER_APC)
1292 {
1293 // The current thread is dying!
1294 TRACE("User APC\n");
1295
1296 // The Message will be on the Trouble list until Thread cleanup.
1297 Message->flags |= SMF_SENDERDIED;
1298
1299 co_IntDeliverUserAPC();
1300 ERR("User APC Returned\n"); // Should not see this message.
1301 }
1302
1303 // Force this thread to wake up for the next go around.
1304 KeSetEvent(pti->pEventQueueServer, IO_NO_INCREMENT, FALSE);
1305
1306 Result = Message->lResult;
1307
1308 // Determine whether this message is being processed or not.
1309 if ((Message->flags & (SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE)) != SMF_RECEIVEDMESSAGE)
1310 {
1311 Message->flags |= SMF_RECEIVERFREE;
1312 }
1313
1314 if (!(Message->flags & SMF_RECEIVERFREE))
1315 {
1316 TRACE("Sender Freeing Message %p ptirec %p bit %d list empty %d\n",Message,ptirec,!!(ptirec->pcti->fsChangeBits & QS_SENDMESSAGE),IsListEmpty(&ptirec->SentMessagesListHead));
1317 // Make it to this point, the message was received.
1318 FreeUserMessage(Message);
1319 }
1320
1321 pti->pusmSent = SaveMsg;
1322
1323 TRACE("MSM Allocation Count %d Status %lx Result %d\n",SendMsgCount,WaitStatus,Result);
1324
1325 if (WaitStatus != STATUS_TIMEOUT)
1326 {
1327 if (uResult)
1328 {
1329 *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : 0);
1330 }
1331 }
1332
1333 return WaitStatus;
1334 }
1335
1336 VOID FASTCALL
MsqPostMessage(PTHREADINFO pti,MSG * Msg,BOOLEAN HardwareMessage,DWORD MessageBits,DWORD dwQEvent,LONG_PTR ExtraInfo)1337 MsqPostMessage(PTHREADINFO pti,
1338 MSG* Msg,
1339 BOOLEAN HardwareMessage,
1340 DWORD MessageBits,
1341 DWORD dwQEvent,
1342 LONG_PTR ExtraInfo)
1343 {
1344 PUSER_MESSAGE Message;
1345 PUSER_MESSAGE_QUEUE MessageQueue;
1346
1347 MessageQueue = pti->MessageQueue;
1348
1349 if ((pti->TIF_flags & TIF_INCLEANUP) || (MessageQueue->QF_flags & QF_INDESTROY))
1350 {
1351 ERR("Post Msg; Thread or Q is Dead!\n");
1352 return;
1353 }
1354
1355 Message = MsqCreateMessage(Msg);
1356 if (!Message)
1357 return;
1358
1359 if (Msg->message == WM_HOTKEY)
1360 MessageBits |= QS_HOTKEY;
1361
1362 Message->dwQEvent = dwQEvent;
1363 Message->ExtraInfo = ExtraInfo;
1364 Message->QS_Flags = MessageBits;
1365 Message->pti = pti;
1366
1367 if (!HardwareMessage)
1368 {
1369 InsertTailList(&pti->PostedMessagesListHead, &Message->ListEntry);
1370 }
1371 else
1372 {
1373 InsertTailList(&MessageQueue->HardwareMessagesListHead, &Message->ListEntry);
1374 }
1375
1376 MsqWakeQueue(pti, MessageBits, TRUE);
1377 TRACE("Post Message %d\n", PostMsgCount);
1378 }
1379
1380 VOID FASTCALL
MsqPostQuitMessage(PTHREADINFO pti,ULONG ExitCode)1381 MsqPostQuitMessage(PTHREADINFO pti, ULONG ExitCode)
1382 {
1383 pti->QuitPosted = TRUE;
1384 pti->exitCode = ExitCode;
1385 MsqWakeQueue(pti, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE);
1386 }
1387
1388 /***********************************************************************
1389 * MsqSendParentNotify
1390 *
1391 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1392 * the window has the WS_EX_NOPARENTNOTIFY style.
1393 */
MsqSendParentNotify(PWND pwnd,WORD event,WORD idChild,POINT pt)1394 static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt )
1395 {
1396 PWND pwndDesktop = UserGetDesktopWindow();
1397
1398 /* pt has to be in the client coordinates of the parent window */
1399 pt.x += pwndDesktop->rcClient.left - pwnd->rcClient.left;
1400 pt.y += pwndDesktop->rcClient.top - pwnd->rcClient.top;
1401
1402 for (;;)
1403 {
1404 PWND pwndParent;
1405
1406 if (!(pwnd->style & WS_CHILD)) break;
1407 if (pwnd->ExStyle & WS_EX_NOPARENTNOTIFY) break;
1408 if (!(pwndParent = IntGetParent(pwnd))) break;
1409 if (pwndParent == pwndDesktop) break;
1410 pt.x += pwnd->rcClient.left - pwndParent->rcClient.left;
1411 pt.y += pwnd->rcClient.top - pwndParent->rcClient.top;
1412
1413 pwnd = pwndParent;
1414 co_IntSendMessage( UserHMGetHandle(pwnd), WM_PARENTNOTIFY,
1415 MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) );
1416 }
1417 }
1418
1419 VOID
1420 FASTCALL
IntTrackMouseMove(PWND pwndTrack,PDESKTOP pDesk,PMSG msg,USHORT hittest)1421 IntTrackMouseMove(PWND pwndTrack, PDESKTOP pDesk, PMSG msg, USHORT hittest)
1422 {
1423 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1424 // hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
1425
1426 if ( pDesk->spwndTrack != pwndTrack || // Change with tracking window or
1427 msg->message != WM_MOUSEMOVE || // Mouse click changes or
1428 pDesk->htEx != hittest) // Change in current hit test states.
1429 {
1430 TRACE("ITMM: Track Mouse Move!\n");
1431
1432 /* Handle only the changing window track and mouse move across a border. */
1433 if ( pDesk->spwndTrack != pwndTrack ||
1434 (pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT) )
1435 {
1436 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1437 pDesk->spwndTrack != pwndTrack,(pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT));
1438
1439 if ( pDesk->dwDTFlags & DF_TME_LEAVE )
1440 UserPostMessage( UserHMGetHandle(pDesk->spwndTrack),
1441 (pDesk->htEx != HTCLIENT) ? WM_NCMOUSELEAVE : WM_MOUSELEAVE,
1442 0, 0);
1443
1444 if ( pDesk->dwDTFlags & DF_TME_HOVER )
1445 IntKillTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE);
1446
1447 /* Clear the flags to sign a change. */
1448 pDesk->dwDTFlags &= ~(DF_TME_LEAVE|DF_TME_HOVER);
1449 }
1450 /* Set the Track window and hit test. */
1451 pDesk->spwndTrack = pwndTrack;
1452 pDesk->htEx = hittest;
1453 }
1454
1455 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1456 if ( pDesk->spwndTrack == pwndTrack &&
1457 ( msg->message != WM_MOUSEMOVE || !RECTL_bPointInRect(&pDesk->rcMouseHover, msg->pt.x, msg->pt.y)) &&
1458 pDesk->dwDTFlags & DF_TME_HOVER )
1459 {
1460 TRACE("ITMM: Reset Hover points!\n");
1461 // Restart timer for the hover period.
1462 IntSetTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM);
1463 // Reset desktop mouse hover from the system default hover rectangle.
1464 RECTL_vSetRect(&pDesk->rcMouseHover,
1465 msg->pt.x - gspv.iMouseHoverWidth / 2,
1466 msg->pt.y - gspv.iMouseHoverHeight / 2,
1467 msg->pt.x + gspv.iMouseHoverWidth / 2,
1468 msg->pt.y + gspv.iMouseHoverHeight / 2);
1469 }
1470 }
1471
co_IntProcessMouseMessage(MSG * msg,BOOL * RemoveMessages,BOOL * NotForUs,LONG_PTR ExtraInfo,UINT first,UINT last)1472 BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, BOOL* NotForUs, LONG_PTR ExtraInfo, UINT first, UINT last)
1473 {
1474 MSG clk_msg;
1475 POINT pt;
1476 UINT message;
1477 USHORT hittest;
1478 EVENTMSG event;
1479 MOUSEHOOKSTRUCT hook;
1480 BOOL eatMsg = FALSE;
1481
1482 PWND pwndMsg, pwndDesktop;
1483 PUSER_MESSAGE_QUEUE MessageQueue;
1484 PTHREADINFO pti;
1485 PSYSTEM_CURSORINFO CurInfo;
1486 PDESKTOP pDesk;
1487
1488 pti = PsGetCurrentThreadWin32Thread();
1489 pwndDesktop = UserGetDesktopWindow();
1490 MessageQueue = pti->MessageQueue;
1491 CurInfo = IntGetSysCursorInfo();
1492 pwndMsg = ValidateHwndNoErr(msg->hwnd);
1493 clk_msg = MessageQueue->msgDblClk;
1494 pDesk = pwndDesktop->head.rpdesk;
1495
1496 /* find the window to dispatch this mouse message to */
1497 if (MessageQueue->spwndCapture)
1498 {
1499 hittest = HTCLIENT;
1500 pwndMsg = MessageQueue->spwndCapture;
1501 }
1502 else
1503 {
1504 /*
1505 Start with null window. See wine win.c:test_mouse_input:WM_COMMAND tests.
1506 */
1507 pwndMsg = co_WinPosWindowFromPoint( NULL, &msg->pt, &hittest, FALSE);
1508 }
1509
1510 TRACE("Got mouse message for %p, hittest: 0x%x\n", msg->hwnd, hittest);
1511
1512 // Null window or not the same "Hardware" message queue.
1513 if (pwndMsg == NULL || pwndMsg->head.pti->MessageQueue != MessageQueue)
1514 {
1515 // Crossing a boundary, so set cursor. See default message queue cursor.
1516 IntSystemSetCursor(SYSTEMCUR(ARROW));
1517 /* Remove and ignore the message */
1518 *RemoveMessages = TRUE;
1519 return FALSE;
1520 }
1521
1522 // Check to see if this is attached,
1523 if ( pwndMsg->head.pti != pti && // window thread is not current,
1524 MessageQueue->cThreads > 1 ) // and is attached...
1525 {
1526 // This is not for us and we should leave so the other thread can check for messages!!!
1527 *NotForUs = TRUE;
1528 *RemoveMessages = FALSE;
1529 return FALSE;
1530 }
1531
1532 if ( MessageQueue == gpqCursor ) // Cursor must use the same Queue!
1533 {
1534 IntTrackMouseMove(pwndMsg, pDesk, msg, hittest);
1535 }
1536 else
1537 {
1538 WARN("Not the same cursor!\n");
1539 }
1540
1541 msg->hwnd = UserHMGetHandle(pwndMsg);
1542
1543 pt = msg->pt;
1544 message = msg->message;
1545
1546 /* Note: windows has no concept of a non-client wheel message */
1547 if (message != WM_MOUSEWHEEL)
1548 {
1549 if (hittest != HTCLIENT)
1550 {
1551 message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
1552 msg->wParam = hittest; // Caution! This might break wParam check in DblClk.
1553 }
1554 else
1555 {
1556 /* coordinates don't get translated while tracking a menu */
1557 /* FIXME: should differentiate popups and top-level menus */
1558 if (!(MessageQueue->MenuOwner))
1559 {
1560 pt.x += pwndDesktop->rcClient.left - pwndMsg->rcClient.left;
1561 pt.y += pwndDesktop->rcClient.top - pwndMsg->rcClient.top;
1562 }
1563 }
1564 }
1565 msg->lParam = MAKELONG( pt.x, pt.y );
1566
1567 /* translate double-clicks */
1568
1569 if ((msg->message == WM_LBUTTONDOWN) ||
1570 (msg->message == WM_RBUTTONDOWN) ||
1571 (msg->message == WM_MBUTTONDOWN) ||
1572 (msg->message == WM_XBUTTONDOWN))
1573 {
1574 BOOL update = *RemoveMessages;
1575
1576 /* translate double-clicks -
1577 * note that ...MOUSEMOVEs can slip in between
1578 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1579
1580 if ((MessageQueue->MenuOwner || MessageQueue->MoveSize) ||
1581 hittest != HTCLIENT ||
1582 (pwndMsg->pcls->style & CS_DBLCLKS))
1583 {
1584 if ((msg->message == clk_msg.message) &&
1585 (msg->hwnd == clk_msg.hwnd) &&
1586 // Only worry about XButton wParam.
1587 (msg->message != WM_XBUTTONDOWN || GET_XBUTTON_WPARAM(msg->wParam) == GET_XBUTTON_WPARAM(clk_msg.wParam)) &&
1588 ((msg->time - clk_msg.time) < (ULONG)gspv.iDblClickTime) &&
1589 (abs(msg->pt.x - clk_msg.pt.x) < UserGetSystemMetrics(SM_CXDOUBLECLK)/2) &&
1590 (abs(msg->pt.y - clk_msg.pt.y) < UserGetSystemMetrics(SM_CYDOUBLECLK)/2))
1591 {
1592 message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
1593 if (update)
1594 {
1595 MessageQueue->msgDblClk.message = 0; /* clear the double-click conditions */
1596 update = FALSE;
1597 }
1598 }
1599 }
1600
1601 if (!((first == 0 && last == 0) || (message >= first || message <= last)))
1602 {
1603 TRACE("Message out of range!!!\n");
1604 return FALSE;
1605 }
1606
1607 /* update static double-click conditions */
1608 if (update) MessageQueue->msgDblClk = *msg;
1609 }
1610 else
1611 {
1612 if (!((first == 0 && last == 0) || (message >= first || message <= last)))
1613 {
1614 TRACE("Message out of range!!!\n");
1615 return FALSE;
1616 }
1617
1618 // Update mouse move down keys.
1619 if (message == WM_MOUSEMOVE)
1620 {
1621 msg->wParam = MsqGetDownKeyState(MessageQueue);
1622 }
1623 }
1624
1625 if (gspv.bMouseClickLock)
1626 {
1627 BOOL IsClkLck = FALSE;
1628
1629 if(msg->message == WM_LBUTTONUP)
1630 {
1631 IsClkLck = ((msg->time - CurInfo->ClickLockTime) >= gspv.dwMouseClickLockTime);
1632 if (IsClkLck && (!CurInfo->ClickLockActive))
1633 {
1634 CurInfo->ClickLockActive = TRUE;
1635 }
1636 }
1637 else if (msg->message == WM_LBUTTONDOWN)
1638 {
1639 if (CurInfo->ClickLockActive)
1640 {
1641 IsClkLck = TRUE;
1642 CurInfo->ClickLockActive = FALSE;
1643 }
1644
1645 CurInfo->ClickLockTime = msg->time;
1646 }
1647
1648 if(IsClkLck)
1649 {
1650 /* Remove and ignore the message */
1651 *RemoveMessages = TRUE;
1652 TRACE("Remove and ignore the message\n");
1653 return FALSE;
1654 }
1655 }
1656
1657 if (pti->TIF_flags & TIF_MSGPOSCHANGED)
1658 {
1659 pti->TIF_flags &= ~TIF_MSGPOSCHANGED;
1660 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
1661 }
1662
1663 /* message is accepted now (but still get dropped) */
1664
1665 event.message = msg->message;
1666 event.time = msg->time;
1667 event.hwnd = msg->hwnd;
1668 event.paramL = msg->pt.x;
1669 event.paramH = msg->pt.y;
1670 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
1671
1672 hook.pt = msg->pt;
1673 hook.hwnd = msg->hwnd;
1674 hook.wHitTestCode = hittest;
1675 hook.dwExtraInfo = ExtraInfo;
1676 if (co_HOOK_CallHooks( WH_MOUSE, *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
1677 message, (LPARAM)&hook ))
1678 {
1679 hook.pt = msg->pt;
1680 hook.hwnd = msg->hwnd;
1681 hook.wHitTestCode = hittest;
1682 hook.dwExtraInfo = ExtraInfo;
1683 co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook );
1684
1685 ERR("WH_MOUSE dropped mouse message!\n");
1686
1687 /* Remove and skip message */
1688 *RemoveMessages = TRUE;
1689 return FALSE;
1690 }
1691
1692 if ((hittest == (USHORT)HTERROR) || (hittest == (USHORT)HTNOWHERE))
1693 {
1694 co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
1695
1696 /* Remove and skip message */
1697 *RemoveMessages = TRUE;
1698 return FALSE;
1699 }
1700
1701 if ((*RemoveMessages == FALSE) || MessageQueue->spwndCapture)
1702 {
1703 /* Accept the message */
1704 msg->message = message;
1705 return TRUE;
1706 }
1707
1708 if ((msg->message == WM_LBUTTONDOWN) ||
1709 (msg->message == WM_RBUTTONDOWN) ||
1710 (msg->message == WM_MBUTTONDOWN) ||
1711 (msg->message == WM_XBUTTONDOWN))
1712 {
1713 /* Send the WM_PARENTNOTIFY,
1714 * note that even for double/nonclient clicks
1715 * notification message is still WM_L/M/RBUTTONDOWN.
1716 */
1717 MsqSendParentNotify(pwndMsg, msg->message, 0, msg->pt );
1718
1719 /* Activate the window if needed */
1720
1721 if (pwndMsg != MessageQueue->spwndActive)
1722 {
1723 PWND pwndTop = pwndMsg;
1724 pwndTop = IntGetNonChildAncestor(pwndTop);
1725
1726 TRACE("Mouse pti %p pwndMsg pti %p pwndTop pti %p\n",MessageQueue->ptiMouse,pwndMsg->head.pti,pwndTop->head.pti);
1727
1728 if (pwndTop && pwndTop != pwndDesktop)
1729 {
1730 LONG ret = co_IntSendMessage( msg->hwnd,
1731 WM_MOUSEACTIVATE,
1732 (WPARAM)UserHMGetHandle(pwndTop),
1733 MAKELONG( hittest, msg->message));
1734 switch(ret)
1735 {
1736 case MA_NOACTIVATEANDEAT:
1737 eatMsg = TRUE;
1738 /* fall through */
1739 case MA_NOACTIVATE:
1740 break;
1741 case MA_ACTIVATEANDEAT:
1742 eatMsg = TRUE;
1743 /* fall through */
1744 case MA_ACTIVATE:
1745 case 0:
1746 if (!co_IntMouseActivateWindow( pwndTop )) eatMsg = TRUE;
1747 break;
1748 default:
1749 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret );
1750 break;
1751 }
1752 }
1753 }
1754 }
1755
1756 /* send the WM_SETCURSOR message */
1757
1758 /* Windows sends the normal mouse message as the message parameter
1759 in the WM_SETCURSOR message even if it's non-client mouse message */
1760 co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
1761
1762 msg->message = message;
1763 return !eatMsg;
1764 }
1765
co_IntProcessKeyboardMessage(MSG * Msg,BOOL * RemoveMessages)1766 BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
1767 {
1768 EVENTMSG Event;
1769 USER_REFERENCE_ENTRY Ref;
1770 PWND pWnd;
1771 UINT ImmRet;
1772 BOOL Ret = TRUE, bKeyUpDown = FALSE;
1773 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1774 const UINT uMsg = Msg->message;
1775
1776 if (uMsg == VK_PACKET)
1777 pti->wchInjected = HIWORD(Msg->wParam);
1778
1779 if (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN || uMsg == WM_KEYUP || uMsg == WM_SYSKEYUP)
1780 {
1781 bKeyUpDown = TRUE;
1782 switch (Msg->wParam)
1783 {
1784 case VK_LSHIFT: case VK_RSHIFT:
1785 Msg->wParam = VK_SHIFT;
1786 break;
1787 case VK_LCONTROL: case VK_RCONTROL:
1788 Msg->wParam = VK_CONTROL;
1789 break;
1790 case VK_LMENU: case VK_RMENU:
1791 Msg->wParam = VK_MENU;
1792 break;
1793 }
1794 }
1795
1796 pWnd = ValidateHwndNoErr(Msg->hwnd);
1797 if (pWnd) UserRefObjectCo(pWnd, &Ref);
1798
1799 Event.message = uMsg;
1800 Event.hwnd = Msg->hwnd;
1801 Event.time = Msg->time;
1802 Event.paramL = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8);
1803 Event.paramH = Msg->lParam & 0x7FFF;
1804 if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000;
1805 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
1806
1807 if (*RemoveMessages)
1808 {
1809 if ((uMsg == WM_KEYDOWN) &&
1810 (Msg->hwnd != IntGetDesktopWindow()))
1811 {
1812 /* Handle F1 key by sending out WM_HELP message */
1813 if (Msg->wParam == VK_F1)
1814 {
1815 UserPostMessage( Msg->hwnd, WM_KEYF1, 0, 0 );
1816 }
1817 else if (Msg->wParam >= VK_BROWSER_BACK &&
1818 Msg->wParam <= VK_LAUNCH_APP2)
1819 {
1820 /* FIXME: Process keystate */
1821 co_IntSendMessage(Msg->hwnd, WM_APPCOMMAND, (WPARAM)Msg->hwnd, MAKELPARAM(0, (FAPPCOMMAND_KEY | (Msg->wParam - VK_BROWSER_BACK + 1))));
1822 }
1823 }
1824 else if (uMsg == WM_KEYUP)
1825 {
1826 /* Handle VK_APPS key by posting a WM_CONTEXTMENU message */
1827 if (Msg->wParam == VK_APPS && pti->MessageQueue->MenuOwner == NULL)
1828 UserPostMessage( Msg->hwnd, WM_CONTEXTMENU, (WPARAM)Msg->hwnd, -1 );
1829 }
1830 }
1831
1832 //// Key Down!
1833 if (*RemoveMessages && uMsg == WM_SYSKEYDOWN)
1834 {
1835 if ( HIWORD(Msg->lParam) & KF_ALTDOWN )
1836 {
1837 if ( Msg->wParam == VK_ESCAPE || Msg->wParam == VK_TAB ) // Alt-Tab/ESC Alt-Shift-Tab/ESC
1838 {
1839 WPARAM wParamTmp;
1840
1841 wParamTmp = UserGetKeyState(VK_SHIFT) & 0x8000 ? SC_PREVWINDOW : SC_NEXTWINDOW;
1842 TRACE("Send WM_SYSCOMMAND Alt-Tab/ESC Alt-Shift-Tab/ESC\n");
1843 co_IntSendMessage( Msg->hwnd, WM_SYSCOMMAND, wParamTmp, Msg->wParam );
1844
1845 //// Keep looping.
1846 Ret = FALSE;
1847 //// Skip the rest.
1848 goto Exit;
1849 }
1850 }
1851 }
1852
1853 if (co_HOOK_CallHooks( WH_KEYBOARD,
1854 *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
1855 LOWORD(Msg->wParam),
1856 Msg->lParam))
1857 {
1858 /* skip this message */
1859 co_HOOK_CallHooks( WH_CBT,
1860 HCBT_KEYSKIPPED,
1861 LOWORD(Msg->wParam),
1862 Msg->lParam );
1863
1864 ERR("KeyboardMessage WH_KEYBOARD Call Hook return!\n");
1865
1866 *RemoveMessages = TRUE;
1867
1868 Ret = FALSE;
1869 }
1870
1871 if (pWnd && Ret && *RemoveMessages && bKeyUpDown && !(pti->TIF_flags & TIF_DISABLEIME))
1872 {
1873 ImmRet = IntImmProcessKey(pti->MessageQueue, pWnd, uMsg, Msg->wParam, Msg->lParam);
1874 if (ImmRet)
1875 {
1876 if ( ImmRet & (IPHK_HOTKEY|IPHK_SKIPTHISKEY) )
1877 {
1878 ImmRet = 0;
1879 }
1880 if ( ImmRet & IPHK_PROCESSBYIME )
1881 {
1882 Msg->wParam = VK_PROCESSKEY;
1883 }
1884 }
1885 }
1886 Exit:
1887 if (pWnd) UserDerefObjectCo(pWnd);
1888 return Ret;
1889 }
1890
co_IntProcessHardwareMessage(MSG * Msg,BOOL * RemoveMessages,BOOL * NotForUs,LONG_PTR ExtraInfo,UINT first,UINT last)1891 BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, BOOL* NotForUs, LONG_PTR ExtraInfo, UINT first, UINT last)
1892 {
1893 if ( IS_MOUSE_MESSAGE(Msg->message))
1894 {
1895 return co_IntProcessMouseMessage(Msg, RemoveMessages, NotForUs, ExtraInfo, first, last);
1896 }
1897 else if ( IS_KBD_MESSAGE(Msg->message))
1898 {
1899 return co_IntProcessKeyboardMessage(Msg, RemoveMessages);
1900 }
1901
1902 return TRUE;
1903 }
1904
1905 /* check whether a message filter contains at least one potential hardware message */
1906 static INT FASTCALL
filter_contains_hw_range(UINT first,UINT last)1907 filter_contains_hw_range( UINT first, UINT last )
1908 {
1909 /* hardware message ranges are (in numerical order):
1910 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1911 * WM_KEYFIRST .. WM_KEYLAST
1912 * WM_MOUSEFIRST .. WM_MOUSELAST
1913 */
1914 if (!last) --last;
1915 if (last < WM_NCMOUSEFIRST) return 0;
1916 if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0;
1917 if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0;
1918 if (first > WM_MOUSELAST) return 0;
1919 return 1;
1920 }
1921
1922 /* check whether message is in the range of mouse messages */
is_mouse_message(UINT message)1923 static inline BOOL is_mouse_message( UINT message )
1924 {
1925 return ( //( message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST ) || This seems to break tests...
1926 ( message >= WM_MOUSEFIRST && message <= WM_MOUSELAST ) ||
1927 ( message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK ) ||
1928 ( message >= WM_MBUTTONDOWN && message <= WM_MBUTTONDBLCLK ) ||
1929 ( message >= WM_LBUTTONDOWN && message <= WM_RBUTTONDBLCLK ) );
1930 }
1931
1932 BOOL APIENTRY
co_MsqPeekHardwareMessage(IN PTHREADINFO pti,IN BOOL Remove,IN PWND Window,IN UINT MsgFilterLow,IN UINT MsgFilterHigh,IN UINT QSflags,OUT MSG * pMsg)1933 co_MsqPeekHardwareMessage(IN PTHREADINFO pti,
1934 IN BOOL Remove,
1935 IN PWND Window,
1936 IN UINT MsgFilterLow,
1937 IN UINT MsgFilterHigh,
1938 IN UINT QSflags,
1939 OUT MSG* pMsg)
1940 {
1941 BOOL AcceptMessage, NotForUs;
1942 PUSER_MESSAGE CurrentMessage;
1943 PLIST_ENTRY ListHead;
1944 MSG msg;
1945 ULONG_PTR idSave;
1946 DWORD QS_Flags;
1947 LONG_PTR ExtraInfo;
1948 MSG clk_msg;
1949 BOOL Ret = FALSE;
1950 PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
1951
1952 if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE;
1953
1954 ListHead = MessageQueue->HardwareMessagesListHead.Flink;
1955
1956 if (IsListEmpty(ListHead)) return FALSE;
1957
1958 if (!MessageQueue->ptiSysLock)
1959 {
1960 MessageQueue->ptiSysLock = pti;
1961 pti->pcti->CTI_flags |= CTI_THREADSYSLOCK;
1962 }
1963
1964 if (MessageQueue->ptiSysLock != pti)
1965 {
1966 ERR("Thread Q is locked to ptiSysLock 0x%p pti 0x%p\n",MessageQueue->ptiSysLock,pti);
1967 return FALSE;
1968 }
1969
1970 while (ListHead != &MessageQueue->HardwareMessagesListHead)
1971 {
1972 CurrentMessage = CONTAINING_RECORD(ListHead, USER_MESSAGE, ListEntry);
1973 ListHead = ListHead->Flink;
1974
1975 if (MessageQueue->idSysPeek == (ULONG_PTR)CurrentMessage)
1976 {
1977 TRACE("Skip this message due to it is in play!\n");
1978 continue;
1979 }
1980 /*
1981 MSDN:
1982 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1983 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1984 3: handle to the window whose messages are to be retrieved.
1985 */
1986 if ( ( !Window || // 1
1987 ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
1988 ( Window != PWND_BOTTOM && UserHMGetHandle(Window) == CurrentMessage->Msg.hwnd ) || // 3
1989 ( is_mouse_message(CurrentMessage->Msg.message) ) ) && // Null window for anything mouse.
1990 ( CurrentMessage->QS_Flags & QSflags ) )
1991 {
1992 idSave = MessageQueue->idSysPeek;
1993 MessageQueue->idSysPeek = (ULONG_PTR)CurrentMessage;
1994
1995 msg = CurrentMessage->Msg;
1996 ExtraInfo = CurrentMessage->ExtraInfo;
1997 QS_Flags = CurrentMessage->QS_Flags;
1998 clk_msg = MessageQueue->msgDblClk;
1999
2000 NotForUs = FALSE;
2001
2002 UpdateKeyStateFromMsg(MessageQueue, &msg);
2003 AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, &NotForUs, ExtraInfo, MsgFilterLow, MsgFilterHigh);
2004
2005 if (!NotForUs && (MsgFilterLow != 0 || MsgFilterHigh != 0))
2006 {
2007 /* Don't return message if not in range */
2008 if (msg.message < MsgFilterLow || msg.message > MsgFilterHigh)
2009 {
2010 MessageQueue->msgDblClk = clk_msg;
2011 MessageQueue->idSysPeek = idSave;
2012 continue;
2013 }
2014 }
2015
2016 if (Remove)
2017 {
2018 if (CurrentMessage->pti != NULL && (MessageQueue->idSysPeek == (ULONG_PTR)CurrentMessage))
2019 {
2020 MsqDestroyMessage(CurrentMessage);
2021 }
2022 ClearMsgBitsMask(pti, QS_Flags);
2023 }
2024
2025 MessageQueue->idSysPeek = idSave;
2026
2027 if (NotForUs)
2028 {
2029 Ret = FALSE;
2030 break;
2031 }
2032
2033 if (AcceptMessage)
2034 {
2035 *pMsg = msg;
2036 // Fix all but one wine win:test_GetMessagePos WM_TIMER tests. See PostTimerMessages.
2037 if (!RtlEqualMemory(&pti->ptLast, &msg.pt, sizeof(POINT)))
2038 {
2039 pti->TIF_flags |= TIF_MSGPOSCHANGED;
2040 }
2041 pti->timeLast = msg.time;
2042 pti->ptLast = msg.pt;
2043 MessageQueue->ExtraInfo = ExtraInfo;
2044 Ret = TRUE;
2045 break;
2046 }
2047 }
2048 }
2049
2050 MessageQueue->ptiSysLock = NULL;
2051 pti->pcti->CTI_flags &= ~CTI_THREADSYSLOCK;
2052 return Ret;
2053 }
2054
2055 BOOLEAN APIENTRY
MsqPeekMessage(IN PTHREADINFO pti,IN BOOLEAN Remove,IN PWND Window,IN UINT MsgFilterLow,IN UINT MsgFilterHigh,IN UINT QSflags,OUT LONG_PTR * ExtraInfo,OUT DWORD * dwQEvent,OUT PMSG Message)2056 MsqPeekMessage(IN PTHREADINFO pti,
2057 IN BOOLEAN Remove,
2058 IN PWND Window,
2059 IN UINT MsgFilterLow,
2060 IN UINT MsgFilterHigh,
2061 IN UINT QSflags,
2062 OUT LONG_PTR *ExtraInfo,
2063 OUT DWORD *dwQEvent,
2064 OUT PMSG Message)
2065 {
2066 PUSER_MESSAGE CurrentMessage;
2067 PLIST_ENTRY ListHead;
2068 DWORD QS_Flags;
2069 BOOL Ret = FALSE;
2070
2071 ListHead = pti->PostedMessagesListHead.Flink;
2072
2073 if (IsListEmpty(ListHead)) return FALSE;
2074
2075 while(ListHead != &pti->PostedMessagesListHead)
2076 {
2077 CurrentMessage = CONTAINING_RECORD(ListHead, USER_MESSAGE, ListEntry);
2078 ListHead = ListHead->Flink;
2079 /*
2080 MSDN:
2081 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
2082 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
2083 3: handle to the window whose messages are to be retrieved.
2084 */
2085 if ( ( !Window || // 1
2086 ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
2087 ( Window != PWND_BOTTOM && UserHMGetHandle(Window) == CurrentMessage->Msg.hwnd ) ) && // 3
2088 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
2089 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
2090 {
2091 *Message = CurrentMessage->Msg;
2092 *ExtraInfo = CurrentMessage->ExtraInfo;
2093 QS_Flags = CurrentMessage->QS_Flags;
2094 if (dwQEvent) *dwQEvent = CurrentMessage->dwQEvent;
2095
2096 if (Remove)
2097 {
2098 if (CurrentMessage->pti != NULL)
2099 {
2100 MsqDestroyMessage(CurrentMessage);
2101 }
2102 ClearMsgBitsMask(pti, QS_Flags);
2103 }
2104 Ret = TRUE;
2105 break;
2106 }
2107 }
2108
2109 return Ret;
2110 }
2111
2112 NTSTATUS FASTCALL
co_MsqWaitForNewMessages(PTHREADINFO pti,PWND WndFilter,UINT MsgFilterMin,UINT MsgFilterMax)2113 co_MsqWaitForNewMessages(PTHREADINFO pti, PWND WndFilter,
2114 UINT MsgFilterMin, UINT MsgFilterMax)
2115 {
2116 NTSTATUS ret = STATUS_SUCCESS;
2117
2118 // Post mouse moves before waiting for messages.
2119 if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED)
2120 {
2121 IntCoalesceMouseMove(pti);
2122 }
2123
2124 UserLeaveCo();
2125
2126 ZwYieldExecution(); // Let someone else run!
2127
2128 ret = KeWaitForSingleObject( pti->pEventQueueServer,
2129 UserRequest,
2130 UserMode,
2131 FALSE,
2132 NULL );
2133 UserEnterCo();
2134 if ( ret == STATUS_USER_APC )
2135 {
2136 TRACE("MWFNW User APC\n");
2137 co_IntDeliverUserAPC();
2138 }
2139 return ret;
2140 }
2141
2142 BOOL FASTCALL
MsqIsHung(PTHREADINFO pti,DWORD TimeOut)2143 MsqIsHung(PTHREADINFO pti, DWORD TimeOut)
2144 {
2145 DWORD dwTimeStamp = EngGetTickCount32();
2146 if (dwTimeStamp - pti->pcti->timeLastRead > TimeOut &&
2147 !(pti->pcti->fsWakeMask & QS_INPUT) &&
2148 !PsGetThreadFreezeCount(pti->pEThread) &&
2149 !(pti->ppi->W32PF_flags & W32PF_APPSTARTING))
2150 {
2151 TRACE("\nMsqIsHung(pti %p, TimeOut %lu)\n"
2152 "pEThread %p, ThreadsProcess %p, ImageFileName '%s'\n"
2153 "dwTimeStamp = %lu\n"
2154 "pti->pcti->timeLastRead = %lu\n"
2155 "pti->timeLast = %lu\n"
2156 "PsGetThreadFreezeCount(pti->pEThread) = %lu\n",
2157 pti, TimeOut,
2158 pti->pEThread,
2159 pti->pEThread ? pti->pEThread->ThreadsProcess : NULL,
2160 (pti->pEThread && pti->pEThread->ThreadsProcess)
2161 ? pti->pEThread->ThreadsProcess->ImageFileName : "(None)",
2162 dwTimeStamp,
2163 pti->pcti->timeLastRead,
2164 pti->timeLast,
2165 PsGetThreadFreezeCount(pti->pEThread));
2166
2167 return TRUE;
2168 }
2169
2170 return FALSE;
2171 }
2172
2173 BOOL FASTCALL
IsThreadSuspended(PTHREADINFO pti)2174 IsThreadSuspended(PTHREADINFO pti)
2175 {
2176 if (pti->pEThread)
2177 {
2178 BOOL Ret = TRUE;
2179 if (!(pti->pEThread->Tcb.SuspendCount) && !PsGetThreadFreezeCount(pti->pEThread)) Ret = FALSE;
2180 return Ret;
2181 }
2182 return FALSE;
2183 }
2184
2185 VOID
2186 CALLBACK
HungAppSysTimerProc(HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime)2187 HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
2188 {
2189 DoTheScreenSaver();
2190 TRACE("HungAppSysTimerProc\n");
2191 // Process list of windows that are hung and waiting.
2192 }
2193
2194 BOOLEAN FASTCALL
MsqInitializeMessageQueue(PTHREADINFO pti,PUSER_MESSAGE_QUEUE MessageQueue)2195 MsqInitializeMessageQueue(PTHREADINFO pti, PUSER_MESSAGE_QUEUE MessageQueue)
2196 {
2197 InitializeListHead(&MessageQueue->HardwareMessagesListHead); // Keep here!
2198 MessageQueue->spwndFocus = NULL;
2199 MessageQueue->iCursorLevel = 0;
2200 MessageQueue->CursorObject = SYSTEMCUR(WAIT); // See test_initial_cursor.
2201 if (MessageQueue->CursorObject)
2202 {
2203 TRACE("Default cursor hcur %p\n",UserHMGetHandle(MessageQueue->CursorObject));
2204 UserReferenceObject(MessageQueue->CursorObject);
2205 }
2206 RtlCopyMemory(MessageQueue->afKeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState));
2207 MessageQueue->ptiMouse = pti;
2208 MessageQueue->ptiKeyboard = pti;
2209 MessageQueue->cThreads++;
2210
2211 return TRUE;
2212 }
2213
2214 VOID FASTCALL
MsqCleanupThreadMsgs(PTHREADINFO pti)2215 MsqCleanupThreadMsgs(PTHREADINFO pti)
2216 {
2217 PLIST_ENTRY CurrentEntry;
2218 PUSER_MESSAGE CurrentMessage;
2219 PUSER_SENT_MESSAGE CurrentSentMessage;
2220
2221 TRACE("MsqCleanupThreadMsgs %p\n",pti);
2222
2223 // Clear it all out.
2224 if (pti->pcti)
2225 {
2226 pti->pcti->fsWakeBits = 0;
2227 pti->pcti->fsChangeBits = 0;
2228 }
2229
2230 pti->nCntsQBits[QSRosKey] = 0;
2231 pti->nCntsQBits[QSRosMouseMove] = 0;
2232 pti->nCntsQBits[QSRosMouseButton] = 0;
2233 pti->nCntsQBits[QSRosPostMessage] = 0;
2234 pti->nCntsQBits[QSRosSendMessage] = 0;
2235 pti->nCntsQBits[QSRosHotKey] = 0;
2236 pti->nCntsQBits[QSRosEvent] = 0;
2237
2238 /* cleanup posted messages */
2239 while (!IsListEmpty(&pti->PostedMessagesListHead))
2240 {
2241 CurrentEntry = pti->PostedMessagesListHead.Flink;
2242 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
2243 ERR("Thread Cleanup Post Messages %p\n",CurrentMessage);
2244 if (CurrentMessage->dwQEvent)
2245 {
2246 if (CurrentMessage->dwQEvent == POSTEVENT_NWE)
2247 {
2248 ExFreePoolWithTag( (PVOID)CurrentMessage->ExtraInfo, TAG_HOOK);
2249 }
2250 }
2251 MsqDestroyMessage(CurrentMessage);
2252 }
2253
2254 /* remove the messages that have not yet been dispatched */
2255 while (!IsListEmpty(&pti->SentMessagesListHead))
2256 {
2257 CurrentEntry = pti->SentMessagesListHead.Flink;
2258 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
2259
2260 ERR("Thread Cleanup Sent Messages %p\n",CurrentSentMessage);
2261
2262 /* wake the sender's thread */
2263 if (CurrentSentMessage->pkCompletionEvent != NULL)
2264 {
2265 KeSetEvent(CurrentSentMessage->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
2266 }
2267
2268 if (CurrentSentMessage->HasPackedLParam)
2269 {
2270 if (CurrentSentMessage->Msg.lParam)
2271 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
2272 }
2273
2274 /* free the message */
2275 FreeUserMessage(CurrentSentMessage);
2276 }
2277
2278 // Process Trouble Message List
2279 if (!IsListEmpty(&usmList))
2280 {
2281 CurrentEntry = usmList.Flink;
2282 while (CurrentEntry != &usmList)
2283 {
2284 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
2285 CurrentEntry = CurrentEntry->Flink;
2286
2287 TRACE("Found troubled messages %p on the list\n",CurrentSentMessage);
2288
2289 if ( pti == CurrentSentMessage->ptiReceiver )
2290 {
2291 if (CurrentSentMessage->HasPackedLParam)
2292 {
2293 if (CurrentSentMessage->Msg.lParam)
2294 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
2295 }
2296
2297 /* free the message */
2298 FreeUserMessage(CurrentSentMessage);
2299 }
2300 else if ( pti == CurrentSentMessage->ptiSender ||
2301 pti == CurrentSentMessage->ptiCallBackSender )
2302 {
2303 // Determine whether this message is being processed or not.
2304 if ((CurrentSentMessage->flags & (SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE)) != SMF_RECEIVEDMESSAGE)
2305 {
2306 CurrentSentMessage->flags |= SMF_RECEIVERFREE;
2307 }
2308
2309 if (!(CurrentSentMessage->flags & SMF_RECEIVERFREE))
2310 {
2311
2312 if (CurrentSentMessage->HasPackedLParam)
2313 {
2314 if (CurrentSentMessage->Msg.lParam)
2315 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
2316 }
2317
2318 /* free the message */
2319 FreeUserMessage(CurrentSentMessage);
2320 }
2321 }
2322 }
2323 }
2324 }
2325
2326 VOID FASTCALL
MsqCleanupMessageQueue(PTHREADINFO pti)2327 MsqCleanupMessageQueue(PTHREADINFO pti)
2328 {
2329 PUSER_MESSAGE_QUEUE MessageQueue;
2330 PLIST_ENTRY CurrentEntry;
2331 PUSER_MESSAGE CurrentMessage;
2332
2333 MessageQueue = pti->MessageQueue;
2334 MessageQueue->cThreads--;
2335
2336 if (MessageQueue->cThreads)
2337 {
2338 if (MessageQueue->ptiSysLock == pti) MessageQueue->ptiSysLock = NULL;
2339 }
2340
2341 if (MessageQueue->cThreads == 0) //// Fix a crash related to CORE-10471 testing.
2342 {
2343 /* cleanup posted messages */
2344 while (!IsListEmpty(&MessageQueue->HardwareMessagesListHead))
2345 {
2346 CurrentEntry = MessageQueue->HardwareMessagesListHead.Flink;
2347 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
2348 ERR("MQ Cleanup Post Messages %p\n",CurrentMessage);
2349 MsqDestroyMessage(CurrentMessage);
2350 }
2351 } ////
2352
2353 if (MessageQueue->CursorObject)
2354 {
2355 PCURICON_OBJECT pCursor = MessageQueue->CursorObject;
2356
2357 /* Change to another cursor if we going to dereference current one
2358 Note: we can't use UserSetCursor because it uses current thread
2359 message queue instead of queue given for cleanup */
2360 if (IntGetSysCursorInfo()->CurrentCursorObject == pCursor)
2361 {
2362 HDC hdcScreen;
2363
2364 /* Get the screen DC */
2365 hdcScreen = IntGetScreenDC();
2366 if (hdcScreen)
2367 GreMovePointer(hdcScreen, -1, -1);
2368 IntGetSysCursorInfo()->CurrentCursorObject = NULL;
2369 }
2370
2371 TRACE("DereferenceObject pCursor\n");
2372 UserDereferenceObject(pCursor);
2373 }
2374
2375 if (gpqForeground == MessageQueue)
2376 {
2377 IntSetFocusMessageQueue(NULL);
2378 }
2379 if (gpqForegroundPrev == MessageQueue)
2380 {
2381 gpqForegroundPrev = NULL;
2382 }
2383 if (gpqCursor == MessageQueue)
2384 {
2385 gpqCursor = NULL;
2386 }
2387 }
2388
2389 PUSER_MESSAGE_QUEUE FASTCALL
MsqCreateMessageQueue(PTHREADINFO pti)2390 MsqCreateMessageQueue(PTHREADINFO pti)
2391 {
2392 PUSER_MESSAGE_QUEUE MessageQueue;
2393
2394 MessageQueue = ExAllocatePoolWithTag(NonPagedPool,
2395 sizeof(*MessageQueue),
2396 USERTAG_Q);
2397
2398 if (!MessageQueue)
2399 {
2400 return NULL;
2401 }
2402
2403 RtlZeroMemory(MessageQueue, sizeof(*MessageQueue));
2404 /* hold at least one reference until it'll be destroyed */
2405 IntReferenceMessageQueue(MessageQueue);
2406 /* initialize the queue */
2407 if (!MsqInitializeMessageQueue(pti, MessageQueue))
2408 {
2409 IntDereferenceMessageQueue(MessageQueue);
2410 return NULL;
2411 }
2412
2413 return MessageQueue;
2414 }
2415
2416 VOID FASTCALL
MsqDestroyMessageQueue(_In_ PTHREADINFO pti)2417 MsqDestroyMessageQueue(_In_ PTHREADINFO pti)
2418 {
2419 PDESKTOP desk;
2420 PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
2421
2422 NT_ASSERT(MessageQueue != NULL);
2423 MessageQueue->QF_flags |= QF_INDESTROY;
2424
2425 /* remove the message queue from any desktops */
2426 if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0)))
2427 {
2428 (void)InterlockedExchangePointer((PVOID*)&desk->ActiveMessageQueue, 0);
2429 IntDereferenceMessageQueue(MessageQueue);
2430 }
2431
2432 /* clean it up */
2433 MsqCleanupMessageQueue(pti);
2434
2435 /* decrease the reference counter, if it hits zero, the queue will be freed */
2436 _PRAGMA_WARNING_SUPPRESS(__WARNING_USING_UNINIT_VAR);
2437 IntDereferenceMessageQueue(MessageQueue);
2438 }
2439
2440 LPARAM FASTCALL
MsqSetMessageExtraInfo(LPARAM lParam)2441 MsqSetMessageExtraInfo(LPARAM lParam)
2442 {
2443 LPARAM Ret;
2444 PTHREADINFO pti;
2445 PUSER_MESSAGE_QUEUE MessageQueue;
2446
2447 pti = PsGetCurrentThreadWin32Thread();
2448 MessageQueue = pti->MessageQueue;
2449 if(!MessageQueue)
2450 {
2451 return 0;
2452 }
2453
2454 Ret = MessageQueue->ExtraInfo;
2455 MessageQueue->ExtraInfo = lParam;
2456
2457 return Ret;
2458 }
2459
2460 LPARAM FASTCALL
MsqGetMessageExtraInfo(VOID)2461 MsqGetMessageExtraInfo(VOID)
2462 {
2463 PTHREADINFO pti;
2464 PUSER_MESSAGE_QUEUE MessageQueue;
2465
2466 pti = PsGetCurrentThreadWin32Thread();
2467 MessageQueue = pti->MessageQueue;
2468 if(!MessageQueue)
2469 {
2470 return 0;
2471 }
2472
2473 return MessageQueue->ExtraInfo;
2474 }
2475
2476 // ReplyMessage is called by the thread receiving the window message.
2477 BOOL FASTCALL
co_MsqReplyMessage(LRESULT lResult)2478 co_MsqReplyMessage( LRESULT lResult )
2479 {
2480 PUSER_SENT_MESSAGE Message;
2481 PTHREADINFO pti;
2482
2483 pti = PsGetCurrentThreadWin32Thread();
2484 Message = pti->pusmCurrent;
2485
2486 if (!Message) return FALSE;
2487
2488 if (Message->QS_Flags & QS_SMRESULT) return FALSE;
2489
2490 // SendMessageXxx || Callback msg and not a notify msg
2491 if (Message->ptiSender || Message->CompletionCallback)
2492 {
2493 Message->lResult = lResult;
2494 Message->QS_Flags |= QS_SMRESULT;
2495 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2496 }
2497 return TRUE;
2498 }
2499
2500 HWND FASTCALL
MsqSetStateWindow(PTHREADINFO pti,ULONG Type,HWND hWnd)2501 MsqSetStateWindow(PTHREADINFO pti, ULONG Type, HWND hWnd)
2502 {
2503 HWND Prev;
2504 PUSER_MESSAGE_QUEUE MessageQueue;
2505
2506 MessageQueue = pti->MessageQueue;
2507
2508 switch(Type)
2509 {
2510 case MSQ_STATE_CAPTURE:
2511 Prev = MessageQueue->spwndCapture ? UserHMGetHandle(MessageQueue->spwndCapture) : 0;
2512 MessageQueue->spwndCapture = ValidateHwndNoErr(hWnd);
2513 return Prev;
2514 case MSQ_STATE_ACTIVE:
2515 Prev = MessageQueue->spwndActive ? UserHMGetHandle(MessageQueue->spwndActive) : 0;
2516 MessageQueue->spwndActive = ValidateHwndNoErr(hWnd);
2517 return Prev;
2518 case MSQ_STATE_FOCUS:
2519 Prev = MessageQueue->spwndFocus ? UserHMGetHandle(MessageQueue->spwndFocus) : 0;
2520 MessageQueue->spwndFocus = ValidateHwndNoErr(hWnd);
2521 return Prev;
2522 case MSQ_STATE_MENUOWNER:
2523 Prev = MessageQueue->MenuOwner;
2524 MessageQueue->MenuOwner = hWnd;
2525 return Prev;
2526 case MSQ_STATE_MOVESIZE:
2527 Prev = MessageQueue->MoveSize;
2528 MessageQueue->MoveSize = hWnd;
2529 return Prev;
2530 case MSQ_STATE_CARET:
2531 Prev = MessageQueue->CaretInfo.hWnd;
2532 MessageQueue->CaretInfo.hWnd = hWnd;
2533 return Prev;
2534 }
2535
2536 return NULL;
2537 }
2538
2539 VOID FASTCALL
MsqReleaseModifierKeys(PUSER_MESSAGE_QUEUE MessageQueue)2540 MsqReleaseModifierKeys(PUSER_MESSAGE_QUEUE MessageQueue)
2541 {
2542 WORD ModifierKeys[] = { VK_LCONTROL, VK_RCONTROL, VK_CONTROL,
2543 VK_LMENU, VK_RMENU, VK_MENU,
2544 VK_LSHIFT, VK_RSHIFT, VK_SHIFT };
2545 UINT i;
2546
2547 for (i = 0; i < _countof(ModifierKeys); ++i)
2548 {
2549 if (IS_KEY_DOWN(MessageQueue->afKeyState, ModifierKeys[i]))
2550 SET_KEY_DOWN(MessageQueue->afKeyState, ModifierKeys[i], FALSE);
2551 }
2552 }
2553
2554 SHORT
2555 APIENTRY
NtUserGetKeyState(INT key)2556 NtUserGetKeyState(INT key)
2557 {
2558 DWORD Ret;
2559
2560 UserEnterShared();
2561
2562 Ret = UserGetKeyState(key);
2563
2564 UserLeave();
2565
2566 return (SHORT)Ret;
2567 }
2568
2569
2570 DWORD
2571 APIENTRY
NtUserGetKeyboardState(LPBYTE lpKeyState)2572 NtUserGetKeyboardState(LPBYTE lpKeyState)
2573 {
2574 DWORD i, ret = TRUE;
2575 PTHREADINFO pti;
2576 PUSER_MESSAGE_QUEUE MessageQueue;
2577
2578 UserEnterShared();
2579
2580 pti = PsGetCurrentThreadWin32Thread();
2581 MessageQueue = pti->MessageQueue;
2582
2583 _SEH2_TRY
2584 {
2585 /* Probe and copy key state to an array */
2586 ProbeForWrite(lpKeyState, 256 * sizeof(BYTE), 1);
2587 for (i = 0; i < 256; ++i)
2588 {
2589 lpKeyState[i] = 0;
2590 if (IS_KEY_DOWN(MessageQueue->afKeyState, i))
2591 lpKeyState[i] |= KS_DOWN_BIT;
2592 if (IS_KEY_LOCKED(MessageQueue->afKeyState, i))
2593 lpKeyState[i] |= KS_LOCK_BIT;
2594 }
2595 }
2596 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2597 {
2598 SetLastNtError(_SEH2_GetExceptionCode());
2599 ret = FALSE;
2600 }
2601 _SEH2_END;
2602
2603 UserLeave();
2604
2605 return ret;
2606 }
2607
2608 BOOL
2609 APIENTRY
NtUserSetKeyboardState(LPBYTE pKeyState)2610 NtUserSetKeyboardState(LPBYTE pKeyState)
2611 {
2612 UINT i;
2613 BOOL bRet = TRUE;
2614 PTHREADINFO pti;
2615 PUSER_MESSAGE_QUEUE MessageQueue;
2616
2617 UserEnterExclusive();
2618
2619 pti = PsGetCurrentThreadWin32Thread();
2620 MessageQueue = pti->MessageQueue;
2621
2622 _SEH2_TRY
2623 {
2624 ProbeForRead(pKeyState, 256 * sizeof(BYTE), 1);
2625 for (i = 0; i < 256; ++i)
2626 {
2627 SET_KEY_DOWN(MessageQueue->afKeyState, i, pKeyState[i] & KS_DOWN_BIT);
2628 SET_KEY_LOCKED(MessageQueue->afKeyState, i, pKeyState[i] & KS_LOCK_BIT);
2629 }
2630 }
2631 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2632 {
2633 SetLastNtError(_SEH2_GetExceptionCode());
2634 bRet = FALSE;
2635 }
2636 _SEH2_END;
2637
2638 UserLeave();
2639
2640 return bRet;
2641 }
2642
2643 /* EOF */
2644