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