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