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