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