1. get rid of the global thread list and group threads in processes instead
[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.74 2004/09/28 15:02:30 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 MsqPostMessage(Wnd->MessageQueue, Msg, FALSE);
523
524 /* eat the message */
525 IntReleaseWindowObject(Wnd);
526 IntReleaseWindowObject(Window);
527 IntReleaseWindowObject(DesktopWindow);
528 return TRUE;
529 }
530 IntReleaseWindowObject(Wnd);
531 }
532
533 IntReleaseWindowObject(DesktopWindow);
534 }
535 }
536 }
537 else
538 {
539 *HitTest = HTCLIENT;
540 }
541
542 if(IS_BTN_MESSAGE(Msg->message, DOWN))
543 {
544 /* generate double click messages, if necessary */
545 if ((((*HitTest) != HTCLIENT) ||
546 (IntGetClassLong(Window, GCL_STYLE, FALSE) & CS_DBLCLKS)) &&
547 MsqIsDblClk(Msg, Remove))
548 {
549 Msg->message += WM_LBUTTONDBLCLK - WM_LBUTTONDOWN;
550 }
551 }
552
553 if(Msg->message != WM_MOUSEWHEEL)
554 {
555
556 if ((*HitTest) != HTCLIENT)
557 {
558 Msg->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
559 if((Msg->message == WM_NCRBUTTONUP) &&
560 (((*HitTest) == HTCAPTION) || ((*HitTest) == HTSYSMENU)))
561 {
562 Msg->message = WM_CONTEXTMENU;
563 Msg->wParam = (WPARAM)Window->Self;
564 }
565 else
566 {
567 Msg->wParam = *HitTest;
568 }
569 Msg->lParam = MAKELONG(Msg->pt.x, Msg->pt.y);
570 }
571 else if(ThreadQueue->MoveSize == NULL &&
572 ThreadQueue->MenuOwner == NULL)
573 {
574 /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
575 Msg->lParam = MAKELONG(
576 Msg->pt.x - (WORD)Window->ClientRect.left,
577 Msg->pt.y - (WORD)Window->ClientRect.top);
578 }
579 }
580
581 IntReleaseWindowObject(Window);
582 return FALSE;
583 }
584
585
586 /*
587 * Internal version of PeekMessage() doing all the work
588 */
589 BOOL FASTCALL
590 IntPeekMessage(PUSER_MESSAGE Msg,
591 HWND Wnd,
592 UINT MsgFilterMin,
593 UINT MsgFilterMax,
594 UINT RemoveMsg)
595 {
596 LARGE_INTEGER LargeTickCount;
597 PUSER_MESSAGE_QUEUE ThreadQueue;
598 PUSER_MESSAGE Message;
599 BOOL Present, RemoveMessages;
600
601 /* The queues and order in which they are checked are documented in the MSDN
602 article on GetMessage() */
603
604 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
605
606 /* Inspect RemoveMsg flags */
607 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
608 RemoveMessages = RemoveMsg & PM_REMOVE;
609
610 CheckMessages:
611
612 Present = FALSE;
613
614 KeQueryTickCount(&LargeTickCount);
615 ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
616
617 /* Dispatch sent messages here. */
618 while (MsqDispatchOneSentMessage(ThreadQueue));
619
620 /* Now look for a quit message. */
621
622 if (ThreadQueue->QuitPosted)
623 {
624 /* According to the PSDK, WM_QUIT messages are always returned, regardless
625 of the filter specified */
626 Msg->Msg.hwnd = NULL;
627 Msg->Msg.message = WM_QUIT;
628 Msg->Msg.wParam = ThreadQueue->QuitExitCode;
629 Msg->Msg.lParam = 0;
630 Msg->FreeLParam = FALSE;
631 if (RemoveMessages)
632 {
633 ThreadQueue->QuitPosted = FALSE;
634 }
635 return TRUE;
636 }
637
638 /* Now check for normal messages. */
639 Present = MsqFindMessage(ThreadQueue,
640 FALSE,
641 RemoveMessages,
642 Wnd,
643 MsgFilterMin,
644 MsgFilterMax,
645 &Message);
646 if (Present)
647 {
648 RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
649 if (RemoveMessages)
650 {
651 MsqDestroyMessage(Message);
652 }
653 goto MessageFound;
654 }
655
656 /* Check for hardware events. */
657 Present = MsqFindMessage(ThreadQueue,
658 TRUE,
659 RemoveMessages,
660 Wnd,
661 MsgFilterMin,
662 MsgFilterMax,
663 &Message);
664 if (Present)
665 {
666 RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
667 if (RemoveMessages)
668 {
669 MsqDestroyMessage(Message);
670 }
671 goto MessageFound;
672 }
673
674 /* Check for sent messages again. */
675 while (MsqDispatchOneSentMessage(ThreadQueue));
676
677 /* Check for paint messages. */
678 if (IntGetPaintMessage(Wnd, MsgFilterMin, MsgFilterMax, PsGetWin32Thread(), &Msg->Msg, RemoveMessages))
679 {
680 Msg->FreeLParam = FALSE;
681 return TRUE;
682 }
683
684 /* FIXME - get WM_(SYS)TIMER messages */
685
686 if(Present)
687 {
688 MessageFound:
689
690 if(RemoveMessages)
691 {
692 PWINDOW_OBJECT MsgWindow = NULL;;
693
694 if(Msg->Msg.hwnd && (MsgWindow = IntGetWindowObject(Msg->Msg.hwnd)) &&
695 Msg->Msg.message >= WM_MOUSEFIRST && Msg->Msg.message <= WM_MOUSELAST)
696 {
697 USHORT HitTest;
698
699 if(IntTranslateMouseMessage(ThreadQueue, &Msg->Msg, &HitTest, TRUE))
700 /* FIXME - check message filter again, if the message doesn't match anymore,
701 search again */
702 {
703 IntReleaseWindowObject(MsgWindow);
704 /* eat the message, search again */
705 goto CheckMessages;
706 }
707 if(ThreadQueue->CaptureWindow == NULL)
708 {
709 IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
710 if((Msg->Msg.message != WM_MOUSEMOVE && Msg->Msg.message != WM_NCMOUSEMOVE) &&
711 IS_BTN_MESSAGE(Msg->Msg.message, DOWN) &&
712 IntActivateWindowMouse(ThreadQueue, &Msg->Msg, MsgWindow, &HitTest))
713 {
714 IntReleaseWindowObject(MsgWindow);
715 /* eat the message, search again */
716 goto CheckMessages;
717 }
718 }
719 }
720 else
721 {
722 IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
723 }
724
725 if(MsgWindow)
726 {
727 IntReleaseWindowObject(MsgWindow);
728 }
729
730 return TRUE;
731 }
732
733 USHORT HitTest;
734 if((Msg->Msg.hwnd && Msg->Msg.message >= WM_MOUSEFIRST && Msg->Msg.message <= WM_MOUSELAST) &&
735 IntTranslateMouseMessage(ThreadQueue, &Msg->Msg, &HitTest, FALSE))
736 /* FIXME - check message filter again, if the message doesn't match anymore,
737 search again */
738 {
739 /* eat the message, search again */
740 goto CheckMessages;
741 }
742
743 return TRUE;
744 }
745
746 return Present;
747 }
748
749 BOOL STDCALL
750 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
751 HWND Wnd,
752 UINT MsgFilterMin,
753 UINT MsgFilterMax,
754 UINT RemoveMsg)
755 {
756 NTSTATUS Status;
757 BOOL Present;
758 NTUSERGETMESSAGEINFO Info;
759 PWINDOW_OBJECT Window;
760 PMSGMEMORY MsgMemoryEntry;
761 PVOID UserMem;
762 UINT Size;
763 USER_MESSAGE Msg;
764
765 /* Validate input */
766 if (NULL != Wnd)
767 {
768 Window = IntGetWindowObject(Wnd);
769 if (NULL == Window)
770 {
771 Wnd = NULL;
772 }
773 else
774 {
775 IntReleaseWindowObject(Window);
776 }
777 }
778
779 if (MsgFilterMax < MsgFilterMin)
780 {
781 MsgFilterMin = 0;
782 MsgFilterMax = 0;
783 }
784
785 Present = IntPeekMessage(&Msg, Wnd, MsgFilterMin, MsgFilterMax, RemoveMsg);
786 if (Present)
787 {
788 Info.Msg = Msg.Msg;
789 /* See if this message type is present in the table */
790 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
791 if (NULL == MsgMemoryEntry)
792 {
793 /* Not present, no copying needed */
794 Info.LParamSize = 0;
795 }
796 else
797 {
798 /* Determine required size */
799 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
800 Info.Msg.lParam);
801 /* Allocate required amount of user-mode memory */
802 Info.LParamSize = Size;
803 UserMem = NULL;
804 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
805 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
806 if (! NT_SUCCESS(Status))
807 {
808 SetLastNtError(Status);
809 return (BOOL) -1;
810 }
811 /* Transfer lParam data to user-mode mem */
812 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
813 if (! NT_SUCCESS(Status))
814 {
815 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
816 &Info.LParamSize, MEM_DECOMMIT);
817 SetLastNtError(Status);
818 return (BOOL) -1;
819 }
820 Info.Msg.lParam = (LPARAM) UserMem;
821 }
822 if (Msg.FreeLParam && 0 != Msg.Msg.lParam)
823 {
824 ExFreePool((void *) Msg.Msg.lParam);
825 }
826 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
827 if (! NT_SUCCESS(Status))
828 {
829 SetLastNtError(Status);
830 return (BOOL) -1;
831 }
832 }
833
834 return Present;
835 }
836
837 static BOOL FASTCALL
838 IntWaitMessage(HWND Wnd,
839 UINT MsgFilterMin,
840 UINT MsgFilterMax)
841 {
842 PUSER_MESSAGE_QUEUE ThreadQueue;
843 NTSTATUS Status;
844 USER_MESSAGE Msg;
845
846 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
847
848 do
849 {
850 if (IntPeekMessage(&Msg, Wnd, MsgFilterMin, MsgFilterMax, PM_NOREMOVE))
851 {
852 return TRUE;
853 }
854
855 /* Nothing found. Wait for new messages. */
856 Status = MsqWaitForNewMessages(ThreadQueue);
857 }
858 while (STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63);
859
860 SetLastNtError(Status);
861
862 return FALSE;
863 }
864
865 BOOL STDCALL
866 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
867 HWND Wnd,
868 UINT MsgFilterMin,
869 UINT MsgFilterMax)
870 /*
871 * FUNCTION: Get a message from the calling thread's message queue.
872 * ARGUMENTS:
873 * UnsafeMsg - Pointer to the structure which receives the returned message.
874 * Wnd - Window whose messages are to be retrieved.
875 * MsgFilterMin - Integer value of the lowest message value to be
876 * retrieved.
877 * MsgFilterMax - Integer value of the highest message value to be
878 * retrieved.
879 */
880 {
881 BOOL GotMessage;
882 NTUSERGETMESSAGEINFO Info;
883 NTSTATUS Status;
884 PWINDOW_OBJECT Window;
885 PMSGMEMORY MsgMemoryEntry;
886 PVOID UserMem;
887 UINT Size;
888 USER_MESSAGE Msg;
889
890 /* Validate input */
891 if (NULL != Wnd)
892 {
893 Window = IntGetWindowObject(Wnd);
894 if(!Window)
895 Wnd = NULL;
896 else
897 IntReleaseWindowObject(Window);
898 }
899 if (MsgFilterMax < MsgFilterMin)
900 {
901 MsgFilterMin = 0;
902 MsgFilterMax = 0;
903 }
904
905 do
906 {
907 GotMessage = IntPeekMessage(&Msg, Wnd, MsgFilterMin, MsgFilterMax, PM_REMOVE);
908 if (GotMessage)
909 {
910 Info.Msg = Msg.Msg;
911 /* See if this message type is present in the table */
912 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
913 if (NULL == MsgMemoryEntry)
914 {
915 /* Not present, no copying needed */
916 Info.LParamSize = 0;
917 }
918 else
919 {
920 /* Determine required size */
921 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
922 Info.Msg.lParam);
923 /* Allocate required amount of user-mode memory */
924 Info.LParamSize = Size;
925 UserMem = NULL;
926 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
927 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
928
929 if (! NT_SUCCESS(Status))
930 {
931 SetLastNtError(Status);
932 return (BOOL) -1;
933 }
934 /* Transfer lParam data to user-mode mem */
935 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
936 if (! NT_SUCCESS(Status))
937 {
938 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
939 &Info.LParamSize, MEM_DECOMMIT);
940 SetLastNtError(Status);
941 return (BOOL) -1;
942 }
943 Info.Msg.lParam = (LPARAM) UserMem;
944 }
945 if (Msg.FreeLParam && 0 != Msg.Msg.lParam)
946 {
947 ExFreePool((void *) Msg.Msg.lParam);
948 }
949 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
950 if (! NT_SUCCESS(Status))
951 {
952 SetLastNtError(Status);
953 return (BOOL) -1;
954 }
955 }
956 else if (! IntWaitMessage(Wnd, MsgFilterMin, MsgFilterMax))
957 {
958 return (BOOL) -1;
959 }
960 }
961 while (! GotMessage);
962
963 return WM_QUIT != Info.Msg.message;
964 }
965
966 DWORD
967 STDCALL
968 NtUserMessageCall(
969 DWORD Unknown0,
970 DWORD Unknown1,
971 DWORD Unknown2,
972 DWORD Unknown3,
973 DWORD Unknown4,
974 DWORD Unknown5,
975 DWORD Unknown6)
976 {
977 UNIMPLEMENTED
978
979 return 0;
980 }
981
982 static NTSTATUS FASTCALL
983 CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
984 {
985 NTSTATUS Status;
986
987 PVOID KernelMem;
988 UINT Size;
989
990 *KernelModeMsg = *UserModeMsg;
991
992 /* See if this message type is present in the table */
993 if (NULL == MsgMemoryEntry)
994 {
995 /* Not present, no copying needed */
996 return STATUS_SUCCESS;
997 }
998
999 /* Determine required size */
1000 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
1001
1002 if (0 != Size)
1003 {
1004 /* Allocate kernel mem */
1005 KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
1006 if (NULL == KernelMem)
1007 {
1008 DPRINT1("Not enough memory to copy message to kernel mem\n");
1009 return STATUS_NO_MEMORY;
1010 }
1011 KernelModeMsg->lParam = (LPARAM) KernelMem;
1012
1013 /* Copy data if required */
1014 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
1015 {
1016 Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
1017 if (! NT_SUCCESS(Status))
1018 {
1019 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
1020 ExFreePool(KernelMem);
1021 return Status;
1022 }
1023 }
1024 else
1025 {
1026 /* Make sure we don't pass any secrets to usermode */
1027 RtlZeroMemory(KernelMem, Size);
1028 }
1029 }
1030 else
1031 {
1032 KernelModeMsg->lParam = 0;
1033 }
1034
1035 return STATUS_SUCCESS;
1036 }
1037
1038 static NTSTATUS FASTCALL
1039 CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
1040 {
1041 NTSTATUS Status;
1042 PMSGMEMORY MsgMemoryEntry;
1043 UINT Size;
1044
1045 /* See if this message type is present in the table */
1046 MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
1047 if (NULL == MsgMemoryEntry)
1048 {
1049 /* Not present, no copying needed */
1050 return STATUS_SUCCESS;
1051 }
1052
1053 /* Determine required size */
1054 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
1055
1056 if (0 != Size)
1057 {
1058 /* Copy data if required */
1059 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
1060 {
1061 Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
1062 if (! NT_SUCCESS(Status))
1063 {
1064 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1065 ExFreePool((PVOID) KernelModeMsg->lParam);
1066 return Status;
1067 }
1068 }
1069
1070 ExFreePool((PVOID) KernelModeMsg->lParam);
1071 }
1072
1073 return STATUS_SUCCESS;
1074 }
1075
1076 BOOL STDCALL
1077 NtUserPostMessage(HWND Wnd,
1078 UINT Msg,
1079 WPARAM wParam,
1080 LPARAM lParam)
1081 {
1082 PWINDOW_OBJECT Window;
1083 MSG UserModeMsg, KernelModeMsg;
1084 LARGE_INTEGER LargeTickCount;
1085 NTSTATUS Status;
1086 PMSGMEMORY MsgMemoryEntry;
1087
1088 if (WM_QUIT == Msg)
1089 {
1090 MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue, wParam);
1091 }
1092 else if (Wnd == HWND_BROADCAST)
1093 {
1094 HWND *List;
1095 PWINDOW_OBJECT DesktopWindow;
1096 ULONG i;
1097
1098 DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
1099 List = IntWinListChildren(DesktopWindow);
1100 IntReleaseWindowObject(DesktopWindow);
1101 if (List != NULL)
1102 {
1103 for (i = 0; List[i]; i++)
1104 NtUserPostMessage(List[i], Msg, wParam, lParam);
1105 ExFreePool(List);
1106 }
1107 }
1108 else
1109 {
1110 PSYSTEM_CURSORINFO CurInfo;
1111 Window = IntGetWindowObject(Wnd);
1112 if (NULL == Window)
1113 {
1114 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1115 return FALSE;
1116 }
1117
1118 UserModeMsg.hwnd = Wnd;
1119 UserModeMsg.message = Msg;
1120 UserModeMsg.wParam = wParam;
1121 UserModeMsg.lParam = lParam;
1122 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1123 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1124 if (! NT_SUCCESS(Status))
1125 {
1126 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1127 return FALSE;
1128 }
1129 CurInfo = IntGetSysCursorInfo(PsGetWin32Process()->WindowStation);
1130 KernelModeMsg.pt.x = CurInfo->x;
1131 KernelModeMsg.pt.y = CurInfo->y;
1132 KeQueryTickCount(&LargeTickCount);
1133 KernelModeMsg.time = LargeTickCount.u.LowPart;
1134 MsqPostMessage(Window->MessageQueue, &KernelModeMsg,
1135 NULL != MsgMemoryEntry && 0 != KernelModeMsg.lParam);
1136 IntReleaseWindowObject(Window);
1137 }
1138
1139 return TRUE;
1140 }
1141
1142 BOOL STDCALL
1143 NtUserPostThreadMessage(DWORD idThread,
1144 UINT Msg,
1145 WPARAM wParam,
1146 LPARAM lParam)
1147 {
1148 MSG UserModeMsg, KernelModeMsg;
1149 PETHREAD peThread;
1150 PW32THREAD pThread;
1151 NTSTATUS Status;
1152 PMSGMEMORY MsgMemoryEntry;
1153
1154 Status = PsLookupThreadByThreadId((void *)idThread,&peThread);
1155
1156 if( Status == STATUS_SUCCESS ) {
1157 pThread = peThread->Tcb.Win32Thread;
1158 if( !pThread || !pThread->MessageQueue )
1159 {
1160 ObDereferenceObject( peThread );
1161 return FALSE;
1162 }
1163
1164 UserModeMsg.hwnd = NULL;
1165 UserModeMsg.message = Msg;
1166 UserModeMsg.wParam = wParam;
1167 UserModeMsg.lParam = lParam;
1168 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1169 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1170 if (! NT_SUCCESS(Status))
1171 {
1172 ObDereferenceObject( peThread );
1173 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1174 return FALSE;
1175 }
1176 MsqPostMessage(pThread->MessageQueue, &KernelModeMsg,
1177 NULL != MsgMemoryEntry && 0 != KernelModeMsg.lParam);
1178 ObDereferenceObject( peThread );
1179 return TRUE;
1180 } else {
1181 SetLastNtError( Status );
1182 return FALSE;
1183 }
1184 }
1185
1186 DWORD STDCALL
1187 NtUserQuerySendMessage(DWORD Unknown0)
1188 {
1189 UNIMPLEMENTED;
1190
1191 return 0;
1192 }
1193
1194 LRESULT FASTCALL
1195 IntSendMessage(HWND hWnd,
1196 UINT Msg,
1197 WPARAM wParam,
1198 LPARAM lParam)
1199 {
1200 ULONG_PTR Result = 0;
1201 if(IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1202 {
1203 return (LRESULT)Result;
1204 }
1205 return 0;
1206 }
1207
1208 static LRESULT FASTCALL
1209 IntSendMessageTimeoutSingle(HWND hWnd,
1210 UINT Msg,
1211 WPARAM wParam,
1212 LPARAM lParam,
1213 UINT uFlags,
1214 UINT uTimeout,
1215 ULONG_PTR *uResult)
1216 {
1217 ULONG_PTR Result;
1218 NTSTATUS Status;
1219 PWINDOW_OBJECT Window;
1220 PMSGMEMORY MsgMemoryEntry;
1221 INT lParamBufferSize;
1222 LPARAM lParamPacked;
1223 PW32THREAD Win32Thread;
1224
1225 /* FIXME: Call hooks. */
1226 Window = IntGetWindowObject(hWnd);
1227 if (!Window)
1228 {
1229 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1230 return FALSE;
1231 }
1232
1233 Win32Thread = PsGetWin32Thread();
1234
1235 if (NULL != Win32Thread &&
1236 Window->MessageQueue == Win32Thread->MessageQueue)
1237 {
1238 if (Win32Thread->IsExiting)
1239 {
1240 /* Never send messages to exiting threads */
1241 IntReleaseWindowObject(Window);
1242 return FALSE;
1243 }
1244
1245 /* See if this message type is present in the table */
1246 MsgMemoryEntry = FindMsgMemory(Msg);
1247 if (NULL == MsgMemoryEntry)
1248 {
1249 lParamBufferSize = -1;
1250 }
1251 else
1252 {
1253 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1254 }
1255
1256 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam)))
1257 {
1258 IntReleaseWindowObject(Window);
1259 DPRINT1("Failed to pack message parameters\n");
1260 return FALSE;
1261 }
1262 if (0xFFFF0000 != ((DWORD) Window->WndProcW & 0xFFFF0000))
1263 {
1264 Result = (ULONG_PTR)IntCallWindowProc(Window->WndProcW, FALSE, hWnd, Msg, wParam,
1265 lParamPacked,lParamBufferSize);
1266 }
1267 else
1268 {
1269 Result = (ULONG_PTR)IntCallWindowProc(Window->WndProcA, TRUE, hWnd, Msg, wParam,
1270 lParamPacked,lParamBufferSize);
1271 }
1272
1273 if(uResult)
1274 {
1275 *uResult = Result;
1276 }
1277
1278 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam)))
1279 {
1280 IntReleaseWindowObject(Window);
1281 DPRINT1("Failed to unpack message parameters\n");
1282 return TRUE;
1283 }
1284
1285 IntReleaseWindowObject(Window);
1286 return TRUE;
1287 }
1288
1289 if(uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->MessageQueue))
1290 {
1291 IntReleaseWindowObject(Window);
1292 /* FIXME - Set a LastError? */
1293 return FALSE;
1294 }
1295
1296 Status = MsqSendMessage(Window->MessageQueue, hWnd, Msg, wParam, lParam,
1297 uTimeout, (uFlags & SMTO_BLOCK), uResult);
1298 IntReleaseWindowObject(Window);
1299 if (STATUS_TIMEOUT == Status)
1300 {
1301 /* MSDN says GetLastError() should return 0 after timeout */
1302 SetLastWin32Error(0);
1303 return FALSE;
1304 }
1305 else if (! NT_SUCCESS(Status))
1306 {
1307 SetLastNtError(Status);
1308 return FALSE;
1309 }
1310
1311 return TRUE;
1312 }
1313
1314 LRESULT FASTCALL
1315 IntSendMessageTimeout(HWND hWnd,
1316 UINT Msg,
1317 WPARAM wParam,
1318 LPARAM lParam,
1319 UINT uFlags,
1320 UINT uTimeout,
1321 ULONG_PTR *uResult)
1322 {
1323 PWINDOW_OBJECT DesktopWindow;
1324 HWND *Children;
1325 HWND *Child;
1326
1327 if (HWND_BROADCAST != hWnd)
1328 {
1329 return IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1330 }
1331
1332 DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
1333 if (NULL == DesktopWindow)
1334 {
1335 SetLastWin32Error(ERROR_INTERNAL_ERROR);
1336 return 0;
1337 }
1338 Children = IntWinListChildren(DesktopWindow);
1339 IntReleaseWindowObject(DesktopWindow);
1340 if (NULL == Children)
1341 {
1342 return 0;
1343 }
1344
1345 for (Child = Children; NULL != *Child; Child++)
1346 {
1347 IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1348 }
1349
1350 ExFreePool(Children);
1351
1352 return (LRESULT) TRUE;
1353 }
1354
1355
1356 /* This function posts a message if the destination's message queue belongs to
1357 another thread, otherwise it sends the message. It does not support broadcast
1358 messages! */
1359 LRESULT FASTCALL
1360 IntPostOrSendMessage(HWND hWnd,
1361 UINT Msg,
1362 WPARAM wParam,
1363 LPARAM lParam)
1364 {
1365 ULONG_PTR Result;
1366 PWINDOW_OBJECT Window;
1367
1368 if(hWnd == HWND_BROADCAST)
1369 {
1370 return 0;
1371 }
1372
1373 Window = IntGetWindowObject(hWnd);
1374 if(!Window)
1375 {
1376 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1377 return 0;
1378 }
1379
1380 if(Window->MessageQueue != PsGetWin32Thread()->MessageQueue)
1381 {
1382 Result = NtUserPostMessage(hWnd, Msg, wParam, lParam);
1383 }
1384 else
1385 {
1386 if(!IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1387 {
1388 Result = 0;
1389 }
1390 }
1391
1392 IntReleaseWindowObject(Window);
1393
1394 return (LRESULT)Result;
1395 }
1396
1397 LRESULT FASTCALL
1398 IntDoSendMessage(HWND Wnd,
1399 UINT Msg,
1400 WPARAM wParam,
1401 LPARAM lParam,
1402 PDOSENDMESSAGE dsm,
1403 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1404 {
1405 LRESULT Result = TRUE;
1406 NTSTATUS Status;
1407 PWINDOW_OBJECT Window;
1408 NTUSERSENDMESSAGEINFO Info;
1409 MSG UserModeMsg;
1410 MSG KernelModeMsg;
1411 PMSGMEMORY MsgMemoryEntry;
1412
1413 RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));
1414
1415 /* FIXME: Call hooks. */
1416 if (HWND_BROADCAST != Wnd)
1417 {
1418 Window = IntGetWindowObject(Wnd);
1419 if (NULL == Window)
1420 {
1421 /* Tell usermode to not touch this one */
1422 Info.HandledByKernel = TRUE;
1423 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1424 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1425 return 0;
1426 }
1427 }
1428
1429 /* FIXME: Check for an exiting window. */
1430
1431 /* See if the current thread can handle the message */
1432 if (HWND_BROADCAST != Wnd && NULL != PsGetWin32Thread() &&
1433 Window->MessageQueue == PsGetWin32Thread()->MessageQueue)
1434 {
1435 /* Gather the information usermode needs to call the window proc directly */
1436 Info.HandledByKernel = FALSE;
1437 if (0xFFFF0000 != ((DWORD) Window->WndProcW & 0xFFFF0000))
1438 {
1439 if (0xFFFF0000 != ((DWORD) Window->WndProcA & 0xFFFF0000))
1440 {
1441 /* Both Unicode and Ansi winprocs are real, see what usermode prefers */
1442 Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi),
1443 sizeof(BOOL));
1444 if (! NT_SUCCESS(Status))
1445 {
1446 Info.Ansi = ! Window->Unicode;
1447 }
1448 Info.Proc = (Info.Ansi ? Window->WndProcA : Window->WndProcW);
1449 }
1450 else
1451 {
1452 /* Real Unicode winproc */
1453 Info.Ansi = FALSE;
1454 Info.Proc = Window->WndProcW;
1455 }
1456 }
1457 else
1458 {
1459 /* Must have real Ansi winproc */
1460 Info.Ansi = TRUE;
1461 Info.Proc = Window->WndProcA;
1462 }
1463 IntReleaseWindowObject(Window);
1464 }
1465 else
1466 {
1467 /* Must be handled by other thread */
1468 if (HWND_BROADCAST != Wnd)
1469 {
1470 IntReleaseWindowObject(Window);
1471 }
1472 Info.HandledByKernel = TRUE;
1473 UserModeMsg.hwnd = Wnd;
1474 UserModeMsg.message = Msg;
1475 UserModeMsg.wParam = wParam;
1476 UserModeMsg.lParam = lParam;
1477 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1478 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1479 if (! NT_SUCCESS(Status))
1480 {
1481 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1482 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1483 return (dsm ? 0 : -1);
1484 }
1485 if(!dsm)
1486 {
1487 Result = IntSendMessage(KernelModeMsg.hwnd, KernelModeMsg.message,
1488 KernelModeMsg.wParam, KernelModeMsg.lParam);
1489 }
1490 else
1491 {
1492 Result = IntSendMessageTimeout(KernelModeMsg.hwnd, KernelModeMsg.message,
1493 KernelModeMsg.wParam, KernelModeMsg.lParam,
1494 dsm->uFlags, dsm->uTimeout, &dsm->Result);
1495 }
1496 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1497 if (! NT_SUCCESS(Status))
1498 {
1499 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1500 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1501 return(dsm ? 0 : -1);
1502 }
1503 }
1504
1505 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1506 if (! NT_SUCCESS(Status))
1507 {
1508 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1509 }
1510
1511 return (LRESULT)Result;
1512 }
1513
1514 LRESULT STDCALL
1515 NtUserSendMessageTimeout(HWND hWnd,
1516 UINT Msg,
1517 WPARAM wParam,
1518 LPARAM lParam,
1519 UINT uFlags,
1520 UINT uTimeout,
1521 ULONG_PTR *uResult,
1522 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1523 {
1524 DOSENDMESSAGE dsm;
1525 LRESULT Result;
1526
1527 dsm.uFlags = uFlags;
1528 dsm.uTimeout = uTimeout;
1529 Result = IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
1530 if(uResult != NULL && Result != 0)
1531 {
1532 NTSTATUS Status;
1533
1534 Status = MmCopyToCaller(uResult, &dsm.Result, sizeof(ULONG_PTR));
1535 if(!NT_SUCCESS(Status))
1536 {
1537 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1538 return FALSE;
1539 }
1540 }
1541 return Result;
1542 }
1543
1544 LRESULT STDCALL
1545 NtUserSendMessage(HWND Wnd,
1546 UINT Msg,
1547 WPARAM wParam,
1548 LPARAM lParam,
1549 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1550 {
1551 return IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo);
1552 }
1553
1554 BOOL STDCALL
1555 NtUserSendMessageCallback(HWND hWnd,
1556 UINT Msg,
1557 WPARAM wParam,
1558 LPARAM lParam,
1559 SENDASYNCPROC lpCallBack,
1560 ULONG_PTR dwData)
1561 {
1562 UNIMPLEMENTED;
1563
1564 return 0;
1565 }
1566
1567 BOOL STDCALL
1568 NtUserSendNotifyMessage(HWND hWnd,
1569 UINT Msg,
1570 WPARAM wParam,
1571 LPARAM lParam)
1572 {
1573 UNIMPLEMENTED;
1574
1575 return 0;
1576 }
1577
1578 BOOL STDCALL
1579 NtUserWaitMessage(VOID)
1580 {
1581
1582 return IntWaitMessage(NULL, 0, 0);
1583 }
1584
1585 DWORD STDCALL
1586 NtUserGetQueueStatus(BOOL ClearChanges)
1587 {
1588 PUSER_MESSAGE_QUEUE Queue;
1589 DWORD Result;
1590
1591 Queue = PsGetWin32Thread()->MessageQueue;
1592
1593 IntLockMessageQueue(Queue);
1594
1595 Result = MAKELONG(Queue->ChangedBits, Queue->WakeBits);
1596 if (ClearChanges)
1597 {
1598 Queue->ChangedBits = 0;
1599 }
1600
1601 IntUnLockMessageQueue(Queue);
1602
1603 return Result;
1604 }
1605
1606 BOOL STDCALL
1607 IntInitMessagePumpHook()
1608 {
1609 PsGetCurrentThread()->Tcb.Win32Thread->MessagePumpHookValue++;
1610 return TRUE;
1611 }
1612
1613 BOOL STDCALL
1614 IntUninitMessagePumpHook()
1615 {
1616 if (PsGetCurrentThread()->Tcb.Win32Thread->MessagePumpHookValue <= 0)
1617 {
1618 return FALSE;
1619 }
1620 PsGetCurrentThread()->Tcb.Win32Thread->MessagePumpHookValue--;
1621 return TRUE;
1622 }
1623
1624 /* EOF */