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