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