This patch removes the cursor location from the window station object and always...
[reactos.git] / reactos / subsys / win32k / ntuser / message.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Messages
24 * FILE: subsys/win32k/ntuser/message.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29
30 /* INCLUDES ******************************************************************/
31
32 #include <w32k.h>
33
34 #define NDEBUG
35 #include <debug.h>
36
37 typedef struct
38 {
39 UINT uFlags;
40 UINT uTimeout;
41 ULONG_PTR Result;
42 } DOSENDMESSAGE, *PDOSENDMESSAGE;
43
44 /* FUNCTIONS *****************************************************************/
45
46 NTSTATUS FASTCALL
47 IntInitMessageImpl(VOID)
48 {
49 return STATUS_SUCCESS;
50 }
51
52 NTSTATUS FASTCALL
53 IntCleanupMessageImpl(VOID)
54 {
55 return STATUS_SUCCESS;
56 }
57
58 #define MMS_SIZE_WPARAM -1
59 #define MMS_SIZE_WPARAMWCHAR -2
60 #define MMS_SIZE_LPARAMSZ -3
61 #define MMS_SIZE_SPECIAL -4
62 #define MMS_FLAG_READ 0x01
63 #define MMS_FLAG_WRITE 0x02
64 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
65 typedef struct tagMSGMEMORY
66 {
67 UINT Message;
68 UINT Size;
69 INT Flags;
70 } MSGMEMORY, *PMSGMEMORY;
71
72 static MSGMEMORY MsgMemory[] =
73 {
74 { WM_CREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
75 { WM_DDE_ACK, sizeof(KMDDELPARAM), MMS_FLAG_READ },
76 { WM_DDE_EXECUTE, MMS_SIZE_WPARAM, MMS_FLAG_READ },
77 { WM_GETMINMAXINFO, sizeof(MINMAXINFO), MMS_FLAG_READWRITE },
78 { WM_GETTEXT, MMS_SIZE_WPARAMWCHAR, MMS_FLAG_WRITE },
79 { WM_NCCALCSIZE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
80 { WM_NCCREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
81 { WM_SETTEXT, MMS_SIZE_LPARAMSZ, MMS_FLAG_READ },
82 { WM_STYLECHANGED, sizeof(STYLESTRUCT), MMS_FLAG_READ },
83 { WM_STYLECHANGING, sizeof(STYLESTRUCT), MMS_FLAG_READWRITE },
84 { WM_COPYDATA, MMS_SIZE_SPECIAL, MMS_FLAG_READ },
85 { WM_WINDOWPOSCHANGED, sizeof(WINDOWPOS), MMS_FLAG_READ },
86 { WM_WINDOWPOSCHANGING, sizeof(WINDOWPOS), MMS_FLAG_READWRITE },
87 };
88
89 static PMSGMEMORY FASTCALL
90 FindMsgMemory(UINT Msg)
91 {
92 PMSGMEMORY MsgMemoryEntry;
93
94 /* See if this message type is present in the table */
95 for (MsgMemoryEntry = MsgMemory;
96 MsgMemoryEntry < MsgMemory + sizeof(MsgMemory) / sizeof(MSGMEMORY);
97 MsgMemoryEntry++)
98 {
99 if (Msg == MsgMemoryEntry->Message)
100 {
101 return MsgMemoryEntry;
102 }
103 }
104
105 return NULL;
106 }
107
108 static UINT FASTCALL
109 MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
110 {
111 CREATESTRUCTW *Cs;
112 PUNICODE_STRING WindowName;
113 PUNICODE_STRING ClassName;
114 UINT Size;
115
116 if (MMS_SIZE_WPARAM == MsgMemoryEntry->Size)
117 {
118 return (UINT) wParam;
119 }
120 else if (MMS_SIZE_WPARAMWCHAR == MsgMemoryEntry->Size)
121 {
122 return (UINT) (wParam * sizeof(WCHAR));
123 }
124 else if (MMS_SIZE_LPARAMSZ == MsgMemoryEntry->Size)
125 {
126 return (UINT) ((wcslen((PWSTR) lParam) + 1) * sizeof(WCHAR));
127 }
128 else if (MMS_SIZE_SPECIAL == MsgMemoryEntry->Size)
129 {
130 switch(MsgMemoryEntry->Message)
131 {
132 case WM_CREATE:
133 case WM_NCCREATE:
134 Cs = (CREATESTRUCTW *) lParam;
135 WindowName = (PUNICODE_STRING) Cs->lpszName;
136 ClassName = (PUNICODE_STRING) Cs->lpszClass;
137 Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
138 if (IS_ATOM(ClassName->Buffer))
139 {
140 Size += sizeof(WCHAR) + sizeof(ATOM);
141 }
142 else
143 {
144 Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
145 }
146 return Size;
147 break;
148
149 case WM_NCCALCSIZE:
150 return wParam ? sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS) : sizeof(RECT);
151 break;
152
153 case WM_COPYDATA:
154 return sizeof(COPYDATASTRUCT) + ((PCOPYDATASTRUCT)lParam)->cbData;
155
156 default:
157 assert(FALSE);
158 return 0;
159 break;
160 }
161 }
162 else
163 {
164 return MsgMemoryEntry->Size;
165 }
166 }
167
168 static FASTCALL NTSTATUS
169 PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
170 {
171 NCCALCSIZE_PARAMS *UnpackedNcCalcsize;
172 NCCALCSIZE_PARAMS *PackedNcCalcsize;
173 CREATESTRUCTW *UnpackedCs;
174 CREATESTRUCTW *PackedCs;
175 PUNICODE_STRING WindowName;
176 PUNICODE_STRING ClassName;
177 UINT Size;
178 PCHAR CsData;
179
180 *lParamPacked = lParam;
181 if (WM_NCCALCSIZE == Msg && wParam)
182 {
183 UnpackedNcCalcsize = (NCCALCSIZE_PARAMS *) lParam;
184 if (UnpackedNcCalcsize->lppos != (PWINDOWPOS) (UnpackedNcCalcsize + 1))
185 {
186 PackedNcCalcsize = ExAllocatePoolWithTag(PagedPool,
187 sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS),
188 TAG_MSG);
189 if (NULL == PackedNcCalcsize)
190 {
191 DPRINT1("Not enough memory to pack lParam\n");
192 return STATUS_NO_MEMORY;
193 }
194 RtlCopyMemory(PackedNcCalcsize, UnpackedNcCalcsize, sizeof(NCCALCSIZE_PARAMS));
195 PackedNcCalcsize->lppos = (PWINDOWPOS) (PackedNcCalcsize + 1);
196 RtlCopyMemory(PackedNcCalcsize->lppos, UnpackedNcCalcsize->lppos, sizeof(WINDOWPOS));
197 *lParamPacked = (LPARAM) PackedNcCalcsize;
198 }
199 }
200 else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
201 {
202 UnpackedCs = (CREATESTRUCTW *) lParam;
203 WindowName = (PUNICODE_STRING) UnpackedCs->lpszName;
204 ClassName = (PUNICODE_STRING) UnpackedCs->lpszClass;
205 Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
206 if (IS_ATOM(ClassName->Buffer))
207 {
208 Size += sizeof(WCHAR) + sizeof(ATOM);
209 }
210 else
211 {
212 Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
213 }
214 PackedCs = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
215 if (NULL == PackedCs)
216 {
217 DPRINT1("Not enough memory to pack lParam\n");
218 return STATUS_NO_MEMORY;
219 }
220 RtlCopyMemory(PackedCs, UnpackedCs, sizeof(CREATESTRUCTW));
221 CsData = (PCHAR) (PackedCs + 1);
222 PackedCs->lpszName = (LPCWSTR) (CsData - (PCHAR) PackedCs);
223 RtlCopyMemory(CsData, WindowName->Buffer, WindowName->Length);
224 CsData += WindowName->Length;
225 *((WCHAR *) CsData) = L'\0';
226 CsData += sizeof(WCHAR);
227 PackedCs->lpszClass = (LPCWSTR) (CsData - (PCHAR) PackedCs);
228 if (IS_ATOM(ClassName->Buffer))
229 {
230 *((WCHAR *) CsData) = L'A';
231 CsData += sizeof(WCHAR);
232 *((ATOM *) CsData) = (ATOM)(DWORD_PTR) ClassName->Buffer;
233 CsData += sizeof(ATOM);
234 }
235 else
236 {
237 *((WCHAR *) CsData) = L'S';
238 CsData += sizeof(WCHAR);
239 RtlCopyMemory(CsData, ClassName->Buffer, ClassName->Length);
240 CsData += ClassName->Length;
241 *((WCHAR *) CsData) = L'\0';
242 CsData += sizeof(WCHAR);
243 }
244 ASSERT(CsData == (PCHAR) PackedCs + Size);
245 *lParamPacked = (LPARAM) PackedCs;
246 }
247
248 return STATUS_SUCCESS;
249 }
250
251 static FASTCALL NTSTATUS
252 UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
253 {
254 NCCALCSIZE_PARAMS *UnpackedParams;
255 NCCALCSIZE_PARAMS *PackedParams;
256 PWINDOWPOS UnpackedWindowPos;
257
258 if (lParamPacked == lParam)
259 {
260 return STATUS_SUCCESS;
261 }
262
263 if (WM_NCCALCSIZE == Msg && wParam)
264 {
265 PackedParams = (NCCALCSIZE_PARAMS *) lParamPacked;
266 UnpackedParams = (NCCALCSIZE_PARAMS *) lParam;
267 UnpackedWindowPos = UnpackedParams->lppos;
268 RtlCopyMemory(UnpackedParams, PackedParams, sizeof(NCCALCSIZE_PARAMS));
269 UnpackedParams->lppos = UnpackedWindowPos;
270 RtlCopyMemory(UnpackedWindowPos, PackedParams + 1, sizeof(WINDOWPOS));
271 ExFreePool((PVOID) lParamPacked);
272
273 return STATUS_SUCCESS;
274 }
275 else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
276 {
277 ExFreePool((PVOID) lParamPacked);
278
279 return STATUS_SUCCESS;
280 }
281
282 ASSERT(FALSE);
283
284 return STATUS_INVALID_PARAMETER;
285 }
286
287
288 LRESULT STDCALL
289 NtUserDispatchMessage(PNTUSERDISPATCHMESSAGEINFO UnsafeMsgInfo)
290 {
291 NTSTATUS Status;
292 NTUSERDISPATCHMESSAGEINFO MsgInfo;
293 PWINDOW_OBJECT WindowObject;
294 LRESULT Result = TRUE;
295
296 Status = MmCopyFromCaller(&MsgInfo, UnsafeMsgInfo, sizeof(NTUSERDISPATCHMESSAGEINFO));
297 if (! NT_SUCCESS(Status))
298 {
299 SetLastNtError(Status);
300 return 0;
301 }
302
303 /* Process timer messages. */
304 if (WM_TIMER == MsgInfo.Msg.message && 0 != MsgInfo.Msg.lParam)
305 {
306 LARGE_INTEGER LargeTickCount;
307 /* FIXME: Call hooks. */
308
309 /* FIXME: Check for continuing validity of timer. */
310
311 MsgInfo.HandledByKernel = FALSE;
312 KeQueryTickCount(&LargeTickCount);
313 MsgInfo.Proc = (WNDPROC) MsgInfo.Msg.lParam;
314 MsgInfo.Msg.lParam = (LPARAM)LargeTickCount.u.LowPart;
315 }
316 else if (NULL == MsgInfo.Msg.hwnd)
317 {
318 MsgInfo.HandledByKernel = TRUE;
319 Result = 0;
320 }
321 else
322 {
323 /* Get the window object. */
324 WindowObject = IntGetWindowObject(MsgInfo.Msg.hwnd);
325 if (NULL == WindowObject)
326 {
327 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
328 MsgInfo.HandledByKernel = TRUE;
329 Result = 0;
330 }
331 else
332 {
333 if (WindowObject->OwnerThread != PsGetCurrentThread())
334 {
335 IntReleaseWindowObject(WindowObject);
336 DPRINT1("Window doesn't belong to the calling thread!\n");
337 MsgInfo.HandledByKernel = TRUE;
338 Result = 0;
339 }
340 else
341 {
342 /* FIXME: Call hook procedures. */
343
344 MsgInfo.HandledByKernel = FALSE;
345 Result = 0;
346 if (0xFFFF0000 != ((DWORD) WindowObject->WndProcW & 0xFFFF0000))
347 {
348 if (0xFFFF0000 != ((DWORD) WindowObject->WndProcA & 0xFFFF0000))
349 {
350 /* Both Unicode and Ansi winprocs are real, use whatever
351 usermode prefers */
352 MsgInfo.Proc = (MsgInfo.Ansi ? WindowObject->WndProcA
353 : WindowObject->WndProcW);
354 }
355 else
356 {
357 /* Real Unicode winproc */
358 MsgInfo.Ansi = FALSE;
359 MsgInfo.Proc = WindowObject->WndProcW;
360 }
361 }
362 else
363 {
364 /* Must have real Ansi winproc */
365 MsgInfo.Ansi = TRUE;
366 MsgInfo.Proc = WindowObject->WndProcA;
367 }
368 }
369 IntReleaseWindowObject(WindowObject);
370 }
371 }
372 Status = MmCopyToCaller(UnsafeMsgInfo, &MsgInfo, sizeof(NTUSERDISPATCHMESSAGEINFO));
373 if (! NT_SUCCESS(Status))
374 {
375 SetLastNtError(Status);
376 return 0;
377 }
378
379 return Result;
380 }
381
382
383 BOOL STDCALL
384 NtUserTranslateMessage(LPMSG lpMsg,
385 HKL dwhkl)
386 {
387 NTSTATUS Status;
388 MSG SafeMsg;
389
390 Status = MmCopyFromCaller(&SafeMsg, lpMsg, sizeof(MSG));
391 if(!NT_SUCCESS(Status))
392 {
393 SetLastNtError(Status);
394 return FALSE;
395 }
396
397 return IntTranslateKbdMessage(&SafeMsg, dwhkl);
398 }
399
400
401 VOID FASTCALL
402 IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg)
403 {
404 if(!Msg->hwnd || ThreadQueue->CaptureWindow)
405 {
406 return;
407 }
408
409 switch(Msg->message)
410 {
411 case WM_MOUSEMOVE:
412 {
413 IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
414 break;
415 }
416 case WM_NCMOUSEMOVE:
417 {
418 IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
419 break;
420 }
421 case WM_LBUTTONDOWN:
422 case WM_MBUTTONDOWN:
423 case WM_RBUTTONDOWN:
424 case WM_XBUTTONDOWN:
425 case WM_LBUTTONDBLCLK:
426 case WM_MBUTTONDBLCLK:
427 case WM_RBUTTONDBLCLK:
428 case WM_XBUTTONDBLCLK:
429 {
430 WPARAM wParam;
431 PSYSTEM_CURSORINFO CurInfo;
432
433 if(!IntGetWindowStationObject(InputWindowStation))
434 {
435 break;
436 }
437 CurInfo = IntGetSysCursorInfo(InputWindowStation);
438 wParam = (WPARAM)(CurInfo->ButtonsDown);
439 ObDereferenceObject(InputWindowStation);
440
441 IntSendMessage(Msg->hwnd, WM_MOUSEMOVE, wParam, Msg->lParam);
442 IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
443 break;
444 }
445 case WM_NCLBUTTONDOWN:
446 case WM_NCMBUTTONDOWN:
447 case WM_NCRBUTTONDOWN:
448 case WM_NCXBUTTONDOWN:
449 case WM_NCLBUTTONDBLCLK:
450 case WM_NCMBUTTONDBLCLK:
451 case WM_NCRBUTTONDBLCLK:
452 case WM_NCXBUTTONDBLCLK:
453 {
454 IntSendMessage(Msg->hwnd, WM_NCMOUSEMOVE, (WPARAM)Msg->wParam, Msg->lParam);
455 IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
456 break;
457 }
458 }
459 }
460
461 BOOL FASTCALL
462 IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, PWINDOW_OBJECT MsgWindow,
463 USHORT *HitTest)
464 {
465 ULONG Result;
466
467 if(*HitTest == (USHORT)HTTRANSPARENT)
468 {
469 /* eat the message, search again! */
470 return TRUE;
471 }
472
473 Result = IntSendMessage(MsgWindow->Self, WM_MOUSEACTIVATE, (WPARAM)NtUserGetParent(MsgWindow->Self), (LPARAM)MAKELONG(*HitTest, Msg->message));
474 switch (Result)
475 {
476 case MA_NOACTIVATEANDEAT:
477 return TRUE;
478 case MA_NOACTIVATE:
479 break;
480 case MA_ACTIVATEANDEAT:
481 IntMouseActivateWindow(MsgWindow);
482 return TRUE;
483 default:
484 /* MA_ACTIVATE */
485 IntMouseActivateWindow(MsgWindow);
486 break;
487 }
488
489 return FALSE;
490 }
491
492 BOOL FASTCALL
493 IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *HitTest, BOOL Remove)
494 {
495 PWINDOW_OBJECT Window;
496
497 if(!(Window = IntGetWindowObject(Msg->hwnd)))
498 {
499 /* let's just eat the message?! */
500 return TRUE;
501 }
502
503 if(ThreadQueue == Window->MessageQueue &&
504 ThreadQueue->CaptureWindow != Window->Self)
505 {
506 /* only send WM_NCHITTEST messages if we're not capturing the window! */
507 *HitTest = IntSendMessage(Window->Self, WM_NCHITTEST, 0,
508 MAKELONG(Msg->pt.x, Msg->pt.y));
509
510 if(*HitTest == (USHORT)HTTRANSPARENT)
511 {
512 PWINDOW_OBJECT DesktopWindow;
513 HWND hDesktop = IntGetDesktopWindow();
514
515 if((DesktopWindow = IntGetWindowObject(hDesktop)))
516 {
517 PWINDOW_OBJECT Wnd;
518
519 WinPosWindowFromPoint(DesktopWindow, Window->MessageQueue, &Msg->pt, &Wnd);
520 if(Wnd)
521 {
522 if(Wnd != Window)
523 {
524 /* post the message to the other window */
525 Msg->hwnd = Wnd->Self;
526 if(!(Wnd->Status & WINDOWSTATUS_DESTROYING))
527 {
528 MsqPostMessage(Wnd->MessageQueue, Msg, FALSE,
529 Msg->message == WM_MOUSEMOVE ? QS_MOUSEMOVE :
530 QS_MOUSEBUTTON);
531 }
532
533 /* eat the message */
534 IntReleaseWindowObject(Wnd);
535 IntReleaseWindowObject(Window);
536 IntReleaseWindowObject(DesktopWindow);
537 return TRUE;
538 }
539 IntReleaseWindowObject(Wnd);
540 }
541
542 IntReleaseWindowObject(DesktopWindow);
543 }
544 }
545 }
546 else
547 {
548 *HitTest = HTCLIENT;
549 }
550
551 if(IS_BTN_MESSAGE(Msg->message, DOWN))
552 {
553 /* generate double click messages, if necessary */
554 if ((((*HitTest) != HTCLIENT) ||
555 (IntGetClassLong(Window, GCL_STYLE, FALSE) & CS_DBLCLKS)) &&
556 MsqIsDblClk(Msg, Remove))
557 {
558 Msg->message += WM_LBUTTONDBLCLK - WM_LBUTTONDOWN;
559 }
560 }
561
562 if(Msg->message != WM_MOUSEWHEEL)
563 {
564
565 if ((*HitTest) != HTCLIENT)
566 {
567 Msg->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
568 if((Msg->message == WM_NCRBUTTONUP) &&
569 (((*HitTest) == HTCAPTION) || ((*HitTest) == HTSYSMENU)))
570 {
571 Msg->message = WM_CONTEXTMENU;
572 Msg->wParam = (WPARAM)Window->Self;
573 }
574 else
575 {
576 Msg->wParam = *HitTest;
577 }
578 Msg->lParam = MAKELONG(Msg->pt.x, Msg->pt.y);
579 }
580 else if(ThreadQueue->MoveSize == NULL &&
581 ThreadQueue->MenuOwner == NULL)
582 {
583 /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
584 Msg->lParam = MAKELONG(
585 Msg->pt.x - (WORD)Window->ClientRect.left,
586 Msg->pt.y - (WORD)Window->ClientRect.top);
587 }
588 }
589
590 IntReleaseWindowObject(Window);
591 return FALSE;
592 }
593
594
595 /*
596 * Internal version of PeekMessage() doing all the work
597 */
598 BOOL FASTCALL
599 IntPeekMessage(PUSER_MESSAGE Msg,
600 HWND Wnd,
601 UINT MsgFilterMin,
602 UINT MsgFilterMax,
603 UINT RemoveMsg)
604 {
605 LARGE_INTEGER LargeTickCount;
606 PUSER_MESSAGE_QUEUE ThreadQueue;
607 PUSER_MESSAGE Message;
608 BOOL Present, RemoveMessages;
609
610 /* The queues and order in which they are checked are documented in the MSDN
611 article on GetMessage() */
612
613 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
614
615 /* Inspect RemoveMsg flags */
616 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
617 RemoveMessages = RemoveMsg & PM_REMOVE;
618
619 CheckMessages:
620
621 Present = FALSE;
622
623 KeQueryTickCount(&LargeTickCount);
624 ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
625
626 /* Dispatch sent messages here. */
627 while (MsqDispatchOneSentMessage(ThreadQueue));
628
629 /* Now look for a quit message. */
630
631 if (ThreadQueue->QuitPosted)
632 {
633 /* According to the PSDK, WM_QUIT messages are always returned, regardless
634 of the filter specified */
635 Msg->Msg.hwnd = NULL;
636 Msg->Msg.message = WM_QUIT;
637 Msg->Msg.wParam = ThreadQueue->QuitExitCode;
638 Msg->Msg.lParam = 0;
639 Msg->FreeLParam = FALSE;
640 if (RemoveMessages)
641 {
642 ThreadQueue->QuitPosted = FALSE;
643 }
644 return TRUE;
645 }
646
647 /* Now check for normal messages. */
648 Present = MsqFindMessage(ThreadQueue,
649 FALSE,
650 RemoveMessages,
651 Wnd,
652 MsgFilterMin,
653 MsgFilterMax,
654 &Message);
655 if (Present)
656 {
657 RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
658 if (RemoveMessages)
659 {
660 MsqDestroyMessage(Message);
661 }
662 goto MessageFound;
663 }
664
665 /* Check for hardware events. */
666 Present = MsqFindMessage(ThreadQueue,
667 TRUE,
668 RemoveMessages,
669 Wnd,
670 MsgFilterMin,
671 MsgFilterMax,
672 &Message);
673 if (Present)
674 {
675 RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
676 if (RemoveMessages)
677 {
678 MsqDestroyMessage(Message);
679 }
680 goto MessageFound;
681 }
682
683 /* Check for sent messages again. */
684 while (MsqDispatchOneSentMessage(ThreadQueue));
685
686 /* Check for paint messages. */
687 if (IntGetPaintMessage(Wnd, MsgFilterMin, MsgFilterMax, PsGetWin32Thread(), &Msg->Msg, RemoveMessages))
688 {
689 Msg->FreeLParam = FALSE;
690 return TRUE;
691 }
692
693 /* Check for WM_(SYS)TIMER messages */
694 Present = MsqGetTimerMessage(ThreadQueue, Wnd, MsgFilterMin, MsgFilterMax,
695 &Msg->Msg, RemoveMessages);
696 if (Present)
697 {
698 Msg->FreeLParam = FALSE;
699 goto MessageFound;
700 }
701
702 if(Present)
703 {
704 MessageFound:
705
706 if(RemoveMessages)
707 {
708 PWINDOW_OBJECT MsgWindow = NULL;;
709
710 if(Msg->Msg.hwnd && (MsgWindow = IntGetWindowObject(Msg->Msg.hwnd)) &&
711 Msg->Msg.message >= WM_MOUSEFIRST && Msg->Msg.message <= WM_MOUSELAST)
712 {
713 USHORT HitTest;
714
715 if(IntTranslateMouseMessage(ThreadQueue, &Msg->Msg, &HitTest, TRUE))
716 /* FIXME - check message filter again, if the message doesn't match anymore,
717 search again */
718 {
719 IntReleaseWindowObject(MsgWindow);
720 /* eat the message, search again */
721 goto CheckMessages;
722 }
723 if(ThreadQueue->CaptureWindow == NULL)
724 {
725 IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
726 if((Msg->Msg.message != WM_MOUSEMOVE && Msg->Msg.message != WM_NCMOUSEMOVE) &&
727 IS_BTN_MESSAGE(Msg->Msg.message, DOWN) &&
728 IntActivateWindowMouse(ThreadQueue, &Msg->Msg, MsgWindow, &HitTest))
729 {
730 IntReleaseWindowObject(MsgWindow);
731 /* eat the message, search again */
732 goto CheckMessages;
733 }
734 }
735 }
736 else
737 {
738 IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
739 }
740
741 if(MsgWindow)
742 {
743 IntReleaseWindowObject(MsgWindow);
744 }
745
746 return TRUE;
747 }
748
749 USHORT HitTest;
750 if((Msg->Msg.hwnd && Msg->Msg.message >= WM_MOUSEFIRST && Msg->Msg.message <= WM_MOUSELAST) &&
751 IntTranslateMouseMessage(ThreadQueue, &Msg->Msg, &HitTest, FALSE))
752 /* FIXME - check message filter again, if the message doesn't match anymore,
753 search again */
754 {
755 /* eat the message, search again */
756 goto CheckMessages;
757 }
758
759 return TRUE;
760 }
761
762 return Present;
763 }
764
765 BOOL STDCALL
766 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
767 HWND Wnd,
768 UINT MsgFilterMin,
769 UINT MsgFilterMax,
770 UINT RemoveMsg)
771 {
772 NTSTATUS Status;
773 BOOL Present;
774 NTUSERGETMESSAGEINFO Info;
775 PWINDOW_OBJECT Window;
776 PMSGMEMORY MsgMemoryEntry;
777 PVOID UserMem;
778 UINT Size;
779 USER_MESSAGE Msg;
780
781 /* Validate input */
782 if (NULL != Wnd)
783 {
784 Window = IntGetWindowObject(Wnd);
785 if (NULL == Window)
786 {
787 Wnd = NULL;
788 }
789 else
790 {
791 IntReleaseWindowObject(Window);
792 }
793 }
794
795 if (MsgFilterMax < MsgFilterMin)
796 {
797 MsgFilterMin = 0;
798 MsgFilterMax = 0;
799 }
800
801 Present = IntPeekMessage(&Msg, Wnd, MsgFilterMin, MsgFilterMax, RemoveMsg);
802 if (Present)
803 {
804 Info.Msg = Msg.Msg;
805 /* See if this message type is present in the table */
806 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
807 if (NULL == MsgMemoryEntry)
808 {
809 /* Not present, no copying needed */
810 Info.LParamSize = 0;
811 }
812 else
813 {
814 /* Determine required size */
815 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
816 Info.Msg.lParam);
817 /* Allocate required amount of user-mode memory */
818 Info.LParamSize = Size;
819 UserMem = NULL;
820 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
821 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
822 if (! NT_SUCCESS(Status))
823 {
824 SetLastNtError(Status);
825 return (BOOL) -1;
826 }
827 /* Transfer lParam data to user-mode mem */
828 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
829 if (! NT_SUCCESS(Status))
830 {
831 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
832 &Info.LParamSize, MEM_DECOMMIT);
833 SetLastNtError(Status);
834 return (BOOL) -1;
835 }
836 Info.Msg.lParam = (LPARAM) UserMem;
837 }
838 if (RemoveMsg && Msg.FreeLParam && 0 != Msg.Msg.lParam)
839 {
840 ExFreePool((void *) Msg.Msg.lParam);
841 }
842 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
843 if (! NT_SUCCESS(Status))
844 {
845 SetLastNtError(Status);
846 return (BOOL) -1;
847 }
848 }
849
850 return Present;
851 }
852
853 static BOOL FASTCALL
854 IntWaitMessage(HWND Wnd,
855 UINT MsgFilterMin,
856 UINT MsgFilterMax)
857 {
858 PUSER_MESSAGE_QUEUE ThreadQueue;
859 NTSTATUS Status;
860 USER_MESSAGE Msg;
861
862 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
863
864 do
865 {
866 if (IntPeekMessage(&Msg, Wnd, MsgFilterMin, MsgFilterMax, PM_NOREMOVE))
867 {
868 return TRUE;
869 }
870
871 /* Nothing found. Wait for new messages. */
872 Status = MsqWaitForNewMessages(ThreadQueue, Wnd, MsgFilterMin, MsgFilterMax);
873 }
874 while ((STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) || STATUS_TIMEOUT == Status);
875
876 SetLastNtError(Status);
877
878 return FALSE;
879 }
880
881 BOOL STDCALL
882 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
883 HWND Wnd,
884 UINT MsgFilterMin,
885 UINT MsgFilterMax)
886 /*
887 * FUNCTION: Get a message from the calling thread's message queue.
888 * ARGUMENTS:
889 * UnsafeMsg - Pointer to the structure which receives the returned message.
890 * Wnd - Window whose messages are to be retrieved.
891 * MsgFilterMin - Integer value of the lowest message value to be
892 * retrieved.
893 * MsgFilterMax - Integer value of the highest message value to be
894 * retrieved.
895 */
896 {
897 BOOL GotMessage;
898 NTUSERGETMESSAGEINFO Info;
899 NTSTATUS Status;
900 PWINDOW_OBJECT Window;
901 PMSGMEMORY MsgMemoryEntry;
902 PVOID UserMem;
903 UINT Size;
904 USER_MESSAGE Msg;
905
906 /* Validate input */
907 if (NULL != Wnd)
908 {
909 Window = IntGetWindowObject(Wnd);
910 if(!Window)
911 Wnd = NULL;
912 else
913 IntReleaseWindowObject(Window);
914 }
915 if (MsgFilterMax < MsgFilterMin)
916 {
917 MsgFilterMin = 0;
918 MsgFilterMax = 0;
919 }
920
921 do
922 {
923 GotMessage = IntPeekMessage(&Msg, Wnd, MsgFilterMin, MsgFilterMax, PM_REMOVE);
924 if (GotMessage)
925 {
926 Info.Msg = Msg.Msg;
927 /* See if this message type is present in the table */
928 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
929 if (NULL == MsgMemoryEntry)
930 {
931 /* Not present, no copying needed */
932 Info.LParamSize = 0;
933 }
934 else
935 {
936 /* Determine required size */
937 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
938 Info.Msg.lParam);
939 /* Allocate required amount of user-mode memory */
940 Info.LParamSize = Size;
941 UserMem = NULL;
942 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
943 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
944
945 if (! NT_SUCCESS(Status))
946 {
947 SetLastNtError(Status);
948 return (BOOL) -1;
949 }
950 /* Transfer lParam data to user-mode mem */
951 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
952 if (! NT_SUCCESS(Status))
953 {
954 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
955 &Info.LParamSize, MEM_DECOMMIT);
956 SetLastNtError(Status);
957 return (BOOL) -1;
958 }
959 Info.Msg.lParam = (LPARAM) UserMem;
960 }
961 if (Msg.FreeLParam && 0 != Msg.Msg.lParam)
962 {
963 ExFreePool((void *) Msg.Msg.lParam);
964 }
965 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
966 if (! NT_SUCCESS(Status))
967 {
968 SetLastNtError(Status);
969 return (BOOL) -1;
970 }
971 }
972 else if (! IntWaitMessage(Wnd, MsgFilterMin, MsgFilterMax))
973 {
974 return (BOOL) -1;
975 }
976 }
977 while (! GotMessage);
978
979 return WM_QUIT != Info.Msg.message;
980 }
981
982 DWORD
983 STDCALL
984 NtUserMessageCall(
985 DWORD Unknown0,
986 DWORD Unknown1,
987 DWORD Unknown2,
988 DWORD Unknown3,
989 DWORD Unknown4,
990 DWORD Unknown5,
991 DWORD Unknown6)
992 {
993 UNIMPLEMENTED
994
995 return 0;
996 }
997
998 static NTSTATUS FASTCALL
999 CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
1000 {
1001 NTSTATUS Status;
1002
1003 PVOID KernelMem;
1004 UINT Size;
1005
1006 *KernelModeMsg = *UserModeMsg;
1007
1008 /* See if this message type is present in the table */
1009 if (NULL == MsgMemoryEntry)
1010 {
1011 /* Not present, no copying needed */
1012 return STATUS_SUCCESS;
1013 }
1014
1015 /* Determine required size */
1016 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
1017
1018 if (0 != Size)
1019 {
1020 /* Allocate kernel mem */
1021 KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
1022 if (NULL == KernelMem)
1023 {
1024 DPRINT1("Not enough memory to copy message to kernel mem\n");
1025 return STATUS_NO_MEMORY;
1026 }
1027 KernelModeMsg->lParam = (LPARAM) KernelMem;
1028
1029 /* Copy data if required */
1030 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
1031 {
1032 Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
1033 if (! NT_SUCCESS(Status))
1034 {
1035 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
1036 ExFreePool(KernelMem);
1037 return Status;
1038 }
1039 }
1040 else
1041 {
1042 /* Make sure we don't pass any secrets to usermode */
1043 RtlZeroMemory(KernelMem, Size);
1044 }
1045 }
1046 else
1047 {
1048 KernelModeMsg->lParam = 0;
1049 }
1050
1051 return STATUS_SUCCESS;
1052 }
1053
1054 static NTSTATUS FASTCALL
1055 CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
1056 {
1057 NTSTATUS Status;
1058 PMSGMEMORY MsgMemoryEntry;
1059 UINT Size;
1060
1061 /* See if this message type is present in the table */
1062 MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
1063 if (NULL == MsgMemoryEntry)
1064 {
1065 /* Not present, no copying needed */
1066 return STATUS_SUCCESS;
1067 }
1068
1069 /* Determine required size */
1070 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
1071
1072 if (0 != Size)
1073 {
1074 /* Copy data if required */
1075 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
1076 {
1077 Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
1078 if (! NT_SUCCESS(Status))
1079 {
1080 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1081 ExFreePool((PVOID) KernelModeMsg->lParam);
1082 return Status;
1083 }
1084 }
1085
1086 ExFreePool((PVOID) KernelModeMsg->lParam);
1087 }
1088
1089 return STATUS_SUCCESS;
1090 }
1091
1092 BOOL STDCALL
1093 NtUserPostMessage(HWND Wnd,
1094 UINT Msg,
1095 WPARAM wParam,
1096 LPARAM lParam)
1097 {
1098 PWINDOW_OBJECT Window;
1099 MSG UserModeMsg, KernelModeMsg;
1100 LARGE_INTEGER LargeTickCount;
1101 NTSTATUS Status;
1102 PMSGMEMORY MsgMemoryEntry;
1103
1104 if (WM_QUIT == Msg)
1105 {
1106 MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue, wParam);
1107 }
1108 else if (Wnd == HWND_BROADCAST)
1109 {
1110 HWND *List;
1111 PWINDOW_OBJECT DesktopWindow;
1112 ULONG i;
1113
1114 DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
1115 List = IntWinListChildren(DesktopWindow);
1116 IntReleaseWindowObject(DesktopWindow);
1117 if (List != NULL)
1118 {
1119 for (i = 0; List[i]; i++)
1120 NtUserPostMessage(List[i], Msg, wParam, lParam);
1121 ExFreePool(List);
1122 }
1123 }
1124 else
1125 {
1126 Window = IntGetWindowObject(Wnd);
1127 if (NULL == Window)
1128 {
1129 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1130 return FALSE;
1131 }
1132 if(Window->Status & WINDOWSTATUS_DESTROYING)
1133 {
1134 IntReleaseWindowObject(Window);
1135 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
1136 /* FIXME - last error code? */
1137 return FALSE;
1138 }
1139
1140 UserModeMsg.hwnd = Wnd;
1141 UserModeMsg.message = Msg;
1142 UserModeMsg.wParam = wParam;
1143 UserModeMsg.lParam = lParam;
1144 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1145 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1146 if (! NT_SUCCESS(Status))
1147 {
1148 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1149 return FALSE;
1150 }
1151 IntGetCursorLocation(PsGetWin32Thread()->Desktop->WindowStation,
1152 &KernelModeMsg.pt);
1153 KeQueryTickCount(&LargeTickCount);
1154 KernelModeMsg.time = LargeTickCount.u.LowPart;
1155 MsqPostMessage(Window->MessageQueue, &KernelModeMsg,
1156 NULL != MsgMemoryEntry && 0 != KernelModeMsg.lParam,
1157 QS_POSTMESSAGE);
1158 IntReleaseWindowObject(Window);
1159 }
1160
1161 return TRUE;
1162 }
1163
1164 BOOL STDCALL
1165 NtUserPostThreadMessage(DWORD idThread,
1166 UINT Msg,
1167 WPARAM wParam,
1168 LPARAM lParam)
1169 {
1170 MSG UserModeMsg, KernelModeMsg;
1171 PETHREAD peThread;
1172 PW32THREAD pThread;
1173 NTSTATUS Status;
1174 PMSGMEMORY MsgMemoryEntry;
1175
1176 Status = PsLookupThreadByThreadId((void *)idThread,&peThread);
1177
1178 if( Status == STATUS_SUCCESS ) {
1179 pThread = peThread->Tcb.Win32Thread;
1180 if( !pThread || !pThread->MessageQueue )
1181 {
1182 ObDereferenceObject( peThread );
1183 return FALSE;
1184 }
1185
1186 UserModeMsg.hwnd = NULL;
1187 UserModeMsg.message = Msg;
1188 UserModeMsg.wParam = wParam;
1189 UserModeMsg.lParam = lParam;
1190 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1191 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1192 if (! NT_SUCCESS(Status))
1193 {
1194 ObDereferenceObject( peThread );
1195 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1196 return FALSE;
1197 }
1198 MsqPostMessage(pThread->MessageQueue, &KernelModeMsg,
1199 NULL != MsgMemoryEntry && 0 != KernelModeMsg.lParam,
1200 QS_POSTMESSAGE);
1201 ObDereferenceObject( peThread );
1202 return TRUE;
1203 } else {
1204 SetLastNtError( Status );
1205 return FALSE;
1206 }
1207 }
1208
1209 DWORD STDCALL
1210 NtUserQuerySendMessage(DWORD Unknown0)
1211 {
1212 UNIMPLEMENTED;
1213
1214 return 0;
1215 }
1216
1217 LRESULT FASTCALL
1218 IntSendMessage(HWND hWnd,
1219 UINT Msg,
1220 WPARAM wParam,
1221 LPARAM lParam)
1222 {
1223 ULONG_PTR Result = 0;
1224 if(IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1225 {
1226 return (LRESULT)Result;
1227 }
1228 return 0;
1229 }
1230
1231 static LRESULT FASTCALL
1232 IntSendMessageTimeoutSingle(HWND hWnd,
1233 UINT Msg,
1234 WPARAM wParam,
1235 LPARAM lParam,
1236 UINT uFlags,
1237 UINT uTimeout,
1238 ULONG_PTR *uResult)
1239 {
1240 ULONG_PTR Result;
1241 NTSTATUS Status;
1242 PWINDOW_OBJECT Window;
1243 PMSGMEMORY MsgMemoryEntry;
1244 INT lParamBufferSize;
1245 LPARAM lParamPacked;
1246 PW32THREAD Win32Thread;
1247
1248 /* FIXME: Call hooks. */
1249 Window = IntGetWindowObject(hWnd);
1250 if (!Window)
1251 {
1252 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1253 return FALSE;
1254 }
1255
1256 Win32Thread = PsGetWin32Thread();
1257
1258 if (NULL != Win32Thread &&
1259 Window->MessageQueue == Win32Thread->MessageQueue)
1260 {
1261 if (Win32Thread->IsExiting)
1262 {
1263 /* Never send messages to exiting threads */
1264 IntReleaseWindowObject(Window);
1265 return FALSE;
1266 }
1267
1268 /* See if this message type is present in the table */
1269 MsgMemoryEntry = FindMsgMemory(Msg);
1270 if (NULL == MsgMemoryEntry)
1271 {
1272 lParamBufferSize = -1;
1273 }
1274 else
1275 {
1276 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1277 }
1278
1279 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam)))
1280 {
1281 IntReleaseWindowObject(Window);
1282 DPRINT1("Failed to pack message parameters\n");
1283 return FALSE;
1284 }
1285 if (0xFFFF0000 != ((DWORD) Window->WndProcW & 0xFFFF0000))
1286 {
1287 Result = (ULONG_PTR)IntCallWindowProc(Window->WndProcW, FALSE, hWnd, Msg, wParam,
1288 lParamPacked,lParamBufferSize);
1289 }
1290 else
1291 {
1292 Result = (ULONG_PTR)IntCallWindowProc(Window->WndProcA, TRUE, hWnd, Msg, wParam,
1293 lParamPacked,lParamBufferSize);
1294 }
1295
1296 if(uResult)
1297 {
1298 *uResult = Result;
1299 }
1300
1301 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam)))
1302 {
1303 IntReleaseWindowObject(Window);
1304 DPRINT1("Failed to unpack message parameters\n");
1305 return TRUE;
1306 }
1307
1308 IntReleaseWindowObject(Window);
1309 return TRUE;
1310 }
1311
1312 if(uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->MessageQueue))
1313 {
1314 IntReleaseWindowObject(Window);
1315 /* FIXME - Set a LastError? */
1316 return FALSE;
1317 }
1318
1319 if(Window->Status & WINDOWSTATUS_DESTROYING)
1320 {
1321 IntReleaseWindowObject(Window);
1322 /* FIXME - last error? */
1323 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1324 return FALSE;
1325 }
1326
1327 Status = MsqSendMessage(Window->MessageQueue, hWnd, Msg, wParam, lParam,
1328 uTimeout, (uFlags & SMTO_BLOCK), uResult);
1329 IntReleaseWindowObject(Window);
1330 if (STATUS_TIMEOUT == Status)
1331 {
1332 /* MSDN says GetLastError() should return 0 after timeout */
1333 SetLastWin32Error(0);
1334 return FALSE;
1335 }
1336 else if (! NT_SUCCESS(Status))
1337 {
1338 SetLastNtError(Status);
1339 return FALSE;
1340 }
1341
1342 return TRUE;
1343 }
1344
1345 LRESULT FASTCALL
1346 IntSendMessageTimeout(HWND hWnd,
1347 UINT Msg,
1348 WPARAM wParam,
1349 LPARAM lParam,
1350 UINT uFlags,
1351 UINT uTimeout,
1352 ULONG_PTR *uResult)
1353 {
1354 PWINDOW_OBJECT DesktopWindow;
1355 HWND *Children;
1356 HWND *Child;
1357
1358 if (HWND_BROADCAST != hWnd)
1359 {
1360 return IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1361 }
1362
1363 DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
1364 if (NULL == DesktopWindow)
1365 {
1366 SetLastWin32Error(ERROR_INTERNAL_ERROR);
1367 return 0;
1368 }
1369 Children = IntWinListChildren(DesktopWindow);
1370 IntReleaseWindowObject(DesktopWindow);
1371 if (NULL == Children)
1372 {
1373 return 0;
1374 }
1375
1376 for (Child = Children; NULL != *Child; Child++)
1377 {
1378 IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1379 }
1380
1381 ExFreePool(Children);
1382
1383 return (LRESULT) TRUE;
1384 }
1385
1386
1387 /* This function posts a message if the destination's message queue belongs to
1388 another thread, otherwise it sends the message. It does not support broadcast
1389 messages! */
1390 LRESULT FASTCALL
1391 IntPostOrSendMessage(HWND hWnd,
1392 UINT Msg,
1393 WPARAM wParam,
1394 LPARAM lParam)
1395 {
1396 ULONG_PTR Result;
1397 PWINDOW_OBJECT Window;
1398
1399 if(hWnd == HWND_BROADCAST)
1400 {
1401 return 0;
1402 }
1403
1404 Window = IntGetWindowObject(hWnd);
1405 if(!Window)
1406 {
1407 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1408 return 0;
1409 }
1410
1411 if(Window->MessageQueue != PsGetWin32Thread()->MessageQueue)
1412 {
1413 Result = NtUserPostMessage(hWnd, Msg, wParam, lParam);
1414 }
1415 else
1416 {
1417 if(!IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1418 {
1419 Result = 0;
1420 }
1421 }
1422
1423 IntReleaseWindowObject(Window);
1424
1425 return (LRESULT)Result;
1426 }
1427
1428 LRESULT FASTCALL
1429 IntDoSendMessage(HWND Wnd,
1430 UINT Msg,
1431 WPARAM wParam,
1432 LPARAM lParam,
1433 PDOSENDMESSAGE dsm,
1434 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1435 {
1436 LRESULT Result = TRUE;
1437 NTSTATUS Status;
1438 PWINDOW_OBJECT Window;
1439 NTUSERSENDMESSAGEINFO Info;
1440 MSG UserModeMsg;
1441 MSG KernelModeMsg;
1442 PMSGMEMORY MsgMemoryEntry;
1443
1444 RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));
1445
1446 /* FIXME: Call hooks. */
1447 if (HWND_BROADCAST != Wnd)
1448 {
1449 Window = IntGetWindowObject(Wnd);
1450 if (NULL == Window)
1451 {
1452 /* Tell usermode to not touch this one */
1453 Info.HandledByKernel = TRUE;
1454 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1455 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1456 return 0;
1457 }
1458 }
1459
1460 /* FIXME: Check for an exiting window. */
1461
1462 /* See if the current thread can handle the message */
1463 if (HWND_BROADCAST != Wnd && NULL != PsGetWin32Thread() &&
1464 Window->MessageQueue == PsGetWin32Thread()->MessageQueue)
1465 {
1466 /* Gather the information usermode needs to call the window proc directly */
1467 Info.HandledByKernel = FALSE;
1468 if (0xFFFF0000 != ((DWORD) Window->WndProcW & 0xFFFF0000))
1469 {
1470 if (0xFFFF0000 != ((DWORD) Window->WndProcA & 0xFFFF0000))
1471 {
1472 /* Both Unicode and Ansi winprocs are real, see what usermode prefers */
1473 Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi),
1474 sizeof(BOOL));
1475 if (! NT_SUCCESS(Status))
1476 {
1477 Info.Ansi = ! Window->Unicode;
1478 }
1479 Info.Proc = (Info.Ansi ? Window->WndProcA : Window->WndProcW);
1480 }
1481 else
1482 {
1483 /* Real Unicode winproc */
1484 Info.Ansi = FALSE;
1485 Info.Proc = Window->WndProcW;
1486 }
1487 }
1488 else
1489 {
1490 /* Must have real Ansi winproc */
1491 Info.Ansi = TRUE;
1492 Info.Proc = Window->WndProcA;
1493 }
1494 IntReleaseWindowObject(Window);
1495 }
1496 else
1497 {
1498 /* Must be handled by other thread */
1499 if (HWND_BROADCAST != Wnd)
1500 {
1501 IntReleaseWindowObject(Window);
1502 }
1503 Info.HandledByKernel = TRUE;
1504 UserModeMsg.hwnd = Wnd;
1505 UserModeMsg.message = Msg;
1506 UserModeMsg.wParam = wParam;
1507 UserModeMsg.lParam = lParam;
1508 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1509 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1510 if (! NT_SUCCESS(Status))
1511 {
1512 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1513 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1514 return (dsm ? 0 : -1);
1515 }
1516 if(!dsm)
1517 {
1518 Result = IntSendMessage(KernelModeMsg.hwnd, KernelModeMsg.message,
1519 KernelModeMsg.wParam, KernelModeMsg.lParam);
1520 }
1521 else
1522 {
1523 Result = IntSendMessageTimeout(KernelModeMsg.hwnd, KernelModeMsg.message,
1524 KernelModeMsg.wParam, KernelModeMsg.lParam,
1525 dsm->uFlags, dsm->uTimeout, &dsm->Result);
1526 }
1527 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1528 if (! NT_SUCCESS(Status))
1529 {
1530 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1531 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1532 return(dsm ? 0 : -1);
1533 }
1534 }
1535
1536 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1537 if (! NT_SUCCESS(Status))
1538 {
1539 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1540 }
1541
1542 return (LRESULT)Result;
1543 }
1544
1545 LRESULT STDCALL
1546 NtUserSendMessageTimeout(HWND hWnd,
1547 UINT Msg,
1548 WPARAM wParam,
1549 LPARAM lParam,
1550 UINT uFlags,
1551 UINT uTimeout,
1552 ULONG_PTR *uResult,
1553 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1554 {
1555 DOSENDMESSAGE dsm;
1556 LRESULT Result;
1557
1558 dsm.uFlags = uFlags;
1559 dsm.uTimeout = uTimeout;
1560 Result = IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
1561 if(uResult != NULL && Result != 0)
1562 {
1563 NTSTATUS Status;
1564
1565 Status = MmCopyToCaller(uResult, &dsm.Result, sizeof(ULONG_PTR));
1566 if(!NT_SUCCESS(Status))
1567 {
1568 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1569 return FALSE;
1570 }
1571 }
1572 return Result;
1573 }
1574
1575 LRESULT STDCALL
1576 NtUserSendMessage(HWND Wnd,
1577 UINT Msg,
1578 WPARAM wParam,
1579 LPARAM lParam,
1580 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1581 {
1582 return IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo);
1583 }
1584
1585 BOOL STDCALL
1586 NtUserSendMessageCallback(HWND hWnd,
1587 UINT Msg,
1588 WPARAM wParam,
1589 LPARAM lParam,
1590 SENDASYNCPROC lpCallBack,
1591 ULONG_PTR dwData)
1592 {
1593 UNIMPLEMENTED;
1594
1595 return 0;
1596 }
1597
1598 BOOL STDCALL
1599 NtUserSendNotifyMessage(HWND hWnd,
1600 UINT Msg,
1601 WPARAM wParam,
1602 LPARAM lParam)
1603 {
1604 UNIMPLEMENTED;
1605
1606 return 0;
1607 }
1608
1609 BOOL STDCALL
1610 NtUserWaitMessage(VOID)
1611 {
1612
1613 return IntWaitMessage(NULL, 0, 0);
1614 }
1615
1616 DWORD STDCALL
1617 NtUserGetQueueStatus(BOOL ClearChanges)
1618 {
1619 PUSER_MESSAGE_QUEUE Queue;
1620 DWORD Result;
1621
1622 Queue = PsGetWin32Thread()->MessageQueue;
1623
1624 IntLockMessageQueue(Queue);
1625
1626 Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
1627 if (ClearChanges)
1628 {
1629 Queue->ChangedBits = 0;
1630 }
1631
1632 IntUnLockMessageQueue(Queue);
1633
1634 return Result;
1635 }
1636
1637 BOOL STDCALL
1638 IntInitMessagePumpHook()
1639 {
1640 PsGetCurrentThread()->Tcb.Win32Thread->MessagePumpHookValue++;
1641 return TRUE;
1642 }
1643
1644 BOOL STDCALL
1645 IntUninitMessagePumpHook()
1646 {
1647 if (PsGetCurrentThread()->Tcb.Win32Thread->MessagePumpHookValue <= 0)
1648 {
1649 return FALSE;
1650 }
1651 PsGetCurrentThread()->Tcb.Win32Thread->MessagePumpHookValue--;
1652 return TRUE;
1653 }
1654
1655 /* EOF */