[WIN32K:NTUSER]
[reactos.git] / reactos / win32ss / user / ntuser / msgqueue.c
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 INIT_FUNCTION
28 NTSTATUS
29 NTAPI
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
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
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 */
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
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
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
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
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
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
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
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
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
501 MsqIncPaintCountQueue(PTHREADINFO pti)
502 {
503 pti->cPaintsReady++;
504 MsqWakeQueue(pti, QS_PAINT, TRUE);
505 }
506
507 VOID FASTCALL
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
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
551 IntCoalesceMouseMove(PTHREADINFO pti)
552 {
553 MSG Msg;
554 LARGE_INTEGER LargeTickCount;
555
556 // Force time stamp to update, keeping message time in sync.
557 if (gdwMouseMoveTimeStamp == 0)
558 {
559 KeQueryTickCount(&LargeTickCount);
560 gdwMouseMoveTimeStamp = MsqCalculateMessageTime(&LargeTickCount);
561 }
562
563 // Build mouse move message.
564 Msg.hwnd = NULL;
565 Msg.message = WM_MOUSEMOVE;
566 Msg.wParam = 0;
567 Msg.lParam = MAKELONG(gpsi->ptCursor.x, gpsi->ptCursor.y);
568 Msg.time = gdwMouseMoveTimeStamp;
569 Msg.pt = gpsi->ptCursor;
570
571 // Post the move.
572 MsqPostMouseMove(pti, &Msg, gdwMouseMoveExtraInfo);
573
574 // Zero the time stamp.
575 gdwMouseMoveTimeStamp = 0;
576
577 // Clear flag since the move was posted.
578 pti->MessageQueue->QF_flags &= ~QF_MOUSEMOVED;
579 }
580
581 VOID FASTCALL
582 co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
583 {
584 LARGE_INTEGER LargeTickCount;
585 MSLLHOOKSTRUCT MouseHookData;
586 // PDESKTOP pDesk;
587 PWND pwnd, pwndDesktop;
588 HDC hdcScreen;
589 PTHREADINFO pti;
590 PUSER_MESSAGE_QUEUE MessageQueue;
591 PSYSTEM_CURSORINFO CurInfo;
592
593 KeQueryTickCount(&LargeTickCount);
594 Msg->time = MsqCalculateMessageTime(&LargeTickCount);
595
596 MouseHookData.pt.x = LOWORD(Msg->lParam);
597 MouseHookData.pt.y = HIWORD(Msg->lParam);
598 switch (Msg->message)
599 {
600 case WM_MOUSEWHEEL:
601 MouseHookData.mouseData = MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg->wParam));
602 break;
603 case WM_XBUTTONDOWN:
604 case WM_XBUTTONUP:
605 case WM_XBUTTONDBLCLK:
606 case WM_NCXBUTTONDOWN:
607 case WM_NCXBUTTONUP:
608 case WM_NCXBUTTONDBLCLK:
609 MouseHookData.mouseData = MAKELONG(0, HIWORD(Msg->wParam));
610 break;
611 default:
612 MouseHookData.mouseData = 0;
613 break;
614 }
615
616 MouseHookData.flags = flags; // LLMHF_INJECTED
617 MouseHookData.time = Msg->time;
618 MouseHookData.dwExtraInfo = dwExtraInfo;
619
620 /* If the hook procedure returned non zero, dont send the message */
621 if (Hook)
622 {
623 if (co_HOOK_CallHooks(WH_MOUSE_LL, HC_ACTION, Msg->message, (LPARAM) &MouseHookData))
624 return;
625 }
626
627 /* Get the desktop window */
628 pwndDesktop = UserGetDesktopWindow();
629 if (!pwndDesktop) return;
630 // pDesk = pwndDesktop->head.rpdesk;
631
632 /* Check if the mouse is captured */
633 Msg->hwnd = IntGetCaptureWindow();
634 if (Msg->hwnd != NULL)
635 {
636 pwnd = UserGetWindowObject(Msg->hwnd);
637 }
638 else
639 {
640 pwnd = IntTopLevelWindowFromPoint(Msg->pt.x, Msg->pt.y);
641 if (pwnd) Msg->hwnd = pwnd->head.h;
642 }
643
644 hdcScreen = IntGetScreenDC();
645 CurInfo = IntGetSysCursorInfo();
646
647 /* Check if we found a window */
648 if (Msg->hwnd != NULL && pwnd != NULL)
649 {
650 pti = pwnd->head.pti;
651 MessageQueue = pti->MessageQueue;
652
653 if (MessageQueue->QF_flags & QF_INDESTROY)
654 {
655 ERR("Mouse is over a Window with a Dead Message Queue!\n");
656 return;
657 }
658
659 // Check to see if this is attached.
660 if ( pti != MessageQueue->ptiMouse &&
661 MessageQueue->cThreads > 1 )
662 {
663 // Set the send pti to the message queue mouse pti.
664 pti = MessageQueue->ptiMouse;
665 }
666
667 if (Msg->message == WM_MOUSEMOVE)
668 {
669 /* Check if cursor should be visible */
670 if(hdcScreen &&
671 MessageQueue->CursorObject &&
672 MessageQueue->iCursorLevel >= 0)
673 {
674 /* Check if shape has changed */
675 if(CurInfo->CurrentCursorObject != MessageQueue->CursorObject)
676 {
677 /* Call GDI to set the new screen cursor */
678 GreSetPointerShape(hdcScreen,
679 MessageQueue->CursorObject->hbmAlpha ?
680 NULL : MessageQueue->CursorObject->hbmMask,
681 MessageQueue->CursorObject->hbmAlpha ?
682 MessageQueue->CursorObject->hbmAlpha : MessageQueue->CursorObject->hbmColor,
683 MessageQueue->CursorObject->xHotspot,
684 MessageQueue->CursorObject->yHotspot,
685 gpsi->ptCursor.x,
686 gpsi->ptCursor.y,
687 MessageQueue->CursorObject->hbmAlpha ? SPS_ALPHA : 0);
688
689 } else
690 GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
691 }
692 /* Check if we have to hide cursor */
693 else if (CurInfo->ShowingCursor >= 0)
694 GreMovePointer(hdcScreen, -1, -1);
695
696 /* Update global cursor info */
697 CurInfo->ShowingCursor = MessageQueue->iCursorLevel;
698 CurInfo->CurrentCursorObject = MessageQueue->CursorObject;
699 gpqCursor = MessageQueue;
700
701 /* Mouse move is a special case */
702 MessageQueue->QF_flags |= QF_MOUSEMOVED;
703 gdwMouseMoveExtraInfo = dwExtraInfo;
704 gdwMouseMoveTimeStamp = Msg->time;
705 MsqWakeQueue(pti, QS_MOUSEMOVE, TRUE);
706 }
707 else
708 {
709 if (!IntGetCaptureWindow())
710 {
711 // ERR("ptiLastInput is set\n");
712 // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground.
713 // Find all the Move Mouse calls and fix mouse set active focus issues......
714 }
715
716 // Post mouse move before posting mouse buttons, keep it in sync.
717 if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED)
718 {
719 IntCoalesceMouseMove(pti);
720 }
721
722 TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd));
723 MsqPostMessage(pti, Msg, TRUE, QS_MOUSEBUTTON, 0, dwExtraInfo);
724 }
725 }
726 else if (hdcScreen)
727 {
728 /* always show cursor on background; FIXME: set default pointer */
729 GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
730 CurInfo->ShowingCursor = 0;
731 }
732 }
733
734 PUSER_MESSAGE FASTCALL
735 MsqCreateMessage(LPMSG Msg)
736 {
737 PUSER_MESSAGE Message;
738
739 Message = ExAllocateFromPagedLookasideList(pgMessageLookasideList);
740 if (!Message)
741 {
742 return NULL;
743 }
744
745 RtlZeroMemory(Message, sizeof(*Message));
746 RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG));
747 PostMsgCount++;
748 return Message;
749 }
750
751 VOID FASTCALL
752 MsqDestroyMessage(PUSER_MESSAGE Message)
753 {
754 TRACE("Post Destroy %d\n",PostMsgCount)
755 if (Message->pti == NULL)
756 {
757 ERR("Double Free Message\n");
758 return;
759 }
760 RemoveEntryList(&Message->ListEntry);
761 Message->pti = NULL;
762 ExFreeToPagedLookasideList(pgMessageLookasideList, Message);
763 PostMsgCount--;
764 }
765
766 PUSER_SENT_MESSAGE FASTCALL
767 AllocateUserMessage(BOOL KEvent)
768 {
769 PUSER_SENT_MESSAGE Message;
770
771 if(!(Message = ExAllocateFromPagedLookasideList(pgSendMsgLookasideList)))
772 {
773 ERR("AllocateUserMessage(): Not enough memory to allocate a message");
774 return NULL;
775 }
776 RtlZeroMemory(Message, sizeof(USER_SENT_MESSAGE));
777
778 if (KEvent)
779 {
780 Message->pkCompletionEvent = &Message->CompletionEvent;
781
782 KeInitializeEvent(Message->pkCompletionEvent, NotificationEvent, FALSE);
783 }
784 SendMsgCount++;
785 TRACE("AUM pti %p msg %p\n",PsGetCurrentThreadWin32Thread(),Message);
786 return Message;
787 }
788
789 VOID FASTCALL
790 FreeUserMessage(PUSER_SENT_MESSAGE Message)
791 {
792 Message->pkCompletionEvent = NULL;
793
794 /* Remove it from the list */
795 RemoveEntryList(&Message->ListEntry);
796
797 ExFreeToPagedLookasideList(pgSendMsgLookasideList, Message);
798 SendMsgCount--;
799 }
800
801 VOID APIENTRY
802 MsqRemoveWindowMessagesFromQueue(PWND Window)
803 {
804 PTHREADINFO pti;
805 PUSER_SENT_MESSAGE SentMessage;
806 PUSER_MESSAGE PostedMessage;
807 PLIST_ENTRY CurrentEntry, ListHead;
808
809 ASSERT(Window);
810
811 pti = Window->head.pti;
812
813 /* remove the posted messages for this window */
814 CurrentEntry = pti->PostedMessagesListHead.Flink;
815 ListHead = &pti->PostedMessagesListHead;
816 while (CurrentEntry != ListHead)
817 {
818 PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
819
820 if (PostedMessage->Msg.hwnd == Window->head.h)
821 {
822 if (PostedMessage->Msg.message == WM_QUIT && pti->QuitPosted == 0)
823 {
824 pti->QuitPosted = 1;
825 pti->exitCode = PostedMessage->Msg.wParam;
826 }
827 ClearMsgBitsMask(pti, PostedMessage->QS_Flags);
828 MsqDestroyMessage(PostedMessage);
829 CurrentEntry = pti->PostedMessagesListHead.Flink;
830 }
831 else
832 {
833 CurrentEntry = CurrentEntry->Flink;
834 }
835 }
836
837 /* remove the sent messages for this window */
838 CurrentEntry = pti->SentMessagesListHead.Flink;
839 ListHead = &pti->SentMessagesListHead;
840 while (CurrentEntry != ListHead)
841 {
842 SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
843
844 if(SentMessage->Msg.hwnd == Window->head.h)
845 {
846 ERR("Remove Window Messages %p From Sent Queue\n",SentMessage);
847 #if 0 // Should mark these as invalid and allow the rest clean up, so far no harm by just commenting out. See CORE-9210.
848 ClearMsgBitsMask(pti, SentMessage->QS_Flags);
849
850 /* wake the sender's thread */
851 if (SentMessage->pkCompletionEvent != NULL)
852 {
853 KeSetEvent(SentMessage->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
854 }
855
856 if (SentMessage->HasPackedLParam)
857 {
858 if (SentMessage->Msg.lParam)
859 ExFreePool((PVOID)SentMessage->Msg.lParam);
860 }
861
862 /* free the message */
863 FreeUserMessage(SentMessage);
864
865 CurrentEntry = pti->SentMessagesListHead.Flink;
866 #endif
867 CurrentEntry = CurrentEntry->Flink;
868 }
869 else
870 {
871 CurrentEntry = CurrentEntry->Flink;
872 }
873 }
874 }
875
876 BOOLEAN FASTCALL
877 co_MsqDispatchOneSentMessage(
878 _In_ PTHREADINFO pti)
879 {
880 PUSER_SENT_MESSAGE SaveMsg, Message;
881 PLIST_ENTRY Entry;
882 BOOL Ret;
883 LRESULT Result = 0;
884
885 ASSERT(pti == PsGetCurrentThreadWin32Thread());
886
887 if (IsListEmpty(&pti->SentMessagesListHead))
888 {
889 return(FALSE);
890 }
891
892 /* remove it from the list of pending messages */
893 Entry = RemoveHeadList(&pti->SentMessagesListHead);
894 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
895
896 // Signal this message is being processed.
897 Message->flags |= SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE;
898
899 SaveMsg = pti->pusmCurrent;
900 pti->pusmCurrent = Message;
901
902 // Processing a message sent to it from another thread.
903 if ( ( Message->ptiSender && pti != Message->ptiSender) ||
904 ( Message->ptiCallBackSender && pti != Message->ptiCallBackSender ))
905 { // most likely, but, to be sure.
906 pti->pcti->CTI_flags |= CTI_INSENDMESSAGE; // Let the user know...
907 }
908
909 /* Now insert it to the global list of messages that can be removed Justin Case there's Trouble */
910 InsertTailList(&usmList, &Message->ListEntry);
911
912 ClearMsgBitsMask(pti, Message->QS_Flags);
913
914 if (Message->HookMessage == MSQ_ISHOOK)
915 { // Direct Hook Call processor
916 Result = co_CallHook( Message->Msg.message, // HookId
917 (INT)(INT_PTR)Message->Msg.hwnd, // Code
918 Message->Msg.wParam,
919 Message->Msg.lParam);
920 }
921 else if(Message->HookMessage == MSQ_INJECTMODULE)
922 {
923 Result = IntLoadHookModule(Message->Msg.message,
924 (HHOOK)Message->Msg.lParam,
925 Message->Msg.wParam);
926 }
927 else if ((Message->CompletionCallback) &&
928 (Message->ptiCallBackSender == pti))
929 { /* Call the callback routine */
930 if (Message->QS_Flags & QS_SMRESULT)
931 {
932 co_IntCallSentMessageCallback(Message->CompletionCallback,
933 Message->Msg.hwnd,
934 Message->Msg.message,
935 Message->CompletionCallbackContext,
936 Message->lResult);
937 /* Set callback to NULL to prevent reentry */
938 Message->CompletionCallback = NULL;
939 }
940 else
941 {
942 /* The message has not been processed yet, reinsert it. */
943 RemoveEntryList(&Message->ListEntry);
944 InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry);
945 // List is occupied need to set the bit.
946 MsqWakeQueue(Message->ptiCallBackSender, QS_SENDMESSAGE, TRUE);
947 ERR("Callback Message not processed yet. Requeuing the message\n"); //// <---- Need to see if this happens.
948 Ret = FALSE;
949 goto Exit;
950 }
951 }
952 else
953 { /* Call the window procedure. */
954 Result = co_IntSendMessage( Message->Msg.hwnd,
955 Message->Msg.message,
956 Message->Msg.wParam,
957 Message->Msg.lParam);
958 }
959
960 /* If the message is a callback, insert it in the callback senders MessageQueue */
961 if (Message->CompletionCallback)
962 {
963 if (Message->ptiCallBackSender)
964 {
965 Message->lResult = Result;
966 Message->QS_Flags |= QS_SMRESULT;
967
968 /* insert it in the callers message queue */
969 RemoveEntryList(&Message->ListEntry);
970 InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry);
971 MsqWakeQueue(Message->ptiCallBackSender, QS_SENDMESSAGE, TRUE);
972 }
973 Ret = TRUE;
974 goto Exit;
975 }
976
977 // Retrieve the result from callback.
978 if (Message->QS_Flags & QS_SMRESULT)
979 {
980 Result = Message->lResult;
981 }
982
983 /* Let the sender know the result. */
984 Message->lResult = Result;
985
986 if (Message->HasPackedLParam)
987 {
988 if (Message->Msg.lParam)
989 ExFreePool((PVOID)Message->Msg.lParam);
990 }
991
992 // Clear busy signal.
993 Message->flags &= ~SMF_RECEIVERBUSY;
994
995 /* Notify the sender. */
996 if (Message->pkCompletionEvent != NULL)
997 {
998 KeSetEvent(Message->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
999 }
1000
1001 /* free the message */
1002 if (Message->flags & SMF_RECEIVERFREE)
1003 {
1004 TRACE("Receiver Freeing Message %p\n",Message);
1005 FreeUserMessage(Message);
1006 }
1007
1008 Ret = TRUE;
1009 Exit:
1010 /* do not hangup on the user if this is reentering */
1011 if (!SaveMsg) pti->pcti->CTI_flags &= ~CTI_INSENDMESSAGE;
1012 pti->pusmCurrent = SaveMsg;
1013
1014 return Ret;
1015 }
1016
1017 BOOL FASTCALL
1018 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,
1019 HWND hwnd,
1020 UINT Msg,
1021 WPARAM wParam,
1022 LPARAM lParam,
1023 SENDASYNCPROC CompletionCallback,
1024 ULONG_PTR CompletionCallbackContext,
1025 BOOL HasPackedLParam,
1026 INT HookMessage)
1027 {
1028
1029 PTHREADINFO ptiSender;
1030 PUSER_SENT_MESSAGE Message;
1031
1032 if(!(Message = AllocateUserMessage(FALSE)))
1033 {
1034 ERR("MsqSendMessageAsync(): Not enough memory to allocate a message");
1035 return FALSE;
1036 }
1037
1038 ptiSender = PsGetCurrentThreadWin32Thread();
1039
1040 Message->Msg.hwnd = hwnd;
1041 Message->Msg.message = Msg;
1042 Message->Msg.wParam = wParam;
1043 Message->Msg.lParam = lParam;
1044 Message->pkCompletionEvent = NULL; // No event needed.
1045 Message->ptiReceiver = ptiReceiver;
1046 Message->ptiCallBackSender = ptiSender;
1047 Message->CompletionCallback = CompletionCallback;
1048 Message->CompletionCallbackContext = CompletionCallbackContext;
1049 Message->HookMessage = HookMessage;
1050 Message->HasPackedLParam = HasPackedLParam;
1051 Message->QS_Flags = QS_SENDMESSAGE;
1052 Message->flags = SMF_RECEIVERFREE;
1053
1054 InsertTailList(&ptiReceiver->SentMessagesListHead, &Message->ListEntry);
1055 MsqWakeQueue(ptiReceiver, QS_SENDMESSAGE, TRUE);
1056
1057 return TRUE;
1058 }
1059
1060 NTSTATUS FASTCALL
1061 co_MsqSendMessage(PTHREADINFO ptirec,
1062 HWND Wnd,
1063 UINT Msg,
1064 WPARAM wParam,
1065 LPARAM lParam,
1066 UINT uTimeout,
1067 BOOL Block,
1068 INT HookMessage,
1069 ULONG_PTR *uResult)
1070 {
1071 PTHREADINFO pti;
1072 PUSER_SENT_MESSAGE SaveMsg, Message;
1073 NTSTATUS WaitStatus;
1074 LARGE_INTEGER Timeout;
1075 PLIST_ENTRY Entry;
1076 PWND pWnd;
1077 BOOLEAN SwapStateEnabled;
1078 LRESULT Result = 0; //// Result could be trashed. ////
1079
1080 pti = PsGetCurrentThreadWin32Thread();
1081 ASSERT(pti != ptirec);
1082 ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!!
1083
1084 /* Don't send from or to a dying thread */
1085 if (pti->TIF_flags & TIF_INCLEANUP || ptirec->TIF_flags & TIF_INCLEANUP)
1086 {
1087 // Unless we are dying and need to tell our parents.
1088 if (pti->TIF_flags & TIF_INCLEANUP && !(ptirec->TIF_flags & TIF_INCLEANUP))
1089 {
1090 // Parent notify is the big one. Fire and forget!
1091 TRACE("Send message from dying thread %u\n", Msg);
1092 co_MsqSendMessageAsync(ptirec, Wnd, Msg, wParam, lParam, NULL, 0, FALSE, HookMessage);
1093 }
1094 if (uResult) *uResult = -1;
1095 TRACE("MsqSM: Msg %u Current pti %lu or Rec pti %lu\n", Msg, pti->TIF_flags & TIF_INCLEANUP, ptirec->TIF_flags & TIF_INCLEANUP);
1096 return STATUS_UNSUCCESSFUL;
1097 }
1098
1099 if (IsThreadSuspended(ptirec))
1100 {
1101 ERR("Sending to Suspended Thread Msg %lx\n",Msg);
1102 if (uResult) *uResult = -1;
1103 return STATUS_UNSUCCESSFUL;
1104 }
1105
1106 // Should we do the same for No Wait?
1107 if ( HookMessage == MSQ_NORMAL )
1108 {
1109 pWnd = ValidateHwndNoErr(Wnd);
1110
1111 // These can not cross International Border lines!
1112 if ( pti->ppi != ptirec->ppi && pWnd )
1113 {
1114 switch(Msg)
1115 {
1116 // Handle the special case when working with password transfers across bordering processes.
1117 case EM_GETLINE:
1118 case EM_SETPASSWORDCHAR:
1119 case WM_GETTEXT:
1120 // Look for edit controls setup for passwords.
1121 if ( gpsi->atomSysClass[ICLS_EDIT] == pWnd->pcls->atomClassName && // Use atomNVClassName.
1122 pWnd->style & ES_PASSWORD )
1123 {
1124 if (uResult) *uResult = -1;
1125 ERR("Running across the border without a passport!\n");
1126 EngSetLastError(ERROR_ACCESS_DENIED);
1127 return STATUS_UNSUCCESSFUL;
1128 }
1129 break;
1130 case WM_NOTIFY:
1131 if (uResult) *uResult = -1;
1132 ERR("Running across the border without a passport!\n");
1133 return STATUS_UNSUCCESSFUL;
1134 }
1135 }
1136
1137 // These can not cross State lines!
1138 if ( Msg == WM_CREATE || Msg == WM_NCCREATE )
1139 {
1140 if (uResult) *uResult = -1;
1141 ERR("Can not tell the other State we have Create!\n");
1142 return STATUS_UNSUCCESSFUL;
1143 }
1144 }
1145
1146 if(!(Message = AllocateUserMessage(TRUE)))
1147 {
1148 ERR("MsqSendMessage(): Not enough memory to allocate a message\n");
1149 if (uResult) *uResult = -1;
1150 return STATUS_INSUFFICIENT_RESOURCES;
1151 }
1152
1153 Timeout.QuadPart = Int32x32To64(-10000,uTimeout); // Pass SMTO test with a TO of 0x80000000.
1154 TRACE("Timeout val %lld\n",Timeout.QuadPart)
1155
1156 Message->Msg.hwnd = Wnd;
1157 Message->Msg.message = Msg;
1158 Message->Msg.wParam = wParam;
1159 Message->Msg.lParam = lParam;
1160 Message->ptiReceiver = ptirec;
1161 Message->ptiSender = pti;
1162 Message->HookMessage = HookMessage;
1163 Message->QS_Flags = QS_SENDMESSAGE;
1164
1165 SaveMsg = pti->pusmSent;
1166 pti->pusmSent = Message;
1167
1168 /* Queue it in the destination's message queue */
1169 InsertTailList(&ptirec->SentMessagesListHead, &Message->ListEntry);
1170
1171 MsqWakeQueue(ptirec, QS_SENDMESSAGE, TRUE);
1172
1173 // First time in, turn off swapping of the stack.
1174 if (pti->cEnterCount == 0)
1175 {
1176 SwapStateEnabled = KeSetKernelStackSwapEnable(FALSE);
1177 }
1178 pti->cEnterCount++;
1179
1180 if (Block)
1181 {
1182 PVOID WaitObjects[2];
1183
1184 WaitObjects[0] = Message->pkCompletionEvent; // Wait 0
1185 WaitObjects[1] = ptirec->pEThread; // Wait 1
1186
1187 UserLeaveCo();
1188
1189 WaitStatus = KeWaitForMultipleObjects( 2,
1190 WaitObjects,
1191 WaitAny,
1192 UserRequest,
1193 UserMode,
1194 FALSE,
1195 (uTimeout ? &Timeout : NULL),
1196 NULL );
1197
1198 UserEnterCo();
1199
1200 if (WaitStatus == STATUS_TIMEOUT)
1201 {
1202 /* Look up if the message has not yet dispatched, if so
1203 make sure it can't pass a result and it must not set the completion event anymore */
1204 Entry = ptirec->SentMessagesListHead.Flink;
1205 while (Entry != &ptirec->SentMessagesListHead)
1206 {
1207 if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message)
1208 {
1209 Message->pkCompletionEvent = NULL;
1210 RemoveEntryList(&Message->ListEntry);
1211 ClearMsgBitsMask(ptirec, Message->QS_Flags);
1212 InsertTailList(&usmList, &Message->ListEntry);
1213 break;
1214 }
1215 Entry = Entry->Flink;
1216 }
1217
1218 ERR("MsqSendMessage (blocked) timed out 1 Status %lx\n", WaitStatus);
1219 }
1220 // Receiving thread passed on and left us hanging with issues still pending.
1221 else if (WaitStatus == STATUS_WAIT_1)
1222 {
1223 ERR("Bk Receiving Thread woken up dead!\n");
1224 Message->flags |= SMF_RECEIVERDIED;
1225 }
1226
1227 while (co_MsqDispatchOneSentMessage(pti))
1228 ;
1229 }
1230 else
1231 {
1232 PVOID WaitObjects[3];
1233
1234 WaitObjects[0] = Message->pkCompletionEvent; // Wait 0
1235 WaitObjects[1] = pti->pEventQueueServer; // Wait 1
1236 WaitObjects[2] = ptirec->pEThread; // Wait 2
1237
1238 do
1239 {
1240 UserLeaveCo();
1241
1242 WaitStatus = KeWaitForMultipleObjects( 3,
1243 WaitObjects,
1244 WaitAny,
1245 UserRequest,
1246 UserMode,
1247 FALSE,
1248 (uTimeout ? &Timeout : NULL),
1249 NULL);
1250
1251 UserEnterCo();
1252
1253 if (WaitStatus == STATUS_TIMEOUT)
1254 {
1255 /* Look up if the message has not yet been dispatched, if so
1256 make sure it can't pass a result and it must not set the completion event anymore */
1257 Entry = ptirec->SentMessagesListHead.Flink;
1258 while (Entry != &ptirec->SentMessagesListHead)
1259 {
1260 if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message)
1261 {
1262 Message->pkCompletionEvent = NULL;
1263 RemoveEntryList(&Message->ListEntry);
1264 ClearMsgBitsMask(ptirec, Message->QS_Flags);
1265 InsertTailList(&usmList, &Message->ListEntry);
1266 break;
1267 }
1268 Entry = Entry->Flink;
1269 }
1270
1271 ERR("MsqSendMessage timed out 2 Status %lx\n", WaitStatus);
1272 break;
1273 }
1274 // Receiving thread passed on and left us hanging with issues still pending.
1275 else if (WaitStatus == STATUS_WAIT_2)
1276 {
1277 ERR("NB Receiving Thread woken up dead!\n");
1278 Message->flags |= SMF_RECEIVERDIED;
1279 break;
1280 }
1281
1282 if (WaitStatus == STATUS_USER_APC) break;
1283
1284 while (co_MsqDispatchOneSentMessage(pti))
1285 ;
1286 } while (WaitStatus == STATUS_WAIT_1);
1287 }
1288
1289 // Count is nil, restore swapping of the stack.
1290 if (--pti->cEnterCount == 0 )
1291 {
1292 KeSetKernelStackSwapEnable(SwapStateEnabled);
1293 }
1294
1295 // Handle User APC
1296 if (WaitStatus == STATUS_USER_APC)
1297 {
1298 // The current thread is dying!
1299 TRACE("User APC\n");
1300
1301 // The Message will be on the Trouble list until Thread cleanup.
1302 Message->flags |= SMF_SENDERDIED;
1303
1304 co_IntDeliverUserAPC();
1305 ERR("User APC Returned\n"); // Should not see this message.
1306 }
1307
1308 // Force this thread to wake up for the next go around.
1309 KeSetEvent(pti->pEventQueueServer, IO_NO_INCREMENT, FALSE);
1310
1311 Result = Message->lResult;
1312
1313 // Determine whether this message is being processed or not.
1314 if ((Message->flags & (SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE)) != SMF_RECEIVEDMESSAGE)
1315 {
1316 Message->flags |= SMF_RECEIVERFREE;
1317 }
1318
1319 if (!(Message->flags & SMF_RECEIVERFREE))
1320 {
1321 TRACE("Sender Freeing Message %p ptirec %p bit %d list empty %d\n",Message,ptirec,!!(ptirec->pcti->fsChangeBits & QS_SENDMESSAGE),IsListEmpty(&ptirec->SentMessagesListHead));
1322 // Make it to this point, the message was received.
1323 FreeUserMessage(Message);
1324 }
1325
1326 pti->pusmSent = SaveMsg;
1327
1328 TRACE("MSM Allocation Count %d Status %lx Result %d\n",SendMsgCount,WaitStatus,Result);
1329
1330 if (WaitStatus != STATUS_TIMEOUT)
1331 {
1332 if (uResult)
1333 {
1334 *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : 0);
1335 }
1336 }
1337
1338 return WaitStatus;
1339 }
1340
1341 VOID FASTCALL
1342 MsqPostMessage(PTHREADINFO pti,
1343 MSG* Msg,
1344 BOOLEAN HardwareMessage,
1345 DWORD MessageBits,
1346 DWORD dwQEvent,
1347 LONG_PTR ExtraInfo)
1348 {
1349 PUSER_MESSAGE Message;
1350 PUSER_MESSAGE_QUEUE MessageQueue;
1351
1352 if ( pti->TIF_flags & TIF_INCLEANUP || pti->MessageQueue->QF_flags & QF_INDESTROY )
1353 {
1354 ERR("Post Msg; Thread or Q is Dead!\n");
1355 return;
1356 }
1357
1358 if(!(Message = MsqCreateMessage(Msg)))
1359 {
1360 return;
1361 }
1362
1363 MessageQueue = pti->MessageQueue;
1364
1365 if (!HardwareMessage)
1366 {
1367 InsertTailList(&pti->PostedMessagesListHead, &Message->ListEntry);
1368 }
1369 else
1370 {
1371 InsertTailList(&MessageQueue->HardwareMessagesListHead, &Message->ListEntry);
1372 }
1373
1374 if (Msg->message == WM_HOTKEY) MessageBits |= QS_HOTKEY; // Justin Case, just set it.
1375 Message->dwQEvent = dwQEvent;
1376 Message->ExtraInfo = ExtraInfo;
1377 Message->QS_Flags = MessageBits;
1378 Message->pti = pti;
1379 MsqWakeQueue(pti, MessageBits, TRUE);
1380 TRACE("Post Message %d\n",PostMsgCount);
1381 }
1382
1383 VOID FASTCALL
1384 MsqPostQuitMessage(PTHREADINFO pti, ULONG ExitCode)
1385 {
1386 pti->QuitPosted = TRUE;
1387 pti->exitCode = ExitCode;
1388 MsqWakeQueue(pti, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE);
1389 }
1390
1391 /***********************************************************************
1392 * MsqSendParentNotify
1393 *
1394 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1395 * the window has the WS_EX_NOPARENTNOTIFY style.
1396 */
1397 static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt )
1398 {
1399 PWND pwndDesktop = UserGetDesktopWindow();
1400
1401 /* pt has to be in the client coordinates of the parent window */
1402 pt.x += pwndDesktop->rcClient.left - pwnd->rcClient.left;
1403 pt.y += pwndDesktop->rcClient.top - pwnd->rcClient.top;
1404
1405 for (;;)
1406 {
1407 PWND pwndParent;
1408
1409 if (!(pwnd->style & WS_CHILD)) break;
1410 if (pwnd->ExStyle & WS_EX_NOPARENTNOTIFY) break;
1411 if (!(pwndParent = IntGetParent(pwnd))) break;
1412 if (pwndParent == pwndDesktop) break;
1413 pt.x += pwnd->rcClient.left - pwndParent->rcClient.left;
1414 pt.y += pwnd->rcClient.top - pwndParent->rcClient.top;
1415
1416 pwnd = pwndParent;
1417 co_IntSendMessage( UserHMGetHandle(pwnd), WM_PARENTNOTIFY,
1418 MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) );
1419 }
1420 }
1421
1422 VOID
1423 FASTCALL
1424 IntTrackMouseMove(PWND pwndTrack, PDESKTOP pDesk, PMSG msg, USHORT hittest)
1425 {
1426 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1427 // hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
1428
1429 if ( pDesk->spwndTrack != pwndTrack || // Change with tracking window or
1430 msg->message != WM_MOUSEMOVE || // Mouse click changes or
1431 pDesk->htEx != hittest) // Change in current hit test states.
1432 {
1433 TRACE("ITMM: Track Mouse Move!\n");
1434
1435 /* Handle only the changing window track and mouse move across a border. */
1436 if ( pDesk->spwndTrack != pwndTrack ||
1437 (pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT) )
1438 {
1439 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1440 pDesk->spwndTrack != pwndTrack,(pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT));
1441
1442 if ( pDesk->dwDTFlags & DF_TME_LEAVE )
1443 UserPostMessage( UserHMGetHandle(pDesk->spwndTrack),
1444 (pDesk->htEx != HTCLIENT) ? WM_NCMOUSELEAVE : WM_MOUSELEAVE,
1445 0, 0);
1446
1447 if ( pDesk->dwDTFlags & DF_TME_HOVER )
1448 IntKillTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE);
1449
1450 /* Clear the flags to sign a change. */
1451 pDesk->dwDTFlags &= ~(DF_TME_LEAVE|DF_TME_HOVER);
1452 }
1453 /* Set the Track window and hit test. */
1454 pDesk->spwndTrack = pwndTrack;
1455 pDesk->htEx = hittest;
1456 }
1457
1458 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1459 if ( pDesk->spwndTrack == pwndTrack &&
1460 ( msg->message != WM_MOUSEMOVE || !RECTL_bPointInRect(&pDesk->rcMouseHover, msg->pt.x, msg->pt.y)) &&
1461 pDesk->dwDTFlags & DF_TME_HOVER )
1462 {
1463 TRACE("ITMM: Reset Hover points!\n");
1464 // Restart timer for the hover period.
1465 IntSetTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM);
1466 // Reset desktop mouse hover from the system default hover rectangle.
1467 RECTL_vSetRect(&pDesk->rcMouseHover,
1468 msg->pt.x - gspv.iMouseHoverWidth / 2,
1469 msg->pt.y - gspv.iMouseHoverHeight / 2,
1470 msg->pt.x + gspv.iMouseHoverWidth / 2,
1471 msg->pt.y + gspv.iMouseHoverHeight / 2);
1472 }
1473 }
1474
1475 BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, BOOL* NotForUs, LONG_PTR ExtraInfo, UINT first, UINT last)
1476 {
1477 MSG clk_msg;
1478 POINT pt;
1479 UINT message;
1480 USHORT hittest;
1481 EVENTMSG event;
1482 MOUSEHOOKSTRUCT hook;
1483 BOOL eatMsg = FALSE;
1484
1485 PWND pwndMsg, pwndDesktop;
1486 PUSER_MESSAGE_QUEUE MessageQueue;
1487 PTHREADINFO pti;
1488 PSYSTEM_CURSORINFO CurInfo;
1489 PDESKTOP pDesk;
1490
1491 pti = PsGetCurrentThreadWin32Thread();
1492 pwndDesktop = UserGetDesktopWindow();
1493 MessageQueue = pti->MessageQueue;
1494 CurInfo = IntGetSysCursorInfo();
1495 pwndMsg = ValidateHwndNoErr(msg->hwnd);
1496 clk_msg = MessageQueue->msgDblClk;
1497 pDesk = pwndDesktop->head.rpdesk;
1498
1499 /* find the window to dispatch this mouse message to */
1500 if (MessageQueue->spwndCapture)
1501 {
1502 hittest = HTCLIENT;
1503 pwndMsg = MessageQueue->spwndCapture;
1504 }
1505 else
1506 {
1507 /*
1508 Start with null window. See wine win.c:test_mouse_input:WM_COMMAND tests.
1509 */
1510 pwndMsg = co_WinPosWindowFromPoint( NULL, &msg->pt, &hittest, FALSE);
1511 }
1512
1513 TRACE("Got mouse message for %p, hittest: 0x%x\n", msg->hwnd, hittest);
1514
1515 // Null window or not the same "Hardware" message queue.
1516 if (pwndMsg == NULL || pwndMsg->head.pti->MessageQueue != MessageQueue)
1517 {
1518 // Crossing a boundary, so set cursor. See default message queue cursor.
1519 IntSystemSetCursor(SYSTEMCUR(ARROW));
1520 /* Remove and ignore the message */
1521 *RemoveMessages = TRUE;
1522 return FALSE;
1523 }
1524
1525 // Check to see if this is attached,
1526 if ( pwndMsg->head.pti != pti && // window thread is not current,
1527 MessageQueue->cThreads > 1 ) // and is attached...
1528 {
1529 // This is not for us and we should leave so the other thread can check for messages!!!
1530 *NotForUs = TRUE;
1531 *RemoveMessages = TRUE;
1532 return FALSE;
1533 }
1534
1535 if ( MessageQueue == gpqCursor ) // Cursor must use the same Queue!
1536 {
1537 IntTrackMouseMove(pwndMsg, pDesk, msg, hittest);
1538 }
1539 else
1540 {
1541 ERR("Not the same cursor!\n");
1542 }
1543
1544 msg->hwnd = UserHMGetHandle(pwndMsg);
1545
1546 pt = msg->pt;
1547 message = msg->message;
1548
1549 /* Note: windows has no concept of a non-client wheel message */
1550 if (message != WM_MOUSEWHEEL)
1551 {
1552 if (hittest != HTCLIENT)
1553 {
1554 message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
1555 msg->wParam = hittest; // Caution! This might break wParam check in DblClk.
1556 }
1557 else
1558 {
1559 /* coordinates don't get translated while tracking a menu */
1560 /* FIXME: should differentiate popups and top-level menus */
1561 if (!(MessageQueue->MenuOwner))
1562 {
1563 pt.x += pwndDesktop->rcClient.left - pwndMsg->rcClient.left;
1564 pt.y += pwndDesktop->rcClient.top - pwndMsg->rcClient.top;
1565 }
1566 }
1567 }
1568 msg->lParam = MAKELONG( pt.x, pt.y );
1569
1570 /* translate double clicks */
1571
1572 if ((msg->message == WM_LBUTTONDOWN) ||
1573 (msg->message == WM_RBUTTONDOWN) ||
1574 (msg->message == WM_MBUTTONDOWN) ||
1575 (msg->message == WM_XBUTTONDOWN))
1576 {
1577 BOOL update = *RemoveMessages;
1578
1579 /* translate double clicks -
1580 * note that ...MOUSEMOVEs can slip in between
1581 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1582
1583 if ((MessageQueue->MenuOwner || MessageQueue->MoveSize) ||
1584 hittest != HTCLIENT ||
1585 (pwndMsg->pcls->style & CS_DBLCLKS))
1586 {
1587 if ((msg->message == clk_msg.message) &&
1588 (msg->hwnd == clk_msg.hwnd) &&
1589 // Only worry about XButton wParam.
1590 (msg->message != WM_XBUTTONDOWN || GET_XBUTTON_WPARAM(msg->wParam) == GET_XBUTTON_WPARAM(clk_msg.wParam)) &&
1591 ((msg->time - clk_msg.time) < (ULONG)gspv.iDblClickTime) &&
1592 (abs(msg->pt.x - clk_msg.pt.x) < UserGetSystemMetrics(SM_CXDOUBLECLK)/2) &&
1593 (abs(msg->pt.y - clk_msg.pt.y) < UserGetSystemMetrics(SM_CYDOUBLECLK)/2))
1594 {
1595 message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
1596 if (update)
1597 {
1598 MessageQueue->msgDblClk.message = 0; /* clear the double click conditions */
1599 update = FALSE;
1600 }
1601 }
1602 }
1603
1604 if (!((first == 0 && last == 0) || (message >= first || message <= last)))
1605 {
1606 TRACE("Message out of range!!!\n");
1607 return FALSE;
1608 }
1609
1610 /* update static double click conditions */
1611 if (update) MessageQueue->msgDblClk = *msg;
1612 }
1613 else
1614 {
1615 if (!((first == 0 && last == 0) || (message >= first || message <= last)))
1616 {
1617 TRACE("Message out of range!!!\n");
1618 return FALSE;
1619 }
1620
1621 // Update mouse move down keys.
1622 if (message == WM_MOUSEMOVE)
1623 {
1624 msg->wParam = MsqGetDownKeyState(MessageQueue);
1625 }
1626 }
1627
1628 if (gspv.bMouseClickLock)
1629 {
1630 BOOL IsClkLck = FALSE;
1631
1632 if(msg->message == WM_LBUTTONUP)
1633 {
1634 IsClkLck = ((msg->time - CurInfo->ClickLockTime) >= gspv.dwMouseClickLockTime);
1635 if (IsClkLck && (!CurInfo->ClickLockActive))
1636 {
1637 CurInfo->ClickLockActive = TRUE;
1638 }
1639 }
1640 else if (msg->message == WM_LBUTTONDOWN)
1641 {
1642 if (CurInfo->ClickLockActive)
1643 {
1644 IsClkLck = TRUE;
1645 CurInfo->ClickLockActive = FALSE;
1646 }
1647
1648 CurInfo->ClickLockTime = msg->time;
1649 }
1650
1651 if(IsClkLck)
1652 {
1653 /* Remove and ignore the message */
1654 *RemoveMessages = TRUE;
1655 TRACE("Remove and ignore the message\n");
1656 return FALSE;
1657 }
1658 }
1659
1660 if (pti->TIF_flags & TIF_MSGPOSCHANGED)
1661 {
1662 pti->TIF_flags &= ~TIF_MSGPOSCHANGED;
1663 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
1664 }
1665
1666 /* message is accepted now (but still get dropped) */
1667
1668 event.message = msg->message;
1669 event.time = msg->time;
1670 event.hwnd = msg->hwnd;
1671 event.paramL = msg->pt.x;
1672 event.paramH = msg->pt.y;
1673 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
1674
1675 hook.pt = msg->pt;
1676 hook.hwnd = msg->hwnd;
1677 hook.wHitTestCode = hittest;
1678 hook.dwExtraInfo = ExtraInfo;
1679 if (co_HOOK_CallHooks( WH_MOUSE, *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
1680 message, (LPARAM)&hook ))
1681 {
1682 hook.pt = msg->pt;
1683 hook.hwnd = msg->hwnd;
1684 hook.wHitTestCode = hittest;
1685 hook.dwExtraInfo = ExtraInfo;
1686 co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook );
1687
1688 ERR("WH_MOUSE dropped mouse message!\n");
1689
1690 /* Remove and skip message */
1691 *RemoveMessages = TRUE;
1692 return FALSE;
1693 }
1694
1695 if ((hittest == (USHORT)HTERROR) || (hittest == (USHORT)HTNOWHERE))
1696 {
1697 co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
1698
1699 /* Remove and skip message */
1700 *RemoveMessages = TRUE;
1701 return FALSE;
1702 }
1703
1704 if ((*RemoveMessages == FALSE) || MessageQueue->spwndCapture)
1705 {
1706 /* Accept the message */
1707 msg->message = message;
1708 return TRUE;
1709 }
1710
1711 if ((msg->message == WM_LBUTTONDOWN) ||
1712 (msg->message == WM_RBUTTONDOWN) ||
1713 (msg->message == WM_MBUTTONDOWN) ||
1714 (msg->message == WM_XBUTTONDOWN))
1715 {
1716 /* Send the WM_PARENTNOTIFY,
1717 * note that even for double/nonclient clicks
1718 * notification message is still WM_L/M/RBUTTONDOWN.
1719 */
1720 MsqSendParentNotify(pwndMsg, msg->message, 0, msg->pt );
1721
1722 /* Activate the window if needed */
1723
1724 if (pwndMsg != MessageQueue->spwndActive)
1725 {
1726 PWND pwndTop = pwndMsg;
1727 pwndTop = IntGetNonChildAncestor(pwndTop);
1728
1729 TRACE("Mouse pti %p pwndMsg pti %p pwndTop pti %p\n",MessageQueue->ptiMouse,pwndMsg->head.pti,pwndTop->head.pti);
1730
1731 if (pwndTop && pwndTop != pwndDesktop)
1732 {
1733 LONG ret = co_IntSendMessage( msg->hwnd,
1734 WM_MOUSEACTIVATE,
1735 (WPARAM)UserHMGetHandle(pwndTop),
1736 MAKELONG( hittest, msg->message));
1737 switch(ret)
1738 {
1739 case MA_NOACTIVATEANDEAT:
1740 eatMsg = TRUE;
1741 /* fall through */
1742 case MA_NOACTIVATE:
1743 break;
1744 case MA_ACTIVATEANDEAT:
1745 eatMsg = TRUE;
1746 /* fall through */
1747 case MA_ACTIVATE:
1748 case 0:
1749 if (!co_IntMouseActivateWindow( pwndTop )) eatMsg = TRUE;
1750 break;
1751 default:
1752 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret );
1753 break;
1754 }
1755 }
1756 }
1757 }
1758
1759 /* send the WM_SETCURSOR message */
1760
1761 /* Windows sends the normal mouse message as the message parameter
1762 in the WM_SETCURSOR message even if it's non-client mouse message */
1763 co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
1764
1765 msg->message = message;
1766 return !eatMsg;
1767 }
1768
1769 BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
1770 {
1771 EVENTMSG Event;
1772 USER_REFERENCE_ENTRY Ref;
1773 PWND pWnd;
1774 UINT ImmRet;
1775 BOOL Ret = TRUE;
1776 WPARAM wParam = Msg->wParam;
1777 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1778
1779 if (Msg->message == VK_PACKET)
1780 {
1781 pti->wchInjected = HIWORD(Msg->wParam);
1782 }
1783
1784 if (Msg->message == WM_KEYDOWN || Msg->message == WM_SYSKEYDOWN ||
1785 Msg->message == WM_KEYUP || Msg->message == WM_SYSKEYUP)
1786 {
1787 switch (Msg->wParam)
1788 {
1789 case VK_LSHIFT: case VK_RSHIFT:
1790 Msg->wParam = VK_SHIFT;
1791 break;
1792 case VK_LCONTROL: case VK_RCONTROL:
1793 Msg->wParam = VK_CONTROL;
1794 break;
1795 case VK_LMENU: case VK_RMENU:
1796 Msg->wParam = VK_MENU;
1797 break;
1798 }
1799 }
1800
1801 pWnd = ValidateHwndNoErr(Msg->hwnd);
1802 if (pWnd) UserRefObjectCo(pWnd, &Ref);
1803
1804 Event.message = Msg->message;
1805 Event.hwnd = Msg->hwnd;
1806 Event.time = Msg->time;
1807 Event.paramL = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8);
1808 Event.paramH = Msg->lParam & 0x7FFF;
1809 if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000;
1810 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
1811
1812 if (*RemoveMessages)
1813 {
1814 if ((Msg->message == WM_KEYDOWN) &&
1815 (Msg->hwnd != IntGetDesktopWindow()))
1816 {
1817 /* Handle F1 key by sending out WM_HELP message */
1818 if (Msg->wParam == VK_F1)
1819 {
1820 UserPostMessage( Msg->hwnd, WM_KEYF1, 0, 0 );
1821 }
1822 else if (Msg->wParam >= VK_BROWSER_BACK &&
1823 Msg->wParam <= VK_LAUNCH_APP2)
1824 {
1825 /* FIXME: Process keystate */
1826 co_IntSendMessage(Msg->hwnd, WM_APPCOMMAND, (WPARAM)Msg->hwnd, MAKELPARAM(0, (FAPPCOMMAND_KEY | (Msg->wParam - VK_BROWSER_BACK + 1))));
1827 }
1828 }
1829 else if (Msg->message == WM_KEYUP)
1830 {
1831 /* Handle VK_APPS key by posting a WM_CONTEXTMENU message */
1832 if (Msg->wParam == VK_APPS && pti->MessageQueue->MenuOwner == NULL)
1833 UserPostMessage( Msg->hwnd, WM_CONTEXTMENU, (WPARAM)Msg->hwnd, -1 );
1834 }
1835 }
1836
1837 //// Key Down!
1838 if ( *RemoveMessages && Msg->message == WM_SYSKEYDOWN )
1839 {
1840 if ( HIWORD(Msg->lParam) & KF_ALTDOWN )
1841 {
1842 if ( Msg->wParam == VK_ESCAPE || Msg->wParam == VK_TAB ) // Alt-Tab/ESC Alt-Shift-Tab/ESC
1843 {
1844 WPARAM wParamTmp;
1845
1846 wParamTmp = UserGetKeyState(VK_SHIFT) & 0x8000 ? SC_PREVWINDOW : SC_NEXTWINDOW;
1847 TRACE("Send WM_SYSCOMMAND Alt-Tab/ESC Alt-Shift-Tab/ESC\n");
1848 co_IntSendMessage( Msg->hwnd, WM_SYSCOMMAND, wParamTmp, Msg->wParam );
1849
1850 //// Keep looping.
1851 Ret = FALSE;
1852 //// Skip the rest.
1853 goto Exit;
1854 }
1855 }
1856 }
1857
1858 if ( *RemoveMessages && (Msg->message == WM_SYSKEYDOWN || Msg->message == WM_KEYDOWN) )
1859 {
1860 if (gdwLanguageToggleKey < 3)
1861 {
1862 if (IS_KEY_DOWN(gafAsyncKeyState, gdwLanguageToggleKey == 1 ? VK_LMENU : VK_CONTROL)) // L Alt 1 or Ctrl 2 .
1863 {
1864 if ( wParam == VK_LSHIFT ) gLanguageToggleKeyState = INPUTLANGCHANGE_FORWARD; // Left Alt - Left Shift, Next
1865 //// FIXME : It seems to always be VK_LSHIFT.
1866 if ( wParam == VK_RSHIFT ) gLanguageToggleKeyState = INPUTLANGCHANGE_BACKWARD; // Left Alt - Right Shift, Previous
1867 }
1868 }
1869 }
1870
1871 //// Key Up! Alt Key Ctrl Key
1872 if ( *RemoveMessages && (Msg->message == WM_SYSKEYUP || Msg->message == WM_KEYUP) )
1873 {
1874 // When initializing win32k: Reading from the registry hotkey combination
1875 // to switch the keyboard layout and store it to global variable.
1876 // Using this combination of hotkeys in this function
1877
1878 if ( gdwLanguageToggleKey < 3 &&
1879 IS_KEY_DOWN(gafAsyncKeyState, gdwLanguageToggleKey == 1 ? VK_LMENU : VK_CONTROL) )
1880 {
1881 if ( Msg->wParam == VK_SHIFT && !(IS_KEY_DOWN(gafAsyncKeyState, VK_SHIFT)))
1882 {
1883 WPARAM wParamILR;
1884 PKL pkl = pti->KeyboardLayout;
1885
1886 if (pWnd) UserDerefObjectCo(pWnd);
1887
1888 //// Seems to override message window.
1889 if (!(pWnd = pti->MessageQueue->spwndFocus))
1890 {
1891 pWnd = pti->MessageQueue->spwndActive;
1892 }
1893 if (pWnd) UserRefObjectCo(pWnd, &Ref);
1894
1895 if (pkl != NULL && gLanguageToggleKeyState)
1896 {
1897 TRACE("Posting WM_INPUTLANGCHANGEREQUEST KeyState %d\n", gLanguageToggleKeyState );
1898
1899 wParamILR = gLanguageToggleKeyState;
1900 // If system character set and font signature send flag.
1901 if ( gSystemFS & pkl->dwFontSigs )
1902 {
1903 wParamILR |= INPUTLANGCHANGE_SYSCHARSET;
1904 }
1905
1906 UserPostMessage( UserHMGetHandle(pWnd),
1907 WM_INPUTLANGCHANGEREQUEST,
1908 wParamILR,
1909 (LPARAM)pkl->hkl );
1910
1911 gLanguageToggleKeyState = 0;
1912 //// Keep looping.
1913 Ret = FALSE;
1914 //// Skip the rest.
1915 goto Exit;
1916 }
1917 }
1918 }
1919 }
1920
1921 if (co_HOOK_CallHooks( WH_KEYBOARD,
1922 *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
1923 LOWORD(Msg->wParam),
1924 Msg->lParam))
1925 {
1926 /* skip this message */
1927 co_HOOK_CallHooks( WH_CBT,
1928 HCBT_KEYSKIPPED,
1929 LOWORD(Msg->wParam),
1930 Msg->lParam );
1931
1932 ERR("KeyboardMessage WH_KEYBOARD Call Hook return!\n");
1933
1934 *RemoveMessages = TRUE;
1935
1936 Ret = FALSE;
1937 }
1938
1939 if ( pWnd && Ret && *RemoveMessages && Msg->message == WM_KEYDOWN && !(pti->TIF_flags & TIF_DISABLEIME))
1940 {
1941 if ( (ImmRet = IntImmProcessKey(pti->MessageQueue, pWnd, Msg->message, Msg->wParam, Msg->lParam)) )
1942 {
1943 if ( ImmRet & (IPHK_HOTKEY|IPHK_SKIPTHISKEY) )
1944 {
1945 ImmRet = 0;
1946 }
1947 if ( ImmRet & IPHK_PROCESSBYIME )
1948 {
1949 Msg->wParam = VK_PROCESSKEY;
1950 }
1951 }
1952 }
1953 Exit:
1954 if (pWnd) UserDerefObjectCo(pWnd);
1955 return Ret;
1956 }
1957
1958 BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, BOOL* NotForUs, LONG_PTR ExtraInfo, UINT first, UINT last)
1959 {
1960 if ( IS_MOUSE_MESSAGE(Msg->message))
1961 {
1962 return co_IntProcessMouseMessage(Msg, RemoveMessages, NotForUs, ExtraInfo, first, last);
1963 }
1964 else if ( IS_KBD_MESSAGE(Msg->message))
1965 {
1966 return co_IntProcessKeyboardMessage(Msg, RemoveMessages);
1967 }
1968
1969 return TRUE;
1970 }
1971
1972 /* check whether a message filter contains at least one potential hardware message */
1973 static INT FASTCALL
1974 filter_contains_hw_range( UINT first, UINT last )
1975 {
1976 /* hardware message ranges are (in numerical order):
1977 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1978 * WM_KEYFIRST .. WM_KEYLAST
1979 * WM_MOUSEFIRST .. WM_MOUSELAST
1980 */
1981 if (!last) --last;
1982 if (last < WM_NCMOUSEFIRST) return 0;
1983 if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0;
1984 if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0;
1985 if (first > WM_MOUSELAST) return 0;
1986 return 1;
1987 }
1988
1989 /* check whether message is in the range of mouse messages */
1990 static inline BOOL is_mouse_message( UINT message )
1991 {
1992 return ( //( message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST ) || This seems to break tests...
1993 ( message >= WM_MOUSEFIRST && message <= WM_MOUSELAST ) ||
1994 ( message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK ) ||
1995 ( message >= WM_MBUTTONDOWN && message <= WM_MBUTTONDBLCLK ) ||
1996 ( message >= WM_LBUTTONDOWN && message <= WM_RBUTTONDBLCLK ) );
1997 }
1998
1999 BOOL APIENTRY
2000 co_MsqPeekHardwareMessage(IN PTHREADINFO pti,
2001 IN BOOL Remove,
2002 IN PWND Window,
2003 IN UINT MsgFilterLow,
2004 IN UINT MsgFilterHigh,
2005 IN UINT QSflags,
2006 OUT MSG* pMsg)
2007 {
2008 BOOL AcceptMessage, NotForUs;
2009 PUSER_MESSAGE CurrentMessage;
2010 PLIST_ENTRY ListHead;
2011 MSG msg;
2012 ULONG_PTR idSave;
2013 DWORD QS_Flags;
2014 LONG_PTR ExtraInfo;
2015 BOOL Ret = FALSE;
2016 PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
2017
2018 if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE;
2019
2020 ListHead = MessageQueue->HardwareMessagesListHead.Flink;
2021
2022 if (IsListEmpty(ListHead)) return FALSE;
2023
2024 if (!MessageQueue->ptiSysLock)
2025 {
2026 MessageQueue->ptiSysLock = pti;
2027 pti->pcti->CTI_flags |= CTI_THREADSYSLOCK;
2028 }
2029
2030 if (MessageQueue->ptiSysLock != pti)
2031 {
2032 ERR("Thread Q is locked to ptiSysLock 0x%p pti 0x%p\n",MessageQueue->ptiSysLock,pti);
2033 return FALSE;
2034 }
2035
2036 while (ListHead != &MessageQueue->HardwareMessagesListHead)
2037 {
2038 CurrentMessage = CONTAINING_RECORD(ListHead, USER_MESSAGE, ListEntry);
2039 ListHead = ListHead->Flink;
2040
2041 if (MessageQueue->idSysPeek == (ULONG_PTR)CurrentMessage)
2042 {
2043 TRACE("Skip this message due to it is in play!\n");
2044 continue;
2045 }
2046 /*
2047 MSDN:
2048 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
2049 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
2050 3: handle to the window whose messages are to be retrieved.
2051 */
2052 if ( ( !Window || // 1
2053 ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
2054 ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) || // 3
2055 ( is_mouse_message(CurrentMessage->Msg.message) ) ) && // Null window for anything mouse.
2056 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
2057 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
2058 {
2059 idSave = MessageQueue->idSysPeek;
2060 MessageQueue->idSysPeek = (ULONG_PTR)CurrentMessage;
2061
2062 msg = CurrentMessage->Msg;
2063 ExtraInfo = CurrentMessage->ExtraInfo;
2064 QS_Flags = CurrentMessage->QS_Flags;
2065
2066 NotForUs = FALSE;
2067
2068 UpdateKeyStateFromMsg(MessageQueue, &msg);
2069 AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, &NotForUs, ExtraInfo, MsgFilterLow, MsgFilterHigh);
2070
2071 if (Remove)
2072 {
2073 if (CurrentMessage->pti != NULL && (MessageQueue->idSysPeek == (ULONG_PTR)CurrentMessage))
2074 {
2075 MsqDestroyMessage(CurrentMessage);
2076 }
2077 ClearMsgBitsMask(pti, QS_Flags);
2078 }
2079
2080 MessageQueue->idSysPeek = idSave;
2081
2082 if (NotForUs)
2083 {
2084 Ret = FALSE;
2085 break;
2086 }
2087
2088 if (AcceptMessage)
2089 {
2090 *pMsg = msg;
2091 // Fix all but one wine win:test_GetMessagePos WM_TIMER tests. See PostTimerMessages.
2092 if (!RtlEqualMemory(&pti->ptLast, &msg.pt, sizeof(POINT)))
2093 {
2094 pti->TIF_flags |= TIF_MSGPOSCHANGED;
2095 }
2096 pti->ptLast = msg.pt;
2097 pti->timeLast = msg.time;
2098 MessageQueue->ExtraInfo = ExtraInfo;
2099 Ret = TRUE;
2100 break;
2101 }
2102 }
2103 }
2104
2105 MessageQueue->ptiSysLock = NULL;
2106 pti->pcti->CTI_flags &= ~CTI_THREADSYSLOCK;
2107 return Ret;
2108 }
2109
2110 BOOLEAN APIENTRY
2111 MsqPeekMessage(IN PTHREADINFO pti,
2112 IN BOOLEAN Remove,
2113 IN PWND Window,
2114 IN UINT MsgFilterLow,
2115 IN UINT MsgFilterHigh,
2116 IN UINT QSflags,
2117 OUT LONG_PTR *ExtraInfo,
2118 OUT DWORD *dwQEvent,
2119 OUT PMSG Message)
2120 {
2121 PUSER_MESSAGE CurrentMessage;
2122 PLIST_ENTRY ListHead;
2123 DWORD QS_Flags;
2124 BOOL Ret = FALSE;
2125
2126 ListHead = pti->PostedMessagesListHead.Flink;
2127
2128 if (IsListEmpty(ListHead)) return FALSE;
2129
2130 while(ListHead != &pti->PostedMessagesListHead)
2131 {
2132 CurrentMessage = CONTAINING_RECORD(ListHead, USER_MESSAGE, ListEntry);
2133 ListHead = ListHead->Flink;
2134 /*
2135 MSDN:
2136 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
2137 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
2138 3: handle to the window whose messages are to be retrieved.
2139 */
2140 if ( ( !Window || // 1
2141 ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
2142 ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3
2143 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
2144 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
2145 {
2146 *Message = CurrentMessage->Msg;
2147 *ExtraInfo = CurrentMessage->ExtraInfo;
2148 QS_Flags = CurrentMessage->QS_Flags;
2149 if (dwQEvent) *dwQEvent = CurrentMessage->dwQEvent;
2150
2151 if (Remove)
2152 {
2153 if (CurrentMessage->pti != NULL)
2154 {
2155 MsqDestroyMessage(CurrentMessage);
2156 }
2157 ClearMsgBitsMask(pti, QS_Flags);
2158 }
2159 Ret = TRUE;
2160 break;
2161 }
2162 }
2163
2164 return Ret;
2165 }
2166
2167 NTSTATUS FASTCALL
2168 co_MsqWaitForNewMessages(PTHREADINFO pti, PWND WndFilter,
2169 UINT MsgFilterMin, UINT MsgFilterMax)
2170 {
2171 NTSTATUS ret = STATUS_SUCCESS;
2172
2173 // Post mouse moves before waiting for messages.
2174 if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED)
2175 {
2176 IntCoalesceMouseMove(pti);
2177 }
2178
2179 UserLeaveCo();
2180
2181 ZwYieldExecution(); // Let someone else run!
2182
2183 ret = KeWaitForSingleObject( pti->pEventQueueServer,
2184 UserRequest,
2185 UserMode,
2186 FALSE,
2187 NULL );
2188 UserEnterCo();
2189 if ( ret == STATUS_USER_APC )
2190 {
2191 TRACE("MWFNW User APC\n");
2192 co_IntDeliverUserAPC();
2193 }
2194 return ret;
2195 }
2196
2197 BOOL FASTCALL
2198 MsqIsHung(PTHREADINFO pti)
2199 {
2200 LARGE_INTEGER LargeTickCount;
2201
2202 KeQueryTickCount(&LargeTickCount);
2203
2204 if ((LargeTickCount.u.LowPart - pti->timeLast) > MSQ_HUNG &&
2205 !(pti->pcti->fsWakeMask & QS_INPUT) &&
2206 !PsGetThreadFreezeCount(pti->pEThread) &&
2207 !(pti->ppi->W32PF_flags & W32PF_APPSTARTING))
2208 return TRUE;
2209
2210 return FALSE;
2211 }
2212
2213 BOOL FASTCALL
2214 IsThreadSuspended(PTHREADINFO pti)
2215 {
2216 if (pti->pEThread)
2217 {
2218 BOOL Ret = TRUE;
2219 if (!(pti->pEThread->Tcb.SuspendCount) && !PsGetThreadFreezeCount(pti->pEThread)) Ret = FALSE;
2220 return Ret;
2221 }
2222 return FALSE;
2223 }
2224
2225 VOID
2226 CALLBACK
2227 HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
2228 {
2229 DoTheScreenSaver();
2230 TRACE("HungAppSysTimerProc\n");
2231 // Process list of windows that are hung and waiting.
2232 }
2233
2234 BOOLEAN FASTCALL
2235 MsqInitializeMessageQueue(PTHREADINFO pti, PUSER_MESSAGE_QUEUE MessageQueue)
2236 {
2237 InitializeListHead(&MessageQueue->HardwareMessagesListHead); // Keep here!
2238 MessageQueue->spwndFocus = NULL;
2239 MessageQueue->iCursorLevel = 0;
2240 MessageQueue->CursorObject = SYSTEMCUR(WAIT); // See test_initial_cursor.
2241 if (MessageQueue->CursorObject)
2242 {
2243 TRACE("Default cursor hcur %p\n",UserHMGetHandle(MessageQueue->CursorObject));
2244 UserReferenceObject(MessageQueue->CursorObject);
2245 }
2246 RtlCopyMemory(MessageQueue->afKeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState));
2247 MessageQueue->ptiMouse = pti;
2248 MessageQueue->ptiKeyboard = pti;
2249 MessageQueue->cThreads++;
2250
2251 return TRUE;
2252 }
2253
2254 VOID FASTCALL
2255 MsqCleanupThreadMsgs(PTHREADINFO pti)
2256 {
2257 PLIST_ENTRY CurrentEntry;
2258 PUSER_MESSAGE CurrentMessage;
2259 PUSER_SENT_MESSAGE CurrentSentMessage;
2260
2261 TRACE("MsqCleanupThreadMsgs %p\n",pti);
2262
2263 // Clear it all out.
2264 if (pti->pcti)
2265 {
2266 pti->pcti->fsWakeBits = 0;
2267 pti->pcti->fsChangeBits = 0;
2268 }
2269
2270 pti->nCntsQBits[QSRosKey] = 0;
2271 pti->nCntsQBits[QSRosMouseMove] = 0;
2272 pti->nCntsQBits[QSRosMouseButton] = 0;
2273 pti->nCntsQBits[QSRosPostMessage] = 0;
2274 pti->nCntsQBits[QSRosSendMessage] = 0;
2275 pti->nCntsQBits[QSRosHotKey] = 0;
2276 pti->nCntsQBits[QSRosEvent] = 0;
2277
2278 /* cleanup posted messages */
2279 while (!IsListEmpty(&pti->PostedMessagesListHead))
2280 {
2281 CurrentEntry = pti->PostedMessagesListHead.Flink;
2282 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
2283 ERR("Thread Cleanup Post Messages %p\n",CurrentMessage);
2284 if (CurrentMessage->dwQEvent)
2285 {
2286 if (CurrentMessage->dwQEvent == POSTEVENT_NWE)
2287 {
2288 ExFreePoolWithTag( (PVOID)CurrentMessage->ExtraInfo, TAG_HOOK);
2289 }
2290 }
2291 MsqDestroyMessage(CurrentMessage);
2292 }
2293
2294 /* remove the messages that have not yet been dispatched */
2295 while (!IsListEmpty(&pti->SentMessagesListHead))
2296 {
2297 CurrentEntry = pti->SentMessagesListHead.Flink;
2298 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
2299
2300 ERR("Thread Cleanup Sent Messages %p\n",CurrentSentMessage);
2301
2302 /* wake the sender's thread */
2303 if (CurrentSentMessage->pkCompletionEvent != NULL)
2304 {
2305 KeSetEvent(CurrentSentMessage->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
2306 }
2307
2308 if (CurrentSentMessage->HasPackedLParam)
2309 {
2310 if (CurrentSentMessage->Msg.lParam)
2311 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
2312 }
2313
2314 /* free the message */
2315 FreeUserMessage(CurrentSentMessage);
2316 }
2317
2318 // Process Trouble Message List
2319 if (!IsListEmpty(&usmList))
2320 {
2321 CurrentEntry = usmList.Flink;
2322 while (CurrentEntry != &usmList)
2323 {
2324 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
2325 CurrentEntry = CurrentEntry->Flink;
2326
2327 TRACE("Found troubled messages %p on the list\n",CurrentSentMessage);
2328
2329 if ( pti == CurrentSentMessage->ptiReceiver )
2330 {
2331 if (CurrentSentMessage->HasPackedLParam)
2332 {
2333 if (CurrentSentMessage->Msg.lParam)
2334 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
2335 }
2336
2337 /* free the message */
2338 FreeUserMessage(CurrentSentMessage);
2339 }
2340 else if ( pti == CurrentSentMessage->ptiSender ||
2341 pti == CurrentSentMessage->ptiCallBackSender )
2342 {
2343 // Determine whether this message is being processed or not.
2344 if ((CurrentSentMessage->flags & (SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE)) != SMF_RECEIVEDMESSAGE)
2345 {
2346 CurrentSentMessage->flags |= SMF_RECEIVERFREE;
2347 }
2348
2349 if (!(CurrentSentMessage->flags & SMF_RECEIVERFREE))
2350 {
2351
2352 if (CurrentSentMessage->HasPackedLParam)
2353 {
2354 if (CurrentSentMessage->Msg.lParam)
2355 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
2356 }
2357
2358 /* free the message */
2359 FreeUserMessage(CurrentSentMessage);
2360 }
2361 }
2362 }
2363 }
2364 }
2365
2366 VOID FASTCALL
2367 MsqCleanupMessageQueue(PTHREADINFO pti)
2368 {
2369 PUSER_MESSAGE_QUEUE MessageQueue;
2370 PLIST_ENTRY CurrentEntry;
2371 PUSER_MESSAGE CurrentMessage;
2372
2373 MessageQueue = pti->MessageQueue;
2374 MessageQueue->cThreads--;
2375
2376 if (MessageQueue->cThreads)
2377 {
2378 if (MessageQueue->ptiSysLock == pti) MessageQueue->ptiSysLock = NULL;
2379 }
2380
2381 if (MessageQueue->cThreads == 0) //// Fix a crash related to CORE-10471 testing.
2382 {
2383 /* cleanup posted messages */
2384 while (!IsListEmpty(&MessageQueue->HardwareMessagesListHead))
2385 {
2386 CurrentEntry = MessageQueue->HardwareMessagesListHead.Flink;
2387 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
2388 ERR("MQ Cleanup Post Messages %p\n",CurrentMessage);
2389 MsqDestroyMessage(CurrentMessage);
2390 }
2391 } ////
2392
2393 if (MessageQueue->CursorObject)
2394 {
2395 PCURICON_OBJECT pCursor = MessageQueue->CursorObject;
2396
2397 /* Change to another cursor if we going to dereference current one
2398 Note: we can't use UserSetCursor because it uses current thread
2399 message queue instead of queue given for cleanup */
2400 if (IntGetSysCursorInfo()->CurrentCursorObject == pCursor)
2401 {
2402 HDC hdcScreen;
2403
2404 /* Get the screen DC */
2405 hdcScreen = IntGetScreenDC();
2406 if (hdcScreen)
2407 GreMovePointer(hdcScreen, -1, -1);
2408 IntGetSysCursorInfo()->CurrentCursorObject = NULL;
2409 }
2410
2411 TRACE("DereferenceObject pCursor\n");
2412 UserDereferenceObject(pCursor);
2413 }
2414
2415 if (gpqForeground == MessageQueue)
2416 {
2417 IntSetFocusMessageQueue(NULL);
2418 }
2419 if (gpqForegroundPrev == MessageQueue)
2420 {
2421 gpqForegroundPrev = NULL;
2422 }
2423 if (gpqCursor == MessageQueue)
2424 {
2425 gpqCursor = NULL;
2426 }
2427 }
2428
2429 PUSER_MESSAGE_QUEUE FASTCALL
2430 MsqCreateMessageQueue(PTHREADINFO pti)
2431 {
2432 PUSER_MESSAGE_QUEUE MessageQueue;
2433
2434 MessageQueue = ExAllocatePoolWithTag(NonPagedPool,
2435 sizeof(*MessageQueue),
2436 USERTAG_Q);
2437
2438 if (!MessageQueue)
2439 {
2440 return NULL;
2441 }
2442
2443 RtlZeroMemory(MessageQueue, sizeof(*MessageQueue));
2444 /* hold at least one reference until it'll be destroyed */
2445 IntReferenceMessageQueue(MessageQueue);
2446 /* initialize the queue */
2447 if (!MsqInitializeMessageQueue(pti, MessageQueue))
2448 {
2449 IntDereferenceMessageQueue(MessageQueue);
2450 return NULL;
2451 }
2452
2453 return MessageQueue;
2454 }
2455
2456 VOID FASTCALL
2457 MsqDestroyMessageQueue(_In_ PTHREADINFO pti)
2458 {
2459 PDESKTOP desk;
2460 PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
2461
2462 NT_ASSERT(MessageQueue != NULL);
2463 MessageQueue->QF_flags |= QF_INDESTROY;
2464
2465 /* remove the message queue from any desktops */
2466 if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0)))
2467 {
2468 (void)InterlockedExchangePointer((PVOID*)&desk->ActiveMessageQueue, 0);
2469 IntDereferenceMessageQueue(MessageQueue);
2470 }
2471
2472 /* clean it up */
2473 MsqCleanupMessageQueue(pti);
2474
2475 /* decrease the reference counter, if it hits zero, the queue will be freed */
2476 _PRAGMA_WARNING_SUPPRESS(__WARNING_USING_UNINIT_VAR);
2477 IntDereferenceMessageQueue(MessageQueue);
2478 }
2479
2480 LPARAM FASTCALL
2481 MsqSetMessageExtraInfo(LPARAM lParam)
2482 {
2483 LPARAM Ret;
2484 PTHREADINFO pti;
2485 PUSER_MESSAGE_QUEUE MessageQueue;
2486
2487 pti = PsGetCurrentThreadWin32Thread();
2488 MessageQueue = pti->MessageQueue;
2489 if(!MessageQueue)
2490 {
2491 return 0;
2492 }
2493
2494 Ret = MessageQueue->ExtraInfo;
2495 MessageQueue->ExtraInfo = lParam;
2496
2497 return Ret;
2498 }
2499
2500 LPARAM FASTCALL
2501 MsqGetMessageExtraInfo(VOID)
2502 {
2503 PTHREADINFO pti;
2504 PUSER_MESSAGE_QUEUE MessageQueue;
2505
2506 pti = PsGetCurrentThreadWin32Thread();
2507 MessageQueue = pti->MessageQueue;
2508 if(!MessageQueue)
2509 {
2510 return 0;
2511 }
2512
2513 return MessageQueue->ExtraInfo;
2514 }
2515
2516 // ReplyMessage is called by the thread receiving the window message.
2517 BOOL FASTCALL
2518 co_MsqReplyMessage( LRESULT lResult )
2519 {
2520 PUSER_SENT_MESSAGE Message;
2521 PTHREADINFO pti;
2522
2523 pti = PsGetCurrentThreadWin32Thread();
2524 Message = pti->pusmCurrent;
2525
2526 if (!Message) return FALSE;
2527
2528 if (Message->QS_Flags & QS_SMRESULT) return FALSE;
2529
2530 // SendMessageXxx || Callback msg and not a notify msg
2531 if (Message->ptiSender || Message->CompletionCallback)
2532 {
2533 Message->lResult = lResult;
2534 Message->QS_Flags |= QS_SMRESULT;
2535 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2536 }
2537 return TRUE;
2538 }
2539
2540 HWND FASTCALL
2541 MsqSetStateWindow(PTHREADINFO pti, ULONG Type, HWND hWnd)
2542 {
2543 HWND Prev;
2544 PUSER_MESSAGE_QUEUE MessageQueue;
2545
2546 MessageQueue = pti->MessageQueue;
2547
2548 switch(Type)
2549 {
2550 case MSQ_STATE_CAPTURE:
2551 Prev = MessageQueue->spwndCapture ? UserHMGetHandle(MessageQueue->spwndCapture) : 0;
2552 MessageQueue->spwndCapture = ValidateHwndNoErr(hWnd);
2553 return Prev;
2554 case MSQ_STATE_ACTIVE:
2555 Prev = MessageQueue->spwndActive ? UserHMGetHandle(MessageQueue->spwndActive) : 0;
2556 MessageQueue->spwndActive = ValidateHwndNoErr(hWnd);
2557 return Prev;
2558 case MSQ_STATE_FOCUS:
2559 Prev = MessageQueue->spwndFocus ? UserHMGetHandle(MessageQueue->spwndFocus) : 0;
2560 MessageQueue->spwndFocus = ValidateHwndNoErr(hWnd);
2561 return Prev;
2562 case MSQ_STATE_MENUOWNER:
2563 Prev = MessageQueue->MenuOwner;
2564 MessageQueue->MenuOwner = hWnd;
2565 return Prev;
2566 case MSQ_STATE_MOVESIZE:
2567 Prev = MessageQueue->MoveSize;
2568 MessageQueue->MoveSize = hWnd;
2569 return Prev;
2570 case MSQ_STATE_CARET:
2571 Prev = MessageQueue->CaretInfo.hWnd;
2572 MessageQueue->CaretInfo.hWnd = hWnd;
2573 return Prev;
2574 }
2575
2576 return NULL;
2577 }
2578
2579 SHORT
2580 APIENTRY
2581 NtUserGetKeyState(INT key)
2582 {
2583 DWORD Ret;
2584
2585 UserEnterShared();
2586
2587 Ret = UserGetKeyState(key);
2588
2589 UserLeave();
2590
2591 return (SHORT)Ret;
2592 }
2593
2594
2595 DWORD
2596 APIENTRY
2597 NtUserGetKeyboardState(LPBYTE lpKeyState)
2598 {
2599 DWORD i, ret = TRUE;
2600 PTHREADINFO pti;
2601 PUSER_MESSAGE_QUEUE MessageQueue;
2602
2603 UserEnterShared();
2604
2605 pti = PsGetCurrentThreadWin32Thread();
2606 MessageQueue = pti->MessageQueue;
2607
2608 _SEH2_TRY
2609 {
2610 /* Probe and copy key state to an array */
2611 ProbeForWrite(lpKeyState, 256 * sizeof(BYTE), 1);
2612 for (i = 0; i < 256; ++i)
2613 {
2614 lpKeyState[i] = 0;
2615 if (IS_KEY_DOWN(MessageQueue->afKeyState, i))
2616 lpKeyState[i] |= KS_DOWN_BIT;
2617 if (IS_KEY_LOCKED(MessageQueue->afKeyState, i))
2618 lpKeyState[i] |= KS_LOCK_BIT;
2619 }
2620 }
2621 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2622 {
2623 SetLastNtError(_SEH2_GetExceptionCode());
2624 ret = FALSE;
2625 }
2626 _SEH2_END;
2627
2628 UserLeave();
2629
2630 return ret;
2631 }
2632
2633 BOOL
2634 APIENTRY
2635 NtUserSetKeyboardState(LPBYTE pKeyState)
2636 {
2637 UINT i;
2638 BOOL bRet = TRUE;
2639 PTHREADINFO pti;
2640 PUSER_MESSAGE_QUEUE MessageQueue;
2641
2642 UserEnterExclusive();
2643
2644 pti = PsGetCurrentThreadWin32Thread();
2645 MessageQueue = pti->MessageQueue;
2646
2647 _SEH2_TRY
2648 {
2649 ProbeForRead(pKeyState, 256 * sizeof(BYTE), 1);
2650 for (i = 0; i < 256; ++i)
2651 {
2652 SET_KEY_DOWN(MessageQueue->afKeyState, i, pKeyState[i] & KS_DOWN_BIT);
2653 SET_KEY_LOCKED(MessageQueue->afKeyState, i, pKeyState[i] & KS_LOCK_BIT);
2654 }
2655 }
2656 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2657 {
2658 SetLastNtError(_SEH2_GetExceptionCode());
2659 bRet = FALSE;
2660 }
2661 _SEH2_END;
2662
2663 UserLeave();
2664
2665 return bRet;
2666 }
2667
2668 /* EOF */