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