- NtUserWaitForInputIdle: Call EngGetTickCount, removing duplicated code
[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 _SEH2_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 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
171 {
172 DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode());
173 Size = 0;
174 }
175 _SEH2_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 static
299 VOID
300 FASTCALL
301 IntCallWndProc
302 ( PWINDOW_OBJECT Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
303 {
304 BOOL SameThread = FALSE;
305
306 if (Window->ti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->ThreadInfo)
307 SameThread = TRUE;
308
309 if ((!SameThread && (Window->ti->Hooks & HOOKID_TO_FLAG(WH_CALLWNDPROC))) ||
310 (SameThread && ISITHOOKED(WH_CALLWNDPROC)) )
311 {
312 CWPSTRUCT CWP;
313 CWP.hwnd = hWnd;
314 CWP.message = Msg;
315 CWP.wParam = wParam;
316 CWP.lParam = lParam;
317 co_HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, SameThread, (LPARAM)&CWP );
318 }
319 }
320 static
321 VOID
322 FASTCALL
323 IntCallWndProcRet
324 ( PWINDOW_OBJECT Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *uResult)
325 {
326 BOOL SameThread = FALSE;
327
328 if (Window->ti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->ThreadInfo)
329 SameThread = TRUE;
330
331 if ((!SameThread && (Window->ti->Hooks & HOOKID_TO_FLAG(WH_CALLWNDPROCRET))) ||
332 (SameThread && ISITHOOKED(WH_CALLWNDPROCRET)) )
333 {
334 CWPRETSTRUCT CWPR;
335 CWPR.hwnd = hWnd;
336 CWPR.message = Msg;
337 CWPR.wParam = wParam;
338 CWPR.lParam = lParam;
339 CWPR.lResult = *uResult;
340 co_HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, SameThread, (LPARAM)&CWPR );
341 }
342 }
343
344
345 BOOL
346 APIENTRY
347 NtUserCallMsgFilter(
348 LPMSG lpmsg,
349 INT code)
350 {
351 BOOL BadChk = FALSE, Ret = TRUE;
352 MSG Msg;
353 DECLARE_RETURN(BOOL);
354
355 DPRINT("Enter NtUserCallMsgFilter\n");
356 UserEnterExclusive();
357 if (lpmsg)
358 {
359 _SEH2_TRY
360 {
361 ProbeForRead((PVOID)lpmsg,
362 sizeof(MSG),
363 1);
364 RtlCopyMemory( &Msg,
365 (PVOID)lpmsg,
366 sizeof(MSG));
367 }
368 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
369 {
370 BadChk = TRUE;
371 }
372 _SEH2_END;
373 }
374 else
375 RETURN( FALSE);
376
377 if (BadChk) RETURN( FALSE);
378
379 if (!co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
380 {
381 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
382 }
383
384 _SEH2_TRY
385 {
386 ProbeForWrite((PVOID)lpmsg,
387 sizeof(MSG),
388 1);
389 RtlCopyMemory((PVOID)lpmsg,
390 &Msg,
391 sizeof(MSG));
392 }
393 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
394 {
395 BadChk = TRUE;
396 }
397 _SEH2_END;
398 if (BadChk) RETURN( FALSE);
399 RETURN( Ret)
400
401 CLEANUP:
402 DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_);
403 UserLeave();
404 END_CLEANUP;
405 }
406
407 LRESULT APIENTRY
408 NtUserDispatchMessage(PNTUSERDISPATCHMESSAGEINFO UnsafeMsgInfo)
409 {
410 NTSTATUS Status;
411 NTUSERDISPATCHMESSAGEINFO MsgInfo;
412 LRESULT Result = TRUE;
413 DECLARE_RETURN(LRESULT);
414
415 DPRINT("Enter NtUserDispatchMessage\n");
416 UserEnterExclusive();
417
418 Status = MmCopyFromCaller(&MsgInfo, UnsafeMsgInfo, sizeof(NTUSERDISPATCHMESSAGEINFO));
419 if (! NT_SUCCESS(Status))
420 {
421 SetLastNtError(Status);
422 RETURN( 0);
423 }
424
425 /* Process timer messages. */
426 if (WM_TIMER == MsgInfo.Msg.message && 0 != MsgInfo.Msg.lParam)
427 {
428 LARGE_INTEGER LargeTickCount;
429 /* FIXME: Call hooks. */
430
431 /* FIXME: Check for continuing validity of timer. */
432
433 MsgInfo.HandledByKernel = FALSE;
434 KeQueryTickCount(&LargeTickCount);
435 MsgInfo.Proc = (WNDPROC) MsgInfo.Msg.lParam;
436 MsgInfo.Msg.lParam = (LPARAM)LargeTickCount.u.LowPart;
437 }
438 else if (NULL == MsgInfo.Msg.hwnd)
439 {
440 MsgInfo.HandledByKernel = TRUE;
441 Result = 0;
442 }
443 else
444 {
445 PWINDOW_OBJECT Window;
446
447 /* Get the window object. */
448 Window = UserGetWindowObject(MsgInfo.Msg.hwnd);
449 if (NULL == Window)
450 {
451 MsgInfo.HandledByKernel = TRUE;
452 Result = 0;
453 }
454 else
455 {
456 if (Window->OwnerThread != PsGetCurrentThread())
457 {
458 DPRINT1("Window doesn't belong to the calling thread!\n");
459 MsgInfo.HandledByKernel = TRUE;
460 Result = 0;
461 }
462 else
463 {
464 /* FIXME: Call hook procedures. */
465
466 MsgInfo.HandledByKernel = FALSE;
467 Result = 0;
468
469 if (Window->Wnd->IsSystem)
470 {
471 MsgInfo.Proc = (!MsgInfo.Ansi ? Window->Wnd->WndProc : Window->Wnd->WndProcExtra);
472 }
473 else
474 {
475 MsgInfo.Ansi = !Window->Wnd->Unicode;
476 MsgInfo.Proc = Window->Wnd->WndProc;
477 }
478 }
479 }
480 }
481 Status = MmCopyToCaller(UnsafeMsgInfo, &MsgInfo, sizeof(NTUSERDISPATCHMESSAGEINFO));
482 if (! NT_SUCCESS(Status))
483 {
484 SetLastNtError(Status);
485 RETURN( 0);
486 }
487
488 RETURN( Result);
489
490 CLEANUP:
491 DPRINT("Leave NtUserDispatchMessage. ret=%i\n", _ret_);
492 UserLeave();
493 END_CLEANUP;
494 }
495
496
497 BOOL APIENTRY
498 NtUserTranslateMessage(LPMSG lpMsg,
499 HKL dwhkl)
500 {
501 NTSTATUS Status;
502 MSG SafeMsg;
503 DECLARE_RETURN(BOOL);
504
505 DPRINT("Enter NtUserTranslateMessage\n");
506 UserEnterExclusive();
507
508 Status = MmCopyFromCaller(&SafeMsg, lpMsg, sizeof(MSG));
509 if(!NT_SUCCESS(Status))
510 {
511 SetLastNtError(Status);
512 RETURN( FALSE);
513 }
514
515 RETURN( IntTranslateKbdMessage(&SafeMsg, dwhkl));
516
517 CLEANUP:
518 DPRINT("Leave NtUserTranslateMessage: ret=%i\n",_ret_);
519 UserLeave();
520 END_CLEANUP;
521 }
522
523
524 VOID FASTCALL
525 co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg)
526 {
527 if(!Msg->hwnd || ThreadQueue->CaptureWindow)
528 {
529 return;
530 }
531
532 switch(Msg->message)
533 {
534 case WM_MOUSEMOVE:
535 {
536 co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
537 break;
538 }
539 case WM_NCMOUSEMOVE:
540 {
541 co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
542 break;
543 }
544 case WM_LBUTTONDOWN:
545 case WM_MBUTTONDOWN:
546 case WM_RBUTTONDOWN:
547 case WM_XBUTTONDOWN:
548 case WM_LBUTTONDBLCLK:
549 case WM_MBUTTONDBLCLK:
550 case WM_RBUTTONDBLCLK:
551 case WM_XBUTTONDBLCLK:
552 {
553 WPARAM wParam;
554 PSYSTEM_CURSORINFO CurInfo;
555
556 if(!IntGetWindowStationObject(InputWindowStation))
557 {
558 break;
559 }
560 CurInfo = IntGetSysCursorInfo(InputWindowStation);
561 wParam = (WPARAM)(CurInfo->ButtonsDown);
562 ObDereferenceObject(InputWindowStation);
563
564 co_IntSendMessage(Msg->hwnd, WM_MOUSEMOVE, wParam, Msg->lParam);
565 co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
566 break;
567 }
568 case WM_NCLBUTTONDOWN:
569 case WM_NCMBUTTONDOWN:
570 case WM_NCRBUTTONDOWN:
571 case WM_NCXBUTTONDOWN:
572 case WM_NCLBUTTONDBLCLK:
573 case WM_NCMBUTTONDBLCLK:
574 case WM_NCRBUTTONDBLCLK:
575 case WM_NCXBUTTONDBLCLK:
576 {
577 co_IntSendMessage(Msg->hwnd, WM_NCMOUSEMOVE, (WPARAM)Msg->wParam, Msg->lParam);
578 co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
579 break;
580 }
581 }
582 }
583
584 BOOL FASTCALL
585 co_IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, PWINDOW_OBJECT MsgWindow,
586 USHORT *HitTest)
587 {
588 ULONG Result;
589 PWINDOW_OBJECT Parent;
590
591 ASSERT_REFS_CO(MsgWindow);
592
593 if(*HitTest == (USHORT)HTTRANSPARENT)
594 {
595 /* eat the message, search again! */
596 return TRUE;
597 }
598
599 Parent = IntGetParent(MsgWindow);//fixme: deref retval?
600
601 /* If no parent window, pass MsgWindows HWND as wParam. Fixes bug #3111 */
602 Result = co_IntSendMessage(MsgWindow->hSelf,
603 WM_MOUSEACTIVATE,
604 (WPARAM) (Parent ? Parent->hSelf : MsgWindow->hSelf),
605 (LPARAM)MAKELONG(*HitTest, Msg->message)
606 );
607
608 switch (Result)
609 {
610 case MA_NOACTIVATEANDEAT:
611 return TRUE;
612 case MA_NOACTIVATE:
613 break;
614 case MA_ACTIVATEANDEAT:
615 co_IntMouseActivateWindow(MsgWindow);
616 return TRUE;
617 default:
618 /* MA_ACTIVATE */
619 co_IntMouseActivateWindow(MsgWindow);
620 break;
621 }
622
623 return FALSE;
624 }
625
626 BOOL FASTCALL
627 co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *HitTest, BOOL Remove)
628 {
629 PWINDOW_OBJECT Window;
630 USER_REFERENCE_ENTRY Ref, DesktopRef;
631
632 if(!(Window = UserGetWindowObject(Msg->hwnd)))
633 {
634 /* let's just eat the message?! */
635 return TRUE;
636 }
637
638 UserRefObjectCo(Window, &Ref);
639
640 if(ThreadQueue == Window->MessageQueue &&
641 ThreadQueue->CaptureWindow != Window->hSelf)
642 {
643 /* only send WM_NCHITTEST messages if we're not capturing the window! */
644 *HitTest = co_IntSendMessage(Window->hSelf, WM_NCHITTEST, 0,
645 MAKELONG(Msg->pt.x, Msg->pt.y));
646
647 if(*HitTest == (USHORT)HTTRANSPARENT)
648 {
649 PWINDOW_OBJECT DesktopWindow;
650 HWND hDesktop = IntGetDesktopWindow();
651
652 if((DesktopWindow = UserGetWindowObject(hDesktop)))
653 {
654 PWINDOW_OBJECT Wnd;
655
656 UserRefObjectCo(DesktopWindow, &DesktopRef);
657
658 co_WinPosWindowFromPoint(DesktopWindow, Window->MessageQueue, &Msg->pt, &Wnd);
659 if(Wnd)
660 {
661 if(Wnd != Window)
662 {
663 /* post the message to the other window */
664 Msg->hwnd = Wnd->hSelf;
665 if(!(Wnd->Status & WINDOWSTATUS_DESTROYING))
666 {
667 MsqPostMessage(Wnd->MessageQueue, Msg, FALSE,
668 Msg->message == WM_MOUSEMOVE ? QS_MOUSEMOVE :
669 QS_MOUSEBUTTON);
670 }
671
672 /* eat the message */
673 UserDereferenceObject(Wnd);
674 UserDerefObjectCo(DesktopWindow);
675 UserDerefObjectCo(Window);
676 return TRUE;
677 }
678 UserDereferenceObject(Wnd);
679 }
680
681 UserDerefObjectCo(DesktopWindow);
682 }
683 }
684 }
685 else
686 {
687 *HitTest = HTCLIENT;
688 }
689
690 if(IS_BTN_MESSAGE(Msg->message, DOWN))
691 {
692 /* generate double click messages, if necessary */
693 if ((((*HitTest) != HTCLIENT) ||
694 (Window->Wnd->Class->Style & CS_DBLCLKS)) &&
695 MsqIsDblClk(Msg, Remove))
696 {
697 Msg->message += WM_LBUTTONDBLCLK - WM_LBUTTONDOWN;
698 }
699 }
700
701 if(Msg->message != WM_MOUSEWHEEL)
702 {
703
704 if ((*HitTest) != HTCLIENT)
705 {
706 Msg->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
707 if((Msg->message == WM_NCRBUTTONUP) &&
708 (((*HitTest) == HTCAPTION) || ((*HitTest) == HTSYSMENU)))
709 {
710 Msg->message = WM_CONTEXTMENU;
711 Msg->wParam = (WPARAM)Window->hSelf;
712 }
713 else
714 {
715 Msg->wParam = *HitTest;
716 }
717 Msg->lParam = MAKELONG(Msg->pt.x, Msg->pt.y);
718 }
719 else if(ThreadQueue->MoveSize == NULL &&
720 ThreadQueue->MenuOwner == NULL)
721 {
722 /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
723 Msg->lParam = MAKELONG(
724 Msg->pt.x - (WORD)Window->Wnd->ClientRect.left,
725 Msg->pt.y - (WORD)Window->Wnd->ClientRect.top);
726 }
727 }
728
729 UserDerefObjectCo(Window);
730 return FALSE;
731 }
732
733
734 /*
735 * Internal version of PeekMessage() doing all the work
736 */
737 BOOL FASTCALL
738 co_IntPeekMessage(PUSER_MESSAGE Msg,
739 HWND hWnd,
740 UINT MsgFilterMin,
741 UINT MsgFilterMax,
742 UINT RemoveMsg)
743 {
744 PTHREADINFO pti;
745 LARGE_INTEGER LargeTickCount;
746 PUSER_MESSAGE_QUEUE ThreadQueue;
747 PUSER_MESSAGE Message;
748 BOOL Present, RemoveMessages;
749 USER_REFERENCE_ENTRY Ref;
750 USHORT HitTest;
751 MOUSEHOOKSTRUCT MHook;
752
753 /* The queues and order in which they are checked are documented in the MSDN
754 article on GetMessage() */
755
756 pti = PsGetCurrentThreadWin32Thread();
757 ThreadQueue = pti->MessageQueue;
758
759 /* Inspect RemoveMsg flags */
760 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
761 RemoveMessages = RemoveMsg & PM_REMOVE;
762
763 CheckMessages:
764
765 Present = FALSE;
766
767 KeQueryTickCount(&LargeTickCount);
768 ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
769
770 /* Dispatch sent messages here. */
771 while (co_MsqDispatchOneSentMessage(ThreadQueue))
772 ;
773
774 /* Now look for a quit message. */
775
776 if (ThreadQueue->QuitPosted)
777 {
778 /* According to the PSDK, WM_QUIT messages are always returned, regardless
779 of the filter specified */
780 Msg->Msg.hwnd = NULL;
781 Msg->Msg.message = WM_QUIT;
782 Msg->Msg.wParam = ThreadQueue->QuitExitCode;
783 Msg->Msg.lParam = 0;
784 Msg->FreeLParam = FALSE;
785 if (RemoveMessages)
786 {
787 ThreadQueue->QuitPosted = FALSE;
788 }
789 goto MsgExit;
790 }
791
792 /* Now check for normal messages. */
793 Present = co_MsqFindMessage(ThreadQueue,
794 FALSE,
795 RemoveMessages,
796 hWnd,
797 MsgFilterMin,
798 MsgFilterMax,
799 &Message);
800 if (Present)
801 {
802 RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
803 if (RemoveMessages)
804 {
805 MsqDestroyMessage(Message);
806 }
807 goto MessageFound;
808 }
809
810 /* Check for hardware events. */
811 Present = co_MsqFindMessage(ThreadQueue,
812 TRUE,
813 RemoveMessages,
814 hWnd,
815 MsgFilterMin,
816 MsgFilterMax,
817 &Message);
818 if (Present)
819 {
820 RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
821 if (RemoveMessages)
822 {
823 MsqDestroyMessage(Message);
824 }
825 goto MessageFound;
826 }
827
828 /* Check for sent messages again. */
829 while (co_MsqDispatchOneSentMessage(ThreadQueue))
830 ;
831
832 /* Check for paint messages. */
833 if (IntGetPaintMessage(hWnd, MsgFilterMin, MsgFilterMax, pti, &Msg->Msg, RemoveMessages))
834 {
835 Msg->FreeLParam = FALSE;
836 goto MsgExit;
837 }
838
839 /* Check for WM_(SYS)TIMER messages */
840 Present = MsqGetTimerMessage(ThreadQueue, hWnd, MsgFilterMin, MsgFilterMax,
841 &Msg->Msg, RemoveMessages);
842 if (Present)
843 {
844 Msg->FreeLParam = FALSE;
845 goto MessageFound;
846 }
847
848 if(Present)
849 {
850 MessageFound:
851
852 if(RemoveMessages)
853 {
854 PWINDOW_OBJECT MsgWindow = NULL;
855
856 if(Msg->Msg.hwnd && (MsgWindow = UserGetWindowObject(Msg->Msg.hwnd)) &&
857 Msg->Msg.message >= WM_MOUSEFIRST && Msg->Msg.message <= WM_MOUSELAST)
858 {
859 USHORT HitTest;
860
861 UserRefObjectCo(MsgWindow, &Ref);
862
863 if(co_IntTranslateMouseMessage(ThreadQueue, &Msg->Msg, &HitTest, TRUE))
864 /* FIXME - check message filter again, if the message doesn't match anymore,
865 search again */
866 {
867 UserDerefObjectCo(MsgWindow);
868 /* eat the message, search again */
869 goto CheckMessages;
870 }
871
872 if(ThreadQueue->CaptureWindow == NULL)
873 {
874 co_IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
875 if((Msg->Msg.message != WM_MOUSEMOVE && Msg->Msg.message != WM_NCMOUSEMOVE) &&
876 IS_BTN_MESSAGE(Msg->Msg.message, DOWN) &&
877 co_IntActivateWindowMouse(ThreadQueue, &Msg->Msg, MsgWindow, &HitTest))
878 {
879 UserDerefObjectCo(MsgWindow);
880 /* eat the message, search again */
881 goto CheckMessages;
882 }
883 }
884
885 UserDerefObjectCo(MsgWindow);
886 }
887 else
888 {
889 co_IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
890 }
891
892 // if(MsgWindow)
893 // {
894 // UserDereferenceObject(MsgWindow);
895 // }
896
897 goto MsgExit;
898 }
899
900 if((Msg->Msg.hwnd && Msg->Msg.message >= WM_MOUSEFIRST && Msg->Msg.message <= WM_MOUSELAST) &&
901 co_IntTranslateMouseMessage(ThreadQueue, &Msg->Msg, &HitTest, FALSE))
902 /* FIXME - check message filter again, if the message doesn't match anymore,
903 search again */
904 {
905 /* eat the message, search again */
906 goto CheckMessages;
907 }
908 MsgExit:
909 if ( ISITHOOKED(WH_MOUSE) &&
910 Msg->Msg.message >= WM_MOUSEFIRST &&
911 Msg->Msg.message <= WM_MOUSELAST )
912 {
913 MHook.pt = Msg->Msg.pt;
914 MHook.hwnd = Msg->Msg.hwnd;
915 MHook.wHitTestCode = HitTest;
916 MHook.dwExtraInfo = 0;
917 if (co_HOOK_CallHooks( WH_MOUSE,
918 RemoveMsg ? HC_ACTION : HC_NOREMOVE,
919 Msg->Msg.message,
920 (LPARAM)&MHook ))
921 {
922 if (ISITHOOKED(WH_CBT))
923 {
924 MHook.pt = Msg->Msg.pt;
925 MHook.hwnd = Msg->Msg.hwnd;
926 MHook.wHitTestCode = HitTest;
927 MHook.dwExtraInfo = 0;
928 co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED,
929 Msg->Msg.message, (LPARAM)&MHook);
930 }
931 return FALSE;
932 }
933 }
934 if ( ISITHOOKED(WH_KEYBOARD) &&
935 (Msg->Msg.message == WM_KEYDOWN || Msg->Msg.message == WM_KEYUP) )
936 {
937 if (co_HOOK_CallHooks( WH_KEYBOARD,
938 RemoveMsg ? HC_ACTION : HC_NOREMOVE,
939 LOWORD(Msg->Msg.wParam),
940 Msg->Msg.lParam))
941 {
942 if (ISITHOOKED(WH_CBT))
943 {
944 /* skip this message */
945 co_HOOK_CallHooks( WH_CBT, HCBT_KEYSKIPPED,
946 LOWORD(Msg->Msg.wParam), Msg->Msg.lParam );
947 }
948 return FALSE;
949 }
950 }
951 // The WH_GETMESSAGE hook enables an application to monitor messages about to
952 // be returned by the GetMessage or PeekMessage function.
953 if (ISITHOOKED(WH_GETMESSAGE))
954 {
955 //DPRINT1("Peek WH_GETMESSAGE -> %x\n",&Msg);
956 co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)&Msg->Msg);
957 }
958 return TRUE;
959 }
960
961 return Present;
962 }
963
964 BOOL APIENTRY
965 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
966 HWND hWnd,
967 UINT MsgFilterMin,
968 UINT MsgFilterMax,
969 UINT RemoveMsg)
970 {
971 NTSTATUS Status;
972 BOOL Present;
973 NTUSERGETMESSAGEINFO Info;
974 PWINDOW_OBJECT Window;
975 PMSGMEMORY MsgMemoryEntry;
976 PVOID UserMem;
977 UINT Size;
978 USER_MESSAGE Msg;
979 DECLARE_RETURN(BOOL);
980
981 DPRINT("Enter NtUserPeekMessage\n");
982 UserEnterExclusive();
983
984 /* Validate input */
985 if (hWnd && hWnd != INVALID_HANDLE_VALUE)
986 {
987 if (!(Window = UserGetWindowObject(hWnd)))
988 {
989 RETURN(-1);
990 }
991 }
992
993 if (MsgFilterMax < MsgFilterMin)
994 {
995 MsgFilterMin = 0;
996 MsgFilterMax = 0;
997 }
998
999 Present = co_IntPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg);
1000 if (Present)
1001 {
1002
1003 Info.Msg = Msg.Msg;
1004 /* See if this message type is present in the table */
1005 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
1006 if (NULL == MsgMemoryEntry)
1007 {
1008 /* Not present, no copying needed */
1009 Info.LParamSize = 0;
1010 }
1011 else
1012 {
1013 /* Determine required size */
1014 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
1015 Info.Msg.lParam);
1016 /* Allocate required amount of user-mode memory */
1017 Info.LParamSize = Size;
1018 UserMem = NULL;
1019 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
1020 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
1021 if (! NT_SUCCESS(Status))
1022 {
1023 SetLastNtError(Status);
1024 RETURN( (BOOL) -1);
1025 }
1026 /* Transfer lParam data to user-mode mem */
1027 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
1028 if (! NT_SUCCESS(Status))
1029 {
1030 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
1031 &Info.LParamSize, MEM_RELEASE);
1032 SetLastNtError(Status);
1033 RETURN( (BOOL) -1);
1034 }
1035 Info.Msg.lParam = (LPARAM) UserMem;
1036 }
1037 if (RemoveMsg && Msg.FreeLParam && 0 != Msg.Msg.lParam)
1038 {
1039 ExFreePool((void *) Msg.Msg.lParam);
1040 }
1041 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
1042 if (! NT_SUCCESS(Status))
1043 {
1044 SetLastNtError(Status);
1045 RETURN( (BOOL) -1);
1046 }
1047 }
1048
1049 RETURN( Present);
1050
1051 CLEANUP:
1052 DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_);
1053 UserLeave();
1054 END_CLEANUP;
1055 }
1056
1057 static BOOL FASTCALL
1058 co_IntWaitMessage(HWND Wnd,
1059 UINT MsgFilterMin,
1060 UINT MsgFilterMax)
1061 {
1062 PTHREADINFO pti;
1063 PUSER_MESSAGE_QUEUE ThreadQueue;
1064 NTSTATUS Status;
1065 USER_MESSAGE Msg;
1066
1067 pti = PsGetCurrentThreadWin32Thread();
1068 ThreadQueue = pti->MessageQueue;
1069
1070 do
1071 {
1072 if (co_IntPeekMessage(&Msg, Wnd, MsgFilterMin, MsgFilterMax, PM_NOREMOVE))
1073 {
1074 return TRUE;
1075 }
1076
1077 /* Nothing found. Wait for new messages. */
1078 Status = co_MsqWaitForNewMessages(ThreadQueue, Wnd, MsgFilterMin, MsgFilterMax);
1079 }
1080 while ((STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) || STATUS_TIMEOUT == Status);
1081
1082 SetLastNtError(Status);
1083
1084 return FALSE;
1085 }
1086
1087 BOOL APIENTRY
1088 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
1089 HWND hWnd,
1090 UINT MsgFilterMin,
1091 UINT MsgFilterMax)
1092 /*
1093 * FUNCTION: Get a message from the calling thread's message queue.
1094 * ARGUMENTS:
1095 * UnsafeMsg - Pointer to the structure which receives the returned message.
1096 * Wnd - Window whose messages are to be retrieved.
1097 * MsgFilterMin - Integer value of the lowest message value to be
1098 * retrieved.
1099 * MsgFilterMax - Integer value of the highest message value to be
1100 * retrieved.
1101 */
1102 {
1103 BOOL GotMessage;
1104 NTUSERGETMESSAGEINFO Info;
1105 NTSTATUS Status;
1106 /* FIXME: if initialization is removed, gcc complains that this may be used before initialization. Please review */
1107 PWINDOW_OBJECT Window = NULL;
1108 PMSGMEMORY MsgMemoryEntry;
1109 PVOID UserMem;
1110 UINT Size;
1111 USER_MESSAGE Msg;
1112 DECLARE_RETURN(BOOL);
1113 // USER_REFERENCE_ENTRY Ref;
1114
1115 DPRINT("Enter NtUserGetMessage\n");
1116 UserEnterExclusive();
1117
1118 /* Validate input */
1119 if (hWnd && !(Window = UserGetWindowObject(hWnd)))
1120 {
1121 RETURN(-1);
1122 }
1123
1124 // if (Window) UserRefObjectCo(Window, &Ref);
1125
1126 if (MsgFilterMax < MsgFilterMin)
1127 {
1128 MsgFilterMin = 0;
1129 MsgFilterMax = 0;
1130 }
1131
1132 do
1133 {
1134 GotMessage = co_IntPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE);
1135 if (GotMessage)
1136 {
1137 Info.Msg = Msg.Msg;
1138 /* See if this message type is present in the table */
1139 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
1140 if (NULL == MsgMemoryEntry)
1141 {
1142 /* Not present, no copying needed */
1143 Info.LParamSize = 0;
1144 }
1145 else
1146 {
1147 /* Determine required size */
1148 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
1149 Info.Msg.lParam);
1150 /* Allocate required amount of user-mode memory */
1151 Info.LParamSize = Size;
1152 UserMem = NULL;
1153 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
1154 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
1155
1156 if (! NT_SUCCESS(Status))
1157 {
1158 SetLastNtError(Status);
1159 RETURN( (BOOL) -1);
1160 }
1161 /* Transfer lParam data to user-mode mem */
1162 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
1163 if (! NT_SUCCESS(Status))
1164 {
1165 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
1166 &Info.LParamSize, MEM_DECOMMIT);
1167 SetLastNtError(Status);
1168 RETURN( (BOOL) -1);
1169 }
1170 Info.Msg.lParam = (LPARAM) UserMem;
1171 }
1172 if (Msg.FreeLParam && 0 != Msg.Msg.lParam)
1173 {
1174 ExFreePool((void *) Msg.Msg.lParam);
1175 }
1176 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
1177 if (! NT_SUCCESS(Status))
1178 {
1179 SetLastNtError(Status);
1180 RETURN( (BOOL) -1);
1181 }
1182 }
1183 else if (! co_IntWaitMessage(hWnd, MsgFilterMin, MsgFilterMax))
1184 {
1185 RETURN( (BOOL) -1);
1186 }
1187 }
1188 while (! GotMessage);
1189
1190 RETURN( WM_QUIT != Info.Msg.message);
1191
1192 CLEANUP:
1193 // if (Window) UserDerefObjectCo(Window);
1194
1195 DPRINT("Leave NtUserGetMessage\n");
1196 UserLeave();
1197 END_CLEANUP;
1198 }
1199
1200
1201 static NTSTATUS FASTCALL
1202 CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
1203 {
1204 NTSTATUS Status;
1205
1206 PVOID KernelMem;
1207 UINT Size;
1208
1209 *KernelModeMsg = *UserModeMsg;
1210
1211 /* See if this message type is present in the table */
1212 if (NULL == MsgMemoryEntry)
1213 {
1214 /* Not present, no copying needed */
1215 return STATUS_SUCCESS;
1216 }
1217
1218 /* Determine required size */
1219 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
1220
1221 if (0 != Size)
1222 {
1223 /* Allocate kernel mem */
1224 KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
1225 if (NULL == KernelMem)
1226 {
1227 DPRINT1("Not enough memory to copy message to kernel mem\n");
1228 return STATUS_NO_MEMORY;
1229 }
1230 KernelModeMsg->lParam = (LPARAM) KernelMem;
1231
1232 /* Copy data if required */
1233 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
1234 {
1235 Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
1236 if (! NT_SUCCESS(Status))
1237 {
1238 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
1239 ExFreePoolWithTag(KernelMem, TAG_MSG);
1240 return Status;
1241 }
1242 }
1243 else
1244 {
1245 /* Make sure we don't pass any secrets to usermode */
1246 RtlZeroMemory(KernelMem, Size);
1247 }
1248 }
1249 else
1250 {
1251 KernelModeMsg->lParam = 0;
1252 }
1253
1254 return STATUS_SUCCESS;
1255 }
1256
1257 static NTSTATUS FASTCALL
1258 CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
1259 {
1260 NTSTATUS Status;
1261 PMSGMEMORY MsgMemoryEntry;
1262 UINT Size;
1263
1264 /* See if this message type is present in the table */
1265 MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
1266 if (NULL == MsgMemoryEntry)
1267 {
1268 /* Not present, no copying needed */
1269 return STATUS_SUCCESS;
1270 }
1271
1272 /* Determine required size */
1273 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
1274
1275 if (0 != Size)
1276 {
1277 /* Copy data if required */
1278 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
1279 {
1280 Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
1281 if (! NT_SUCCESS(Status))
1282 {
1283 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1284 ExFreePool((PVOID) KernelModeMsg->lParam);
1285 return Status;
1286 }
1287 }
1288
1289 ExFreePool((PVOID) KernelModeMsg->lParam);
1290 }
1291
1292 return STATUS_SUCCESS;
1293 }
1294
1295 BOOL FASTCALL
1296 UserPostMessage(HWND Wnd,
1297 UINT Msg,
1298 WPARAM wParam,
1299 LPARAM lParam)
1300 {
1301 PTHREADINFO pti;
1302 MSG UserModeMsg, KernelModeMsg;
1303 LARGE_INTEGER LargeTickCount;
1304 NTSTATUS Status;
1305 PMSGMEMORY MsgMemoryEntry;
1306
1307 pti = PsGetCurrentThreadWin32Thread();
1308 if (WM_QUIT == Msg)
1309 {
1310 MsqPostQuitMessage(pti->MessageQueue, wParam);
1311 }
1312 else if (Wnd == HWND_BROADCAST)
1313 {
1314 HWND *List;
1315 PWINDOW_OBJECT DesktopWindow;
1316 ULONG i;
1317
1318 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1319 List = IntWinListChildren(DesktopWindow);
1320
1321 if (List != NULL)
1322 {
1323 for (i = 0; List[i]; i++)
1324 UserPostMessage(List[i], Msg, wParam, lParam);
1325 ExFreePool(List);
1326 }
1327 }
1328 else
1329 {
1330 PWINDOW_OBJECT Window;
1331
1332 Window = UserGetWindowObject(Wnd);
1333 if (NULL == Window)
1334 {
1335 return FALSE;
1336 }
1337 if(Window->Status & WINDOWSTATUS_DESTROYING)
1338 {
1339 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
1340 /* FIXME - last error code? */
1341 return FALSE;
1342 }
1343
1344 UserModeMsg.hwnd = Wnd;
1345 UserModeMsg.message = Msg;
1346 UserModeMsg.wParam = wParam;
1347 UserModeMsg.lParam = lParam;
1348 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1349 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1350 if (! NT_SUCCESS(Status))
1351 {
1352 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1353 return FALSE;
1354 }
1355 IntGetCursorLocation(pti->Desktop->WindowStation,
1356 &KernelModeMsg.pt);
1357 KeQueryTickCount(&LargeTickCount);
1358 KernelModeMsg.time = MsqCalculateMessageTime(&LargeTickCount);
1359 MsqPostMessage(Window->MessageQueue, &KernelModeMsg,
1360 NULL != MsgMemoryEntry && 0 != KernelModeMsg.lParam,
1361 QS_POSTMESSAGE);
1362 }
1363
1364 return TRUE;
1365 }
1366
1367
1368 BOOL APIENTRY
1369 NtUserPostMessage(HWND hWnd,
1370 UINT Msg,
1371 WPARAM wParam,
1372 LPARAM lParam)
1373 {
1374 DECLARE_RETURN(BOOL);
1375
1376 DPRINT("Enter NtUserPostMessage\n");
1377 UserEnterExclusive();
1378
1379 RETURN(UserPostMessage(hWnd, Msg, wParam, lParam));
1380
1381 CLEANUP:
1382 DPRINT("Leave NtUserPostMessage, ret=%i\n",_ret_);
1383 UserLeave();
1384 END_CLEANUP;
1385 }
1386
1387
1388
1389 BOOL APIENTRY
1390 NtUserPostThreadMessage(DWORD idThread,
1391 UINT Msg,
1392 WPARAM wParam,
1393 LPARAM lParam)
1394 {
1395 MSG UserModeMsg, KernelModeMsg;
1396 PETHREAD peThread;
1397 PTHREADINFO pThread;
1398 NTSTATUS Status;
1399 PMSGMEMORY MsgMemoryEntry;
1400 DECLARE_RETURN(BOOL);
1401
1402 DPRINT("Enter NtUserPostThreadMessage\n");
1403 UserEnterExclusive();
1404
1405 Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
1406
1407 if( Status == STATUS_SUCCESS )
1408 {
1409 pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
1410 if( !pThread || !pThread->MessageQueue )
1411 {
1412 ObDereferenceObject( peThread );
1413 RETURN( FALSE);
1414 }
1415
1416 UserModeMsg.hwnd = NULL;
1417 UserModeMsg.message = Msg;
1418 UserModeMsg.wParam = wParam;
1419 UserModeMsg.lParam = lParam;
1420 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1421 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1422 if (! NT_SUCCESS(Status))
1423 {
1424 ObDereferenceObject( peThread );
1425 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1426 RETURN( FALSE);
1427 }
1428 MsqPostMessage(pThread->MessageQueue, &KernelModeMsg,
1429 NULL != MsgMemoryEntry && 0 != KernelModeMsg.lParam,
1430 QS_POSTMESSAGE);
1431 ObDereferenceObject( peThread );
1432 RETURN( TRUE);
1433 }
1434 else
1435 {
1436 SetLastNtError( Status );
1437 RETURN( FALSE);
1438 }
1439
1440 CLEANUP:
1441 DPRINT("Leave NtUserPostThreadMessage, ret=%i\n",_ret_);
1442 UserLeave();
1443 END_CLEANUP;
1444 }
1445
1446 DWORD APIENTRY
1447 NtUserQuerySendMessage(DWORD Unknown0)
1448 {
1449 UNIMPLEMENTED;
1450
1451 return 0;
1452 }
1453
1454 LRESULT FASTCALL
1455 co_IntSendMessage(HWND hWnd,
1456 UINT Msg,
1457 WPARAM wParam,
1458 LPARAM lParam)
1459 {
1460 ULONG_PTR Result = 0;
1461 if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1462 {
1463 return (LRESULT)Result;
1464 }
1465 return 0;
1466 }
1467
1468 static
1469 LRESULT FASTCALL
1470 co_IntSendMessageTimeoutSingle(HWND hWnd,
1471 UINT Msg,
1472 WPARAM wParam,
1473 LPARAM lParam,
1474 UINT uFlags,
1475 UINT uTimeout,
1476 ULONG_PTR *uResult)
1477 {
1478 ULONG_PTR Result;
1479 NTSTATUS Status;
1480 PWINDOW_OBJECT Window = NULL;
1481 PMSGMEMORY MsgMemoryEntry;
1482 INT lParamBufferSize;
1483 LPARAM lParamPacked;
1484 PTHREADINFO Win32Thread;
1485 DECLARE_RETURN(LRESULT);
1486 USER_REFERENCE_ENTRY Ref;
1487
1488 if (!(Window = UserGetWindowObject(hWnd)))
1489 {
1490 RETURN( FALSE);
1491 }
1492
1493 UserRefObjectCo(Window, &Ref);
1494
1495 Win32Thread = PsGetCurrentThreadWin32Thread();
1496
1497 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1498
1499 if (NULL != Win32Thread &&
1500 Window->MessageQueue == Win32Thread->MessageQueue)
1501 {
1502 if (Win32Thread->IsExiting)
1503 {
1504 /* Never send messages to exiting threads */
1505 RETURN( FALSE);
1506 }
1507
1508 /* See if this message type is present in the table */
1509 MsgMemoryEntry = FindMsgMemory(Msg);
1510 if (NULL == MsgMemoryEntry)
1511 {
1512 lParamBufferSize = -1;
1513 }
1514 else
1515 {
1516 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1517 }
1518
1519 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam)))
1520 {
1521 DPRINT1("Failed to pack message parameters\n");
1522 RETURN( FALSE);
1523 }
1524
1525 Result = (ULONG_PTR)co_IntCallWindowProc(Window->Wnd->WndProc, !Window->Wnd->Unicode, hWnd, Msg, wParam,
1526 lParamPacked,lParamBufferSize);
1527
1528 if(uResult)
1529 {
1530 *uResult = Result;
1531 }
1532
1533 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1534
1535 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam)))
1536 {
1537 DPRINT1("Failed to unpack message parameters\n");
1538 RETURN( TRUE);
1539 }
1540
1541 RETURN( TRUE);
1542 }
1543
1544 if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->MessageQueue))
1545 {
1546 /* FIXME - Set a LastError? */
1547 RETURN( FALSE);
1548 }
1549
1550 if (Window->Status & WINDOWSTATUS_DESTROYING)
1551 {
1552 /* FIXME - last error? */
1553 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1554 RETURN( FALSE);
1555 }
1556
1557 do
1558 {
1559 Status = co_MsqSendMessage( Window->MessageQueue,
1560 hWnd,
1561 Msg,
1562 wParam,
1563 lParam,
1564 uTimeout,
1565 (uFlags & SMTO_BLOCK),
1566 MSQ_NORMAL,
1567 uResult);
1568 }
1569 while ((STATUS_TIMEOUT == Status) &&
1570 (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
1571 !MsqIsHung(Window->MessageQueue));
1572
1573 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1574
1575 if (STATUS_TIMEOUT == Status)
1576 {
1577 /*
1578 MSDN says:
1579 Microsoft Windows 2000: If GetLastError returns zero, then the function
1580 timed out.
1581 XP+ : If the function fails or times out, the return value is zero.
1582 To get extended error information, call GetLastError. If GetLastError
1583 returns ERROR_TIMEOUT, then the function timed out.
1584 */
1585 SetLastWin32Error(ERROR_TIMEOUT);
1586 RETURN( FALSE);
1587 }
1588 else if (! NT_SUCCESS(Status))
1589 {
1590 SetLastNtError(Status);
1591 RETURN( FALSE);
1592 }
1593
1594 RETURN( TRUE);
1595
1596 CLEANUP:
1597 if (Window) UserDerefObjectCo(Window);
1598 END_CLEANUP;
1599 }
1600
1601 LRESULT FASTCALL
1602 co_IntSendMessageTimeout(HWND hWnd,
1603 UINT Msg,
1604 WPARAM wParam,
1605 LPARAM lParam,
1606 UINT uFlags,
1607 UINT uTimeout,
1608 ULONG_PTR *uResult)
1609 {
1610 PWINDOW_OBJECT DesktopWindow;
1611 HWND *Children;
1612 HWND *Child;
1613
1614 if (HWND_BROADCAST != hWnd)
1615 {
1616 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1617 }
1618
1619 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1620 if (NULL == DesktopWindow)
1621 {
1622 SetLastWin32Error(ERROR_INTERNAL_ERROR);
1623 return 0;
1624 }
1625
1626 Children = IntWinListChildren(DesktopWindow);
1627 if (NULL == Children)
1628 {
1629 return 0;
1630 }
1631
1632 for (Child = Children; NULL != *Child; Child++)
1633 {
1634 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1635 }
1636
1637 ExFreePool(Children);
1638
1639 return (LRESULT) TRUE;
1640 }
1641
1642
1643 /* This function posts a message if the destination's message queue belongs to
1644 another thread, otherwise it sends the message. It does not support broadcast
1645 messages! */
1646 LRESULT FASTCALL
1647 co_IntPostOrSendMessage(HWND hWnd,
1648 UINT Msg,
1649 WPARAM wParam,
1650 LPARAM lParam)
1651 {
1652 ULONG_PTR Result;
1653 PTHREADINFO pti;
1654 PWINDOW_OBJECT Window;
1655
1656 if(hWnd == HWND_BROADCAST)
1657 {
1658 return 0;
1659 }
1660
1661 if(!(Window = UserGetWindowObject(hWnd)))
1662 {
1663 return 0;
1664 }
1665
1666 pti = PsGetCurrentThreadWin32Thread();
1667 if(Window->MessageQueue != pti->MessageQueue)
1668 {
1669 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1670 }
1671 else
1672 {
1673 if(!co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result)) {
1674 Result = 0;
1675 }
1676 }
1677
1678 return (LRESULT)Result;
1679 }
1680
1681 LRESULT FASTCALL
1682 co_IntDoSendMessage(HWND hWnd,
1683 UINT Msg,
1684 WPARAM wParam,
1685 LPARAM lParam,
1686 PDOSENDMESSAGE dsm,
1687 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1688 {
1689 PTHREADINFO pti;
1690 LRESULT Result = TRUE;
1691 NTSTATUS Status;
1692 PWINDOW_OBJECT Window = NULL;
1693 NTUSERSENDMESSAGEINFO Info;
1694 MSG UserModeMsg;
1695 MSG KernelModeMsg;
1696 PMSGMEMORY MsgMemoryEntry;
1697
1698 RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));
1699
1700 /* FIXME: Call hooks. */
1701 if (HWND_BROADCAST != hWnd)
1702 {
1703 Window = UserGetWindowObject(hWnd);
1704 if (NULL == Window)
1705 {
1706 /* Tell usermode to not touch this one */
1707 Info.HandledByKernel = TRUE;
1708 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1709 return 0;
1710 }
1711 if (!Window->Wnd)
1712 return 0;
1713 }
1714
1715 /* FIXME: Check for an exiting window. */
1716
1717 /* See if the current thread can handle the message */
1718 pti = PsGetCurrentThreadWin32Thread();
1719 if (HWND_BROADCAST != hWnd && NULL != pti &&
1720 Window->MessageQueue == pti->MessageQueue)
1721 {
1722 /* Gather the information usermode needs to call the window proc directly */
1723 Info.HandledByKernel = FALSE;
1724
1725 Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi),
1726 sizeof(BOOL));
1727 if (! NT_SUCCESS(Status))
1728 {
1729 Info.Ansi = ! Window->Wnd->Unicode;
1730 }
1731
1732 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1733
1734 if (Window->Wnd->IsSystem)
1735 {
1736 Info.Proc = (!Info.Ansi ? Window->Wnd->WndProc : Window->Wnd->WndProcExtra);
1737 }
1738 else
1739 {
1740 Info.Ansi = !Window->Wnd->Unicode;
1741 Info.Proc = Window->Wnd->WndProc;
1742 }
1743
1744 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, &Result);
1745
1746 }
1747 else
1748 {
1749 /* Must be handled by other thread */
1750 // if (HWND_BROADCAST != hWnd)
1751 // {
1752 // UserDereferenceObject(Window);
1753 // }
1754 Info.HandledByKernel = TRUE;
1755 UserModeMsg.hwnd = hWnd;
1756 UserModeMsg.message = Msg;
1757 UserModeMsg.wParam = wParam;
1758 UserModeMsg.lParam = lParam;
1759 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1760 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1761 if (! NT_SUCCESS(Status))
1762 {
1763 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1764 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1765 return (dsm ? 0 : -1);
1766 }
1767 if(!dsm)
1768 {
1769 Result = co_IntSendMessage(KernelModeMsg.hwnd, KernelModeMsg.message,
1770 KernelModeMsg.wParam, KernelModeMsg.lParam);
1771 }
1772 else
1773 {
1774 Result = co_IntSendMessageTimeout(KernelModeMsg.hwnd, KernelModeMsg.message,
1775 KernelModeMsg.wParam, KernelModeMsg.lParam,
1776 dsm->uFlags, dsm->uTimeout, &dsm->Result);
1777 }
1778 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1779 if (! NT_SUCCESS(Status))
1780 {
1781 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1782 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1783 return(dsm ? 0 : -1);
1784 }
1785 }
1786
1787 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1788 if (! NT_SUCCESS(Status))
1789 {
1790 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1791 }
1792
1793 return (LRESULT)Result;
1794 }
1795
1796 LRESULT APIENTRY
1797 NtUserSendMessageTimeout(HWND hWnd,
1798 UINT Msg,
1799 WPARAM wParam,
1800 LPARAM lParam,
1801 UINT uFlags,
1802 UINT uTimeout,
1803 ULONG_PTR *uResult,
1804 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1805 {
1806 DOSENDMESSAGE dsm;
1807 LRESULT Result;
1808 DECLARE_RETURN(BOOL);
1809
1810 DPRINT("Enter NtUserSendMessageTimeout\n");
1811 UserEnterExclusive();
1812
1813 dsm.uFlags = uFlags;
1814 dsm.uTimeout = uTimeout;
1815 Result = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
1816 if(uResult != NULL && Result != 0)
1817 {
1818 NTSTATUS Status;
1819
1820 Status = MmCopyToCaller(uResult, &dsm.Result, sizeof(ULONG_PTR));
1821 if(!NT_SUCCESS(Status))
1822 {
1823 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1824 RETURN( FALSE);
1825 }
1826 }
1827 RETURN( Result);
1828
1829 CLEANUP:
1830 DPRINT("Leave NtUserSendMessageTimeout, ret=%i\n",_ret_);
1831 UserLeave();
1832 END_CLEANUP;
1833 }
1834
1835 LRESULT APIENTRY
1836 NtUserSendMessage(HWND Wnd,
1837 UINT Msg,
1838 WPARAM wParam,
1839 LPARAM lParam,
1840 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1841 {
1842 DECLARE_RETURN(BOOL);
1843
1844 DPRINT("Enter NtUserSendMessage\n");
1845 UserEnterExclusive();
1846
1847 RETURN(co_IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo));
1848
1849 CLEANUP:
1850 DPRINT("Leave NtUserSendMessage, ret=%i\n",_ret_);
1851 UserLeave();
1852 END_CLEANUP;
1853 }
1854
1855
1856 BOOL FASTCALL
1857 UserSendNotifyMessage(HWND hWnd,
1858 UINT Msg,
1859 WPARAM wParam,
1860 LPARAM lParam)
1861 {
1862 BOOL Result = TRUE;
1863 // Basicly the same as IntPostOrSendMessage
1864 if (hWnd == HWND_BROADCAST) //Handle Broadcast
1865 {
1866 HWND *List;
1867 PWINDOW_OBJECT DesktopWindow;
1868 ULONG i;
1869
1870 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1871 List = IntWinListChildren(DesktopWindow);
1872
1873 if (List != NULL)
1874 {
1875 for (i = 0; List[i]; i++)
1876 {
1877 UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1878 }
1879 ExFreePool(List);
1880 }
1881 }
1882 else
1883 {
1884 ULONG_PTR PResult;
1885 PTHREADINFO pti;
1886 PWINDOW_OBJECT Window;
1887 NTSTATUS Status;
1888 MSG UserModeMsg;
1889 MSG KernelModeMsg;
1890 PMSGMEMORY MsgMemoryEntry;
1891
1892 if(!(Window = UserGetWindowObject(hWnd))) return FALSE;
1893
1894 pti = PsGetCurrentThreadWin32Thread();
1895 if(Window->MessageQueue != pti->MessageQueue)
1896 { // Send message w/o waiting for it.
1897 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1898 }
1899 else
1900 { // Handle message and callback.
1901 UserModeMsg.hwnd = hWnd;
1902 UserModeMsg.message = Msg;
1903 UserModeMsg.wParam = wParam;
1904 UserModeMsg.lParam = lParam;
1905 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1906 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1907 if (! NT_SUCCESS(Status))
1908 {
1909 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1910 return FALSE;
1911 }
1912 Result = co_IntSendMessageTimeoutSingle(
1913 KernelModeMsg.hwnd, KernelModeMsg.message,
1914 KernelModeMsg.wParam, KernelModeMsg.lParam,
1915 SMTO_NORMAL, 0, &PResult);
1916
1917 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1918 if (! NT_SUCCESS(Status))
1919 {
1920 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1921 return FALSE;
1922 }
1923 }
1924 }
1925 return Result;
1926 }
1927
1928
1929 BOOL APIENTRY
1930 NtUserSendNotifyMessage(HWND hWnd,
1931 UINT Msg,
1932 WPARAM wParam,
1933 LPARAM lParam)
1934 {
1935 DECLARE_RETURN(BOOL);
1936
1937 DPRINT("EnterNtUserSendNotifyMessage\n");
1938 UserEnterExclusive();
1939
1940 RETURN(UserSendNotifyMessage(hWnd, Msg, wParam, lParam));
1941
1942 CLEANUP:
1943 DPRINT("Leave NtUserSendNotifyMessage, ret=%i\n",_ret_);
1944 UserLeave();
1945 END_CLEANUP;
1946
1947 }
1948
1949
1950 BOOL APIENTRY
1951 NtUserWaitMessage(VOID)
1952 {
1953 DECLARE_RETURN(BOOL);
1954
1955 DPRINT("EnterNtUserWaitMessage\n");
1956 UserEnterExclusive();
1957
1958 RETURN(co_IntWaitMessage(NULL, 0, 0));
1959
1960 CLEANUP:
1961 DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_);
1962 UserLeave();
1963 END_CLEANUP;
1964 }
1965
1966 DWORD APIENTRY
1967 IntGetQueueStatus(BOOL ClearChanges)
1968 {
1969 PTHREADINFO pti;
1970 PUSER_MESSAGE_QUEUE Queue;
1971 DWORD Result;
1972 DECLARE_RETURN(DWORD);
1973
1974 DPRINT("Enter IntGetQueueStatus\n");
1975
1976 pti = PsGetCurrentThreadWin32Thread();
1977 Queue = pti->MessageQueue;
1978
1979 Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
1980 if (ClearChanges)
1981 {
1982 Queue->ChangedBits = 0;
1983 }
1984
1985 RETURN(Result);
1986
1987 CLEANUP:
1988 DPRINT("Leave IntGetQueueStatus, ret=%i\n",_ret_);
1989 END_CLEANUP;
1990 }
1991
1992 BOOL APIENTRY
1993 IntInitMessagePumpHook()
1994 {
1995 if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo)
1996 {
1997 ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook++;
1998 return TRUE;
1999 }
2000 return FALSE;
2001 }
2002
2003 BOOL APIENTRY
2004 IntUninitMessagePumpHook()
2005 {
2006 if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo)
2007 {
2008 if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook <= 0)
2009 {
2010 return FALSE;
2011 }
2012 ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook--;
2013 return TRUE;
2014 }
2015 return FALSE;
2016 }
2017
2018
2019 LRESULT APIENTRY
2020 NtUserMessageCall(
2021 HWND hWnd,
2022 UINT Msg,
2023 WPARAM wParam,
2024 LPARAM lParam,
2025 ULONG_PTR ResultInfo,
2026 DWORD dwType, // fnID?
2027 BOOL Ansi)
2028 {
2029 LRESULT lResult = 0;
2030 PWINDOW_OBJECT Window = NULL;
2031 USER_REFERENCE_ENTRY Ref;
2032
2033 UserEnterExclusive();
2034
2035 /* Validate input */
2036 if (hWnd && (hWnd != INVALID_HANDLE_VALUE) && !(Window = UserGetWindowObject(hWnd)))
2037 {
2038 return 0;
2039 }
2040 switch(dwType)
2041 {
2042 case FNID_DEFWINDOWPROC:
2043 UserRefObjectCo(Window, &Ref);
2044 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2045 UserDerefObjectCo(Window);
2046 break;
2047 case FNID_BROADCASTSYSTEMMESSAGE:
2048 {
2049 PBROADCASTPARM parm;
2050 BOOL BadChk = FALSE;
2051 DWORD_PTR RetVal = 0;
2052 lResult = -1;
2053
2054 if (ResultInfo)
2055 {
2056 _SEH2_TRY
2057 {
2058 ProbeForWrite((PVOID)ResultInfo,
2059 sizeof(BROADCASTPARM),
2060 1);
2061 parm = (PBROADCASTPARM)ResultInfo;
2062 }
2063 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2064 {
2065 BadChk = TRUE;
2066 }
2067 _SEH2_END;
2068 if (BadChk) break;
2069 }
2070 else
2071 break;
2072
2073 if ( parm->recipients & BSM_ALLDESKTOPS ||
2074 parm->recipients == BSM_ALLCOMPONENTS )
2075 {
2076 }
2077 else if (parm->recipients & BSM_APPLICATIONS)
2078 {
2079 if (parm->flags & BSF_QUERY)
2080 {
2081 if (parm->flags & BSF_FORCEIFHUNG || parm->flags & BSF_NOHANG)
2082 {
2083 co_IntSendMessageTimeout( HWND_BROADCAST,
2084 Msg,
2085 wParam,
2086 lParam,
2087 SMTO_ABORTIFHUNG,
2088 2000,
2089 &RetVal);
2090 }
2091 else if (parm->flags & BSF_NOTIMEOUTIFNOTHUNG)
2092 {
2093 co_IntSendMessageTimeout( HWND_BROADCAST,
2094 Msg,
2095 wParam,
2096 lParam,
2097 SMTO_NOTIMEOUTIFNOTHUNG,
2098 2000,
2099 &RetVal);
2100 }
2101 else
2102 {
2103 co_IntSendMessageTimeout( HWND_BROADCAST,
2104 Msg,
2105 wParam,
2106 lParam,
2107 SMTO_NORMAL,
2108 2000,
2109 &RetVal);
2110 }
2111 }
2112 else if (parm->flags & BSF_POSTMESSAGE)
2113 {
2114 lResult = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
2115 }
2116 else if ( parm->flags & BSF_SENDNOTIFYMESSAGE)
2117 {
2118 lResult = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
2119 }
2120 }
2121 }
2122 break;
2123 case FNID_SENDMESSAGECALLBACK:
2124 break;
2125 // CallNextHook bypass.
2126 case FNID_CALLWNDPROC:
2127 case FNID_CALLWNDPROCRET:
2128 {
2129 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
2130 PHOOK NextObj, Hook = ClientInfo->phkCurrent;
2131
2132 if (!ClientInfo || !Hook) break;
2133
2134 UserReferenceObject(Hook);
2135
2136 if (Hook->Thread && (Hook->Thread != PsGetCurrentThread()))
2137 {
2138 UserDereferenceObject(Hook);
2139 break;
2140 }
2141
2142 NextObj = IntGetNextHook(Hook);
2143 ClientInfo->phkCurrent = NextObj;
2144
2145 if ( Hook->HookId == WH_CALLWNDPROC)
2146 {
2147 CWPSTRUCT CWP;
2148 CWP.hwnd = hWnd;
2149 CWP.message = Msg;
2150 CWP.wParam = wParam;
2151 CWP.lParam = lParam;
2152 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
2153
2154 lResult = co_IntCallHookProc( Hook->HookId,
2155 HC_ACTION,
2156 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2157 (LPARAM)&CWP,
2158 Hook->Proc,
2159 Hook->Ansi,
2160 &Hook->ModuleName);
2161 }
2162 else
2163 {
2164 CWPRETSTRUCT CWPR;
2165 CWPR.hwnd = hWnd;
2166 CWPR.message = Msg;
2167 CWPR.wParam = wParam;
2168 CWPR.lParam = lParam;
2169 CWPR.lResult = ClientInfo->dwHookData;
2170
2171 lResult = co_IntCallHookProc( Hook->HookId,
2172 HC_ACTION,
2173 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2174 (LPARAM)&CWPR,
2175 Hook->Proc,
2176 Hook->Ansi,
2177 &Hook->ModuleName);
2178 }
2179 UserDereferenceObject(Hook);
2180 lResult = (LRESULT) NextObj;
2181 }
2182 break;
2183 }
2184 UserLeave();
2185 return lResult;
2186 }
2187
2188 #define INFINITE 0xFFFFFFFF
2189 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2190
2191 DWORD
2192 APIENTRY
2193 NtUserWaitForInputIdle(
2194 IN HANDLE hProcess,
2195 IN DWORD dwMilliseconds,
2196 IN BOOL Unknown2)
2197 {
2198 PEPROCESS Process;
2199 PW32PROCESS W32Process;
2200 NTSTATUS Status;
2201 HANDLE Handles[2];
2202 LARGE_INTEGER Timeout;
2203 ULONGLONG StartTime, Run, Elapsed = 0;
2204
2205 UserEnterExclusive();
2206
2207 Status = ObReferenceObjectByHandle(hProcess,
2208 PROCESS_QUERY_INFORMATION,
2209 PsProcessType,
2210 UserMode,
2211 (PVOID*)&Process,
2212 NULL);
2213
2214 if (!NT_SUCCESS(Status))
2215 {
2216 UserLeave();
2217 SetLastNtError(Status);
2218 return WAIT_FAILED;
2219 }
2220
2221 W32Process = (PW32PROCESS)Process->Win32Process;
2222 if (!W32Process)
2223 {
2224 ObDereferenceObject(Process);
2225 UserLeave();
2226 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2227 return WAIT_FAILED;
2228 }
2229
2230 EngCreateEvent((PEVENT *)&W32Process->InputIdleEvent);
2231
2232 Handles[0] = Process;
2233 Handles[1] = W32Process->InputIdleEvent;
2234
2235 if (!Handles[1])
2236 {
2237 ObDereferenceObject(Process);
2238 UserLeave();
2239 return STATUS_SUCCESS; /* no event to wait on */
2240 }
2241
2242 StartTime = EngGetTickCount();
2243
2244 Run = dwMilliseconds;
2245
2246 DPRINT("WFII: waiting for %p\n", Handles[1] );
2247 do
2248 {
2249 Timeout.QuadPart = Run - Elapsed;
2250 UserLeave();
2251 Status = KeWaitForMultipleObjects( 2,
2252 Handles,
2253 WaitAny,
2254 UserRequest,
2255 UserMode,
2256 FALSE,
2257 dwMilliseconds == INFINITE ? NULL : &Timeout,
2258 NULL);
2259 UserEnterExclusive();
2260
2261 if (!NT_SUCCESS(Status))
2262 {
2263 SetLastNtError(Status);
2264 Status = WAIT_FAILED;
2265 goto WaitExit;
2266 }
2267
2268 switch (Status)
2269 {
2270 case STATUS_WAIT_0:
2271 Status = WAIT_FAILED;
2272 goto WaitExit;
2273
2274 case STATUS_WAIT_2:
2275 {
2276 USER_MESSAGE Msg;
2277 co_IntPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE );
2278 break;
2279 }
2280
2281 case STATUS_USER_APC:
2282 case STATUS_ALERTED:
2283 case STATUS_TIMEOUT:
2284 DPRINT1("WFII: timeout\n");
2285 Status = STATUS_TIMEOUT;
2286 goto WaitExit;
2287
2288 default:
2289 DPRINT1("WFII: finished\n");
2290 Status = STATUS_SUCCESS;
2291 goto WaitExit;
2292 }
2293
2294 if (dwMilliseconds != INFINITE)
2295 {
2296 Elapsed = EngGetTickCount() - StartTime;
2297
2298 if (Elapsed > Run)
2299 Status = STATUS_TIMEOUT;
2300 break;
2301 }
2302 }
2303 while (1);
2304
2305 WaitExit:
2306 if (W32Process->InputIdleEvent)
2307 {
2308 EngDeleteEvent((PEVENT)W32Process->InputIdleEvent);
2309 W32Process->InputIdleEvent = NULL;
2310 }
2311 ObDereferenceObject(Process);
2312 UserLeave();
2313 return Status;
2314 }
2315
2316 /* EOF */