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