Don't free the memory for LParam in NtUserPeekMessage if called with PM_NOREMOVE...
[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 PSYSTEM_CURSORINFO CurInfo;
1127 Window = IntGetWindowObject(Wnd);
1128 if (NULL == Window)
1129 {
1130 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1131 return FALSE;
1132 }
1133 if(Window->Status & WINDOWSTATUS_DESTROYING)
1134 {
1135 IntReleaseWindowObject(Window);
1136 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
1137 /* FIXME - last error code? */
1138 return FALSE;
1139 }
1140
1141 UserModeMsg.hwnd = Wnd;
1142 UserModeMsg.message = Msg;
1143 UserModeMsg.wParam = wParam;
1144 UserModeMsg.lParam = lParam;
1145 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1146 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1147 if (! NT_SUCCESS(Status))
1148 {
1149 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1150 return FALSE;
1151 }
1152 CurInfo = IntGetSysCursorInfo(PsGetWin32Thread()->Desktop->WindowStation);
1153 KernelModeMsg.pt.x = CurInfo->x;
1154 KernelModeMsg.pt.y = CurInfo->y;
1155 KeQueryTickCount(&LargeTickCount);
1156 KernelModeMsg.time = LargeTickCount.u.LowPart;
1157 MsqPostMessage(Window->MessageQueue, &KernelModeMsg,
1158 NULL != MsgMemoryEntry && 0 != KernelModeMsg.lParam,
1159 QS_POSTMESSAGE);
1160 IntReleaseWindowObject(Window);
1161 }
1162
1163 return TRUE;
1164 }
1165
1166 BOOL STDCALL
1167 NtUserPostThreadMessage(DWORD idThread,
1168 UINT Msg,
1169 WPARAM wParam,
1170 LPARAM lParam)
1171 {
1172 MSG UserModeMsg, KernelModeMsg;
1173 PETHREAD peThread;
1174 PW32THREAD pThread;
1175 NTSTATUS Status;
1176 PMSGMEMORY MsgMemoryEntry;
1177
1178 Status = PsLookupThreadByThreadId((void *)idThread,&peThread);
1179
1180 if( Status == STATUS_SUCCESS ) {
1181 pThread = peThread->Tcb.Win32Thread;
1182 if( !pThread || !pThread->MessageQueue )
1183 {
1184 ObDereferenceObject( peThread );
1185 return FALSE;
1186 }
1187
1188 UserModeMsg.hwnd = NULL;
1189 UserModeMsg.message = Msg;
1190 UserModeMsg.wParam = wParam;
1191 UserModeMsg.lParam = lParam;
1192 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1193 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1194 if (! NT_SUCCESS(Status))
1195 {
1196 ObDereferenceObject( peThread );
1197 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1198 return FALSE;
1199 }
1200 MsqPostMessage(pThread->MessageQueue, &KernelModeMsg,
1201 NULL != MsgMemoryEntry && 0 != KernelModeMsg.lParam,
1202 QS_POSTMESSAGE);
1203 ObDereferenceObject( peThread );
1204 return TRUE;
1205 } else {
1206 SetLastNtError( Status );
1207 return FALSE;
1208 }
1209 }
1210
1211 DWORD STDCALL
1212 NtUserQuerySendMessage(DWORD Unknown0)
1213 {
1214 UNIMPLEMENTED;
1215
1216 return 0;
1217 }
1218
1219 LRESULT FASTCALL
1220 IntSendMessage(HWND hWnd,
1221 UINT Msg,
1222 WPARAM wParam,
1223 LPARAM lParam)
1224 {
1225 ULONG_PTR Result = 0;
1226 if(IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1227 {
1228 return (LRESULT)Result;
1229 }
1230 return 0;
1231 }
1232
1233 static LRESULT FASTCALL
1234 IntSendMessageTimeoutSingle(HWND hWnd,
1235 UINT Msg,
1236 WPARAM wParam,
1237 LPARAM lParam,
1238 UINT uFlags,
1239 UINT uTimeout,
1240 ULONG_PTR *uResult)
1241 {
1242 ULONG_PTR Result;
1243 NTSTATUS Status;
1244 PWINDOW_OBJECT Window;
1245 PMSGMEMORY MsgMemoryEntry;
1246 INT lParamBufferSize;
1247 LPARAM lParamPacked;
1248 PW32THREAD Win32Thread;
1249
1250 /* FIXME: Call hooks. */
1251 Window = IntGetWindowObject(hWnd);
1252 if (!Window)
1253 {
1254 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1255 return FALSE;
1256 }
1257
1258 Win32Thread = PsGetWin32Thread();
1259
1260 if (NULL != Win32Thread &&
1261 Window->MessageQueue == Win32Thread->MessageQueue)
1262 {
1263 if (Win32Thread->IsExiting)
1264 {
1265 /* Never send messages to exiting threads */
1266 IntReleaseWindowObject(Window);
1267 return FALSE;
1268 }
1269
1270 /* See if this message type is present in the table */
1271 MsgMemoryEntry = FindMsgMemory(Msg);
1272 if (NULL == MsgMemoryEntry)
1273 {
1274 lParamBufferSize = -1;
1275 }
1276 else
1277 {
1278 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1279 }
1280
1281 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam)))
1282 {
1283 IntReleaseWindowObject(Window);
1284 DPRINT1("Failed to pack message parameters\n");
1285 return FALSE;
1286 }
1287 if (0xFFFF0000 != ((DWORD) Window->WndProcW & 0xFFFF0000))
1288 {
1289 Result = (ULONG_PTR)IntCallWindowProc(Window->WndProcW, FALSE, hWnd, Msg, wParam,
1290 lParamPacked,lParamBufferSize);
1291 }
1292 else
1293 {
1294 Result = (ULONG_PTR)IntCallWindowProc(Window->WndProcA, TRUE, hWnd, Msg, wParam,
1295 lParamPacked,lParamBufferSize);
1296 }
1297
1298 if(uResult)
1299 {
1300 *uResult = Result;
1301 }
1302
1303 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam)))
1304 {
1305 IntReleaseWindowObject(Window);
1306 DPRINT1("Failed to unpack message parameters\n");
1307 return TRUE;
1308 }
1309
1310 IntReleaseWindowObject(Window);
1311 return TRUE;
1312 }
1313
1314 if(uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->MessageQueue))
1315 {
1316 IntReleaseWindowObject(Window);
1317 /* FIXME - Set a LastError? */
1318 return FALSE;
1319 }
1320
1321 if(Window->Status & WINDOWSTATUS_DESTROYING)
1322 {
1323 IntReleaseWindowObject(Window);
1324 /* FIXME - last error? */
1325 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1326 return FALSE;
1327 }
1328
1329 Status = MsqSendMessage(Window->MessageQueue, hWnd, Msg, wParam, lParam,
1330 uTimeout, (uFlags & SMTO_BLOCK), uResult);
1331 IntReleaseWindowObject(Window);
1332 if (STATUS_TIMEOUT == Status)
1333 {
1334 /* MSDN says GetLastError() should return 0 after timeout */
1335 SetLastWin32Error(0);
1336 return FALSE;
1337 }
1338 else if (! NT_SUCCESS(Status))
1339 {
1340 SetLastNtError(Status);
1341 return FALSE;
1342 }
1343
1344 return TRUE;
1345 }
1346
1347 LRESULT FASTCALL
1348 IntSendMessageTimeout(HWND hWnd,
1349 UINT Msg,
1350 WPARAM wParam,
1351 LPARAM lParam,
1352 UINT uFlags,
1353 UINT uTimeout,
1354 ULONG_PTR *uResult)
1355 {
1356 PWINDOW_OBJECT DesktopWindow;
1357 HWND *Children;
1358 HWND *Child;
1359
1360 if (HWND_BROADCAST != hWnd)
1361 {
1362 return IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1363 }
1364
1365 DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
1366 if (NULL == DesktopWindow)
1367 {
1368 SetLastWin32Error(ERROR_INTERNAL_ERROR);
1369 return 0;
1370 }
1371 Children = IntWinListChildren(DesktopWindow);
1372 IntReleaseWindowObject(DesktopWindow);
1373 if (NULL == Children)
1374 {
1375 return 0;
1376 }
1377
1378 for (Child = Children; NULL != *Child; Child++)
1379 {
1380 IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1381 }
1382
1383 ExFreePool(Children);
1384
1385 return (LRESULT) TRUE;
1386 }
1387
1388
1389 /* This function posts a message if the destination's message queue belongs to
1390 another thread, otherwise it sends the message. It does not support broadcast
1391 messages! */
1392 LRESULT FASTCALL
1393 IntPostOrSendMessage(HWND hWnd,
1394 UINT Msg,
1395 WPARAM wParam,
1396 LPARAM lParam)
1397 {
1398 ULONG_PTR Result;
1399 PWINDOW_OBJECT Window;
1400
1401 if(hWnd == HWND_BROADCAST)
1402 {
1403 return 0;
1404 }
1405
1406 Window = IntGetWindowObject(hWnd);
1407 if(!Window)
1408 {
1409 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1410 return 0;
1411 }
1412
1413 if(Window->MessageQueue != PsGetWin32Thread()->MessageQueue)
1414 {
1415 Result = NtUserPostMessage(hWnd, Msg, wParam, lParam);
1416 }
1417 else
1418 {
1419 if(!IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1420 {
1421 Result = 0;
1422 }
1423 }
1424
1425 IntReleaseWindowObject(Window);
1426
1427 return (LRESULT)Result;
1428 }
1429
1430 LRESULT FASTCALL
1431 IntDoSendMessage(HWND Wnd,
1432 UINT Msg,
1433 WPARAM wParam,
1434 LPARAM lParam,
1435 PDOSENDMESSAGE dsm,
1436 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1437 {
1438 LRESULT Result = TRUE;
1439 NTSTATUS Status;
1440 PWINDOW_OBJECT Window;
1441 NTUSERSENDMESSAGEINFO Info;
1442 MSG UserModeMsg;
1443 MSG KernelModeMsg;
1444 PMSGMEMORY MsgMemoryEntry;
1445
1446 RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));
1447
1448 /* FIXME: Call hooks. */
1449 if (HWND_BROADCAST != Wnd)
1450 {
1451 Window = IntGetWindowObject(Wnd);
1452 if (NULL == Window)
1453 {
1454 /* Tell usermode to not touch this one */
1455 Info.HandledByKernel = TRUE;
1456 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1457 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1458 return 0;
1459 }
1460 }
1461
1462 /* FIXME: Check for an exiting window. */
1463
1464 /* See if the current thread can handle the message */
1465 if (HWND_BROADCAST != Wnd && NULL != PsGetWin32Thread() &&
1466 Window->MessageQueue == PsGetWin32Thread()->MessageQueue)
1467 {
1468 /* Gather the information usermode needs to call the window proc directly */
1469 Info.HandledByKernel = FALSE;
1470 if (0xFFFF0000 != ((DWORD) Window->WndProcW & 0xFFFF0000))
1471 {
1472 if (0xFFFF0000 != ((DWORD) Window->WndProcA & 0xFFFF0000))
1473 {
1474 /* Both Unicode and Ansi winprocs are real, see what usermode prefers */
1475 Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi),
1476 sizeof(BOOL));
1477 if (! NT_SUCCESS(Status))
1478 {
1479 Info.Ansi = ! Window->Unicode;
1480 }
1481 Info.Proc = (Info.Ansi ? Window->WndProcA : Window->WndProcW);
1482 }
1483 else
1484 {
1485 /* Real Unicode winproc */
1486 Info.Ansi = FALSE;
1487 Info.Proc = Window->WndProcW;
1488 }
1489 }
1490 else
1491 {
1492 /* Must have real Ansi winproc */
1493 Info.Ansi = TRUE;
1494 Info.Proc = Window->WndProcA;
1495 }
1496 IntReleaseWindowObject(Window);
1497 }
1498 else
1499 {
1500 /* Must be handled by other thread */
1501 if (HWND_BROADCAST != Wnd)
1502 {
1503 IntReleaseWindowObject(Window);
1504 }
1505 Info.HandledByKernel = TRUE;
1506 UserModeMsg.hwnd = Wnd;
1507 UserModeMsg.message = Msg;
1508 UserModeMsg.wParam = wParam;
1509 UserModeMsg.lParam = lParam;
1510 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1511 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1512 if (! NT_SUCCESS(Status))
1513 {
1514 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1515 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1516 return (dsm ? 0 : -1);
1517 }
1518 if(!dsm)
1519 {
1520 Result = IntSendMessage(KernelModeMsg.hwnd, KernelModeMsg.message,
1521 KernelModeMsg.wParam, KernelModeMsg.lParam);
1522 }
1523 else
1524 {
1525 Result = IntSendMessageTimeout(KernelModeMsg.hwnd, KernelModeMsg.message,
1526 KernelModeMsg.wParam, KernelModeMsg.lParam,
1527 dsm->uFlags, dsm->uTimeout, &dsm->Result);
1528 }
1529 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1530 if (! NT_SUCCESS(Status))
1531 {
1532 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1533 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1534 return(dsm ? 0 : -1);
1535 }
1536 }
1537
1538 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1539 if (! NT_SUCCESS(Status))
1540 {
1541 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1542 }
1543
1544 return (LRESULT)Result;
1545 }
1546
1547 LRESULT STDCALL
1548 NtUserSendMessageTimeout(HWND hWnd,
1549 UINT Msg,
1550 WPARAM wParam,
1551 LPARAM lParam,
1552 UINT uFlags,
1553 UINT uTimeout,
1554 ULONG_PTR *uResult,
1555 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1556 {
1557 DOSENDMESSAGE dsm;
1558 LRESULT Result;
1559
1560 dsm.uFlags = uFlags;
1561 dsm.uTimeout = uTimeout;
1562 Result = IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
1563 if(uResult != NULL && Result != 0)
1564 {
1565 NTSTATUS Status;
1566
1567 Status = MmCopyToCaller(uResult, &dsm.Result, sizeof(ULONG_PTR));
1568 if(!NT_SUCCESS(Status))
1569 {
1570 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1571 return FALSE;
1572 }
1573 }
1574 return Result;
1575 }
1576
1577 LRESULT STDCALL
1578 NtUserSendMessage(HWND Wnd,
1579 UINT Msg,
1580 WPARAM wParam,
1581 LPARAM lParam,
1582 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1583 {
1584 return IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo);
1585 }
1586
1587 BOOL STDCALL
1588 NtUserSendMessageCallback(HWND hWnd,
1589 UINT Msg,
1590 WPARAM wParam,
1591 LPARAM lParam,
1592 SENDASYNCPROC lpCallBack,
1593 ULONG_PTR dwData)
1594 {
1595 UNIMPLEMENTED;
1596
1597 return 0;
1598 }
1599
1600 BOOL STDCALL
1601 NtUserSendNotifyMessage(HWND hWnd,
1602 UINT Msg,
1603 WPARAM wParam,
1604 LPARAM lParam)
1605 {
1606 UNIMPLEMENTED;
1607
1608 return 0;
1609 }
1610
1611 BOOL STDCALL
1612 NtUserWaitMessage(VOID)
1613 {
1614
1615 return IntWaitMessage(NULL, 0, 0);
1616 }
1617
1618 DWORD STDCALL
1619 NtUserGetQueueStatus(BOOL ClearChanges)
1620 {
1621 PUSER_MESSAGE_QUEUE Queue;
1622 DWORD Result;
1623
1624 Queue = PsGetWin32Thread()->MessageQueue;
1625
1626 IntLockMessageQueue(Queue);
1627
1628 Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
1629 if (ClearChanges)
1630 {
1631 Queue->ChangedBits = 0;
1632 }
1633
1634 IntUnLockMessageQueue(Queue);
1635
1636 return Result;
1637 }
1638
1639 BOOL STDCALL
1640 IntInitMessagePumpHook()
1641 {
1642 PsGetCurrentThread()->Tcb.Win32Thread->MessagePumpHookValue++;
1643 return TRUE;
1644 }
1645
1646 BOOL STDCALL
1647 IntUninitMessagePumpHook()
1648 {
1649 if (PsGetCurrentThread()->Tcb.Win32Thread->MessagePumpHookValue <= 0)
1650 {
1651 return FALSE;
1652 }
1653 PsGetCurrentThread()->Tcb.Win32Thread->MessagePumpHookValue--;
1654 return TRUE;
1655 }
1656
1657 /* EOF */