Merge amd64 NDK from amd64 branch:
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / message.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Messages
5 * FILE: subsys/win32k/ntuser/message.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <w32k.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18 typedef struct
19 {
20 UINT uFlags;
21 UINT uTimeout;
22 ULONG_PTR Result;
23 }
24 DOSENDMESSAGE, *PDOSENDMESSAGE;
25
26 /* FUNCTIONS *****************************************************************/
27
28 NTSTATUS FASTCALL
29 IntInitMessageImpl(VOID)
30 {
31 return STATUS_SUCCESS;
32 }
33
34 NTSTATUS FASTCALL
35 IntCleanupMessageImpl(VOID)
36 {
37 return STATUS_SUCCESS;
38 }
39
40 #define MMS_SIZE_WPARAM -1
41 #define MMS_SIZE_WPARAMWCHAR -2
42 #define MMS_SIZE_LPARAMSZ -3
43 #define MMS_SIZE_SPECIAL -4
44 #define MMS_FLAG_READ 0x01
45 #define MMS_FLAG_WRITE 0x02
46 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
47 typedef struct tagMSGMEMORY
48 {
49 UINT Message;
50 UINT Size;
51 INT Flags;
52 }
53 MSGMEMORY, *PMSGMEMORY;
54
55 static MSGMEMORY MsgMemory[] =
56 {
57 { WM_CREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
58 { WM_DDE_ACK, sizeof(KMDDELPARAM), MMS_FLAG_READ },
59 { WM_DDE_EXECUTE, MMS_SIZE_WPARAM, MMS_FLAG_READ },
60 { WM_GETMINMAXINFO, sizeof(MINMAXINFO), MMS_FLAG_READWRITE },
61 { WM_GETTEXT, MMS_SIZE_WPARAMWCHAR, MMS_FLAG_WRITE },
62 { WM_NCCALCSIZE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
63 { WM_NCCREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
64 { WM_SETTEXT, MMS_SIZE_LPARAMSZ, MMS_FLAG_READ },
65 { WM_STYLECHANGED, sizeof(STYLESTRUCT), MMS_FLAG_READ },
66 { WM_STYLECHANGING, sizeof(STYLESTRUCT), MMS_FLAG_READWRITE },
67 { WM_COPYDATA, MMS_SIZE_SPECIAL, MMS_FLAG_READ },
68 { WM_WINDOWPOSCHANGED, sizeof(WINDOWPOS), MMS_FLAG_READ },
69 { WM_WINDOWPOSCHANGING, sizeof(WINDOWPOS), MMS_FLAG_READWRITE },
70 };
71
72 static PMSGMEMORY FASTCALL
73 FindMsgMemory(UINT Msg)
74 {
75 PMSGMEMORY MsgMemoryEntry;
76
77 /* See if this message type is present in the table */
78 for (MsgMemoryEntry = MsgMemory;
79 MsgMemoryEntry < MsgMemory + sizeof(MsgMemory) / sizeof(MSGMEMORY);
80 MsgMemoryEntry++)
81 {
82 if (Msg == MsgMemoryEntry->Message)
83 {
84 return MsgMemoryEntry;
85 }
86 }
87
88 return NULL;
89 }
90
91 static UINT FASTCALL
92 MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
93 {
94 CREATESTRUCTW *Cs;
95 PUNICODE_STRING WindowName;
96 PUNICODE_STRING ClassName;
97 UINT Size = 0;
98
99 _SEH2_TRY
100 {
101 if (MMS_SIZE_WPARAM == MsgMemoryEntry->Size)
102 {
103 Size = (UINT)wParam;
104 }
105 else if (MMS_SIZE_WPARAMWCHAR == MsgMemoryEntry->Size)
106 {
107 Size = (UINT) (wParam * sizeof(WCHAR));
108 }
109 else if (MMS_SIZE_LPARAMSZ == MsgMemoryEntry->Size)
110 {
111 Size = (UINT) ((wcslen((PWSTR) lParam) + 1) * sizeof(WCHAR));
112 }
113 else if (MMS_SIZE_SPECIAL == MsgMemoryEntry->Size)
114 {
115 switch(MsgMemoryEntry->Message)
116 {
117 case WM_CREATE:
118 case WM_NCCREATE:
119 Cs = (CREATESTRUCTW *) lParam;
120 WindowName = (PUNICODE_STRING) Cs->lpszName;
121 ClassName = (PUNICODE_STRING) Cs->lpszClass;
122 Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
123 if (IS_ATOM(ClassName->Buffer))
124 {
125 Size += sizeof(WCHAR) + sizeof(ATOM);
126 }
127 else
128 {
129 Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
130 }
131 break;
132
133 case WM_NCCALCSIZE:
134 Size = wParam ? sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS) : sizeof(RECT);
135 break;
136
137 case WM_COPYDATA:
138 Size = sizeof(COPYDATASTRUCT) + ((PCOPYDATASTRUCT)lParam)->cbData;
139 break;
140
141 case WM_COPYGLOBALDATA:
142 Size = wParam;
143 break;
144
145 default:
146 assert(FALSE);
147 Size = 0;
148 break;
149 }
150 }
151 else
152 {
153 Size = MsgMemoryEntry->Size;
154 }
155 }
156 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
157 {
158 DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode());
159 Size = 0;
160 }
161 _SEH2_END;
162 return Size;
163 }
164
165 static NTSTATUS
166 PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
167 {
168 NCCALCSIZE_PARAMS *UnpackedNcCalcsize;
169 NCCALCSIZE_PARAMS *PackedNcCalcsize;
170 CREATESTRUCTW *UnpackedCs;
171 CREATESTRUCTW *PackedCs;
172 PUNICODE_STRING WindowName;
173 PUNICODE_STRING ClassName;
174 UINT Size;
175 PCHAR CsData;
176
177 *lParamPacked = lParam;
178 if (WM_NCCALCSIZE == Msg && wParam)
179 {
180 UnpackedNcCalcsize = (NCCALCSIZE_PARAMS *) lParam;
181 if (UnpackedNcCalcsize->lppos != (PWINDOWPOS) (UnpackedNcCalcsize + 1))
182 {
183 PackedNcCalcsize = ExAllocatePoolWithTag(PagedPool,
184 sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS),
185 TAG_MSG);
186 if (NULL == PackedNcCalcsize)
187 {
188 DPRINT1("Not enough memory to pack lParam\n");
189 return STATUS_NO_MEMORY;
190 }
191 RtlCopyMemory(PackedNcCalcsize, UnpackedNcCalcsize, sizeof(NCCALCSIZE_PARAMS));
192 PackedNcCalcsize->lppos = (PWINDOWPOS) (PackedNcCalcsize + 1);
193 RtlCopyMemory(PackedNcCalcsize->lppos, UnpackedNcCalcsize->lppos, sizeof(WINDOWPOS));
194 *lParamPacked = (LPARAM) PackedNcCalcsize;
195 }
196 }
197 else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
198 {
199 UnpackedCs = (CREATESTRUCTW *) lParam;
200 WindowName = (PUNICODE_STRING) UnpackedCs->lpszName;
201 ClassName = (PUNICODE_STRING) UnpackedCs->lpszClass;
202 Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
203 if (IS_ATOM(ClassName->Buffer))
204 {
205 Size += sizeof(WCHAR) + sizeof(ATOM);
206 }
207 else
208 {
209 Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
210 }
211 PackedCs = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
212 if (NULL == PackedCs)
213 {
214 DPRINT1("Not enough memory to pack lParam\n");
215 return STATUS_NO_MEMORY;
216 }
217 RtlCopyMemory(PackedCs, UnpackedCs, sizeof(CREATESTRUCTW));
218 CsData = (PCHAR) (PackedCs + 1);
219 PackedCs->lpszName = (LPCWSTR) (CsData - (PCHAR) PackedCs);
220 RtlCopyMemory(CsData, WindowName->Buffer, WindowName->Length);
221 CsData += WindowName->Length;
222 *((WCHAR *) CsData) = L'\0';
223 CsData += sizeof(WCHAR);
224 PackedCs->lpszClass = (LPCWSTR) (CsData - (PCHAR) PackedCs);
225 if (IS_ATOM(ClassName->Buffer))
226 {
227 *((WCHAR *) CsData) = L'A';
228 CsData += sizeof(WCHAR);
229 *((ATOM *) CsData) = (ATOM)(DWORD_PTR) ClassName->Buffer;
230 CsData += sizeof(ATOM);
231 }
232 else
233 {
234 *((WCHAR *) CsData) = L'S';
235 CsData += sizeof(WCHAR);
236 RtlCopyMemory(CsData, ClassName->Buffer, ClassName->Length);
237 CsData += ClassName->Length;
238 *((WCHAR *) CsData) = L'\0';
239 CsData += sizeof(WCHAR);
240 }
241 ASSERT(CsData == (PCHAR) PackedCs + Size);
242 *lParamPacked = (LPARAM) PackedCs;
243 }
244
245 return STATUS_SUCCESS;
246 }
247
248 static NTSTATUS
249 UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
250 {
251 NCCALCSIZE_PARAMS *UnpackedParams;
252 NCCALCSIZE_PARAMS *PackedParams;
253 PWINDOWPOS UnpackedWindowPos;
254
255 if (lParamPacked == lParam)
256 {
257 return STATUS_SUCCESS;
258 }
259
260 if (WM_NCCALCSIZE == Msg && wParam)
261 {
262 PackedParams = (NCCALCSIZE_PARAMS *) lParamPacked;
263 UnpackedParams = (NCCALCSIZE_PARAMS *) lParam;
264 UnpackedWindowPos = UnpackedParams->lppos;
265 RtlCopyMemory(UnpackedParams, PackedParams, sizeof(NCCALCSIZE_PARAMS));
266 UnpackedParams->lppos = UnpackedWindowPos;
267 RtlCopyMemory(UnpackedWindowPos, PackedParams + 1, sizeof(WINDOWPOS));
268 ExFreePool((PVOID) lParamPacked);
269
270 return STATUS_SUCCESS;
271 }
272 else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
273 {
274 ExFreePool((PVOID) lParamPacked);
275
276 return STATUS_SUCCESS;
277 }
278
279 ASSERT(FALSE);
280
281 return STATUS_INVALID_PARAMETER;
282 }
283
284 static
285 VOID
286 FASTCALL
287 IntCallWndProc
288 ( PWINDOW_OBJECT Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
289 {
290 BOOL SameThread = FALSE;
291
292 if (Window->ti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
293 SameThread = TRUE;
294
295 if ((!SameThread && (Window->ti->fsHooks & HOOKID_TO_FLAG(WH_CALLWNDPROC))) ||
296 (SameThread && ISITHOOKED(WH_CALLWNDPROC)) )
297 {
298 CWPSTRUCT CWP;
299 CWP.hwnd = hWnd;
300 CWP.message = Msg;
301 CWP.wParam = wParam;
302 CWP.lParam = lParam;
303 co_HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, SameThread, (LPARAM)&CWP );
304 }
305 }
306
307 static
308 VOID
309 FASTCALL
310 IntCallWndProcRet
311 ( PWINDOW_OBJECT Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *uResult)
312 {
313 BOOL SameThread = FALSE;
314
315 if (Window->ti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
316 SameThread = TRUE;
317
318 if ((!SameThread && (Window->ti->fsHooks & HOOKID_TO_FLAG(WH_CALLWNDPROCRET))) ||
319 (SameThread && ISITHOOKED(WH_CALLWNDPROCRET)) )
320 {
321 CWPRETSTRUCT CWPR;
322 CWPR.hwnd = hWnd;
323 CWPR.message = Msg;
324 CWPR.wParam = wParam;
325 CWPR.lParam = lParam;
326 CWPR.lResult = *uResult;
327 co_HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, SameThread, (LPARAM)&CWPR );
328 }
329 }
330
331 LRESULT
332 FASTCALL
333 IntDispatchMessage(PMSG pMsg)
334 {
335 LARGE_INTEGER TickCount;
336 LONG Time;
337 LRESULT retval;
338 PWINDOW_OBJECT Window = NULL;
339
340 if (pMsg->hwnd)
341 {
342 Window = UserGetWindowObject(pMsg->hwnd);
343 if (!Window || !Window->Wnd) return 0;
344 }
345
346 if (((pMsg->message == WM_SYSTIMER) ||
347 (pMsg->message == WM_TIMER)) &&
348 (pMsg->lParam) )
349 {
350 if (pMsg->message == WM_TIMER)
351 {
352 if (ValidateTimerCallback(PsGetCurrentThreadWin32Thread(),Window,pMsg->wParam,pMsg->lParam))
353 {
354 KeQueryTickCount(&TickCount);
355 Time = MsqCalculateMessageTime(&TickCount);
356 return co_IntCallWindowProc((WNDPROC)pMsg->lParam,
357 TRUE,
358 pMsg->hwnd,
359 WM_TIMER,
360 pMsg->wParam,
361 (LPARAM)Time,
362 sizeof(LPARAM));
363 }
364 return 0;
365 }
366 else
367 {
368 PTIMER pTimer = FindSystemTimer(pMsg);
369 if (pTimer && pTimer->pfn)
370 {
371 KeQueryTickCount(&TickCount);
372 Time = MsqCalculateMessageTime(&TickCount);
373 pTimer->pfn(pMsg->hwnd, WM_SYSTIMER, (UINT)pMsg->wParam, Time);
374 }
375 return 0;
376 }
377 }
378 // Need a window!
379 if (!Window) return 0;
380
381 retval = co_IntPostOrSendMessage(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam);
382
383 if (pMsg->message == WM_PAINT)
384 {
385 /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
386 HRGN hrgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
387 co_UserGetUpdateRgn( Window, hrgn, TRUE );
388 GreDeleteObject( hrgn );
389 }
390 return retval;
391 }
392
393
394 BOOL
395 APIENTRY
396 NtUserCallMsgFilter(
397 LPMSG lpmsg,
398 INT code)
399 {
400 BOOL BadChk = FALSE, Ret = TRUE;
401 MSG Msg;
402 DECLARE_RETURN(BOOL);
403
404 DPRINT("Enter NtUserCallMsgFilter\n");
405 UserEnterExclusive();
406 if (lpmsg)
407 {
408 _SEH2_TRY
409 {
410 ProbeForRead((PVOID)lpmsg,
411 sizeof(MSG),
412 1);
413 RtlCopyMemory( &Msg,
414 (PVOID)lpmsg,
415 sizeof(MSG));
416 }
417 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
418 {
419 BadChk = TRUE;
420 }
421 _SEH2_END;
422 }
423 else
424 RETURN( FALSE);
425
426 if (BadChk) RETURN( FALSE);
427
428 if (!co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
429 {
430 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
431 }
432
433 _SEH2_TRY
434 {
435 ProbeForWrite((PVOID)lpmsg,
436 sizeof(MSG),
437 1);
438 RtlCopyMemory((PVOID)lpmsg,
439 &Msg,
440 sizeof(MSG));
441 }
442 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
443 {
444 BadChk = TRUE;
445 }
446 _SEH2_END;
447 if (BadChk) RETURN( FALSE);
448 RETURN( Ret)
449
450 CLEANUP:
451 DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_);
452 UserLeave();
453 END_CLEANUP;
454 }
455
456 LRESULT APIENTRY
457 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
458 {
459 LRESULT Res = 0;
460 BOOL Hit = FALSE;
461 MSG SafeMsg;
462
463 UserEnterExclusive();
464 _SEH2_TRY
465 {
466 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
467 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
468 }
469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
470 {
471 SetLastNtError(_SEH2_GetExceptionCode());
472 Hit = TRUE;
473 }
474 _SEH2_END;
475
476 if (!Hit) Res = IntDispatchMessage(&SafeMsg);
477
478 UserLeave();
479 return Res;
480 }
481
482
483 BOOL APIENTRY
484 NtUserTranslateMessage(LPMSG lpMsg,
485 HKL dwhkl)
486 {
487 NTSTATUS Status;
488 MSG SafeMsg;
489 DECLARE_RETURN(BOOL);
490
491 DPRINT("Enter NtUserTranslateMessage\n");
492 UserEnterExclusive();
493
494 Status = MmCopyFromCaller(&SafeMsg, lpMsg, sizeof(MSG));
495 if(!NT_SUCCESS(Status))
496 {
497 SetLastNtError(Status);
498 RETURN( FALSE);
499 }
500
501 RETURN( IntTranslateKbdMessage(&SafeMsg, dwhkl));
502
503 CLEANUP:
504 DPRINT("Leave NtUserTranslateMessage: ret=%i\n",_ret_);
505 UserLeave();
506 END_CLEANUP;
507 }
508
509
510 VOID FASTCALL
511 co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg)
512 {
513 if(!Msg->hwnd || ThreadQueue->CaptureWindow)
514 {
515 return;
516 }
517
518 switch(Msg->message)
519 {
520 case WM_MOUSEMOVE:
521 {
522 co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
523 break;
524 }
525 case WM_NCMOUSEMOVE:
526 {
527 co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
528 break;
529 }
530 case WM_LBUTTONDOWN:
531 case WM_MBUTTONDOWN:
532 case WM_RBUTTONDOWN:
533 case WM_XBUTTONDOWN:
534 case WM_LBUTTONDBLCLK:
535 case WM_MBUTTONDBLCLK:
536 case WM_RBUTTONDBLCLK:
537 case WM_XBUTTONDBLCLK:
538 {
539 WPARAM wParam;
540 PSYSTEM_CURSORINFO CurInfo;
541
542 if(!IntGetWindowStationObject(InputWindowStation))
543 {
544 break;
545 }
546 CurInfo = IntGetSysCursorInfo(InputWindowStation);
547 wParam = (WPARAM)(CurInfo->ButtonsDown);
548 ObDereferenceObject(InputWindowStation);
549
550 co_IntSendMessage(Msg->hwnd, WM_MOUSEMOVE, wParam, Msg->lParam);
551 co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
552 break;
553 }
554 case WM_NCLBUTTONDOWN:
555 case WM_NCMBUTTONDOWN:
556 case WM_NCRBUTTONDOWN:
557 case WM_NCXBUTTONDOWN:
558 case WM_NCLBUTTONDBLCLK:
559 case WM_NCMBUTTONDBLCLK:
560 case WM_NCRBUTTONDBLCLK:
561 case WM_NCXBUTTONDBLCLK:
562 {
563 co_IntSendMessage(Msg->hwnd, WM_NCMOUSEMOVE, (WPARAM)Msg->wParam, Msg->lParam);
564 co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
565 break;
566 }
567 }
568 }
569
570 BOOL FASTCALL
571 co_IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, PWINDOW_OBJECT MsgWindow,
572 USHORT *HitTest)
573 {
574 ULONG Result;
575 PWINDOW_OBJECT Parent;
576
577 ASSERT_REFS_CO(MsgWindow);
578
579 if(*HitTest == (USHORT)HTTRANSPARENT)
580 {
581 /* eat the message, search again! */
582 return TRUE;
583 }
584
585 Parent = IntGetParent(MsgWindow);//fixme: deref retval?
586
587 /* If no parent window, pass MsgWindows HWND as wParam. Fixes bug #3111 */
588 Result = co_IntSendMessage(MsgWindow->hSelf,
589 WM_MOUSEACTIVATE,
590 (WPARAM) (Parent ? Parent->hSelf : MsgWindow->hSelf),
591 (LPARAM)MAKELONG(*HitTest, Msg->message)
592 );
593
594 switch (Result)
595 {
596 case MA_NOACTIVATEANDEAT:
597 return TRUE;
598 case MA_NOACTIVATE:
599 break;
600 case MA_ACTIVATEANDEAT:
601 co_IntMouseActivateWindow(MsgWindow);
602 return TRUE;
603 default:
604 /* MA_ACTIVATE */
605 co_IntMouseActivateWindow(MsgWindow);
606 break;
607 }
608
609 return FALSE;
610 }
611
612 BOOL FASTCALL
613 co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *HitTest, BOOL Remove)
614 {
615 PWINDOW_OBJECT Window;
616 USER_REFERENCE_ENTRY Ref, DesktopRef;
617
618 if(!(Window = UserGetWindowObject(Msg->hwnd)))
619 {
620 /* let's just eat the message?! */
621 return TRUE;
622 }
623
624 UserRefObjectCo(Window, &Ref);
625
626 if(ThreadQueue == Window->MessageQueue &&
627 ThreadQueue->CaptureWindow != Window->hSelf)
628 {
629 /* only send WM_NCHITTEST messages if we're not capturing the window! */
630 *HitTest = co_IntSendMessage(Window->hSelf, WM_NCHITTEST, 0,
631 MAKELONG(Msg->pt.x, Msg->pt.y));
632
633 if(*HitTest == (USHORT)HTTRANSPARENT)
634 {
635 PWINDOW_OBJECT DesktopWindow;
636 HWND hDesktop = IntGetDesktopWindow();
637
638 if((DesktopWindow = UserGetWindowObject(hDesktop)))
639 {
640 PWINDOW_OBJECT Wnd;
641
642 UserRefObjectCo(DesktopWindow, &DesktopRef);
643
644 co_WinPosWindowFromPoint(DesktopWindow, Window->MessageQueue, &Msg->pt, &Wnd);
645 if(Wnd)
646 {
647 if(Wnd != Window)
648 {
649 /* post the message to the other window */
650 Msg->hwnd = Wnd->hSelf;
651 if(!(Wnd->Status & WINDOWSTATUS_DESTROYING))
652 {
653 MsqPostMessage(Wnd->MessageQueue, Msg, FALSE,
654 Msg->message == WM_MOUSEMOVE ? QS_MOUSEMOVE :
655 QS_MOUSEBUTTON);
656 }
657
658 /* eat the message */
659 UserDereferenceObject(Wnd);
660 UserDerefObjectCo(DesktopWindow);
661 UserDerefObjectCo(Window);
662 return TRUE;
663 }
664 UserDereferenceObject(Wnd);
665 }
666
667 UserDerefObjectCo(DesktopWindow);
668 }
669 }
670 }
671 else
672 {
673 *HitTest = HTCLIENT;
674 }
675
676 if (gspv.bMouseClickLock && ((Msg->message == WM_LBUTTONUP) || (Msg->message == WM_LBUTTONDOWN)))
677 {
678 if (MsqIsClkLck(Msg, Remove))
679 {
680 // FIXME: drop the message, hack: use WM_NULL
681 Msg->message = WM_NULL;
682 }
683 }
684
685 if(IS_BTN_MESSAGE(Msg->message, DOWN))
686 {
687 /* generate double click messages, if necessary */
688 if ((((*HitTest) != HTCLIENT) ||
689 (Window->Wnd->pcls->style & CS_DBLCLKS)) &&
690 MsqIsDblClk(Msg, Remove))
691 {
692 Msg->message += WM_LBUTTONDBLCLK - WM_LBUTTONDOWN;
693 }
694 }
695
696 if(Msg->message != WM_MOUSEWHEEL)
697 {
698
699 if ((*HitTest) != HTCLIENT)
700 {
701 Msg->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
702 if((Msg->message == WM_NCRBUTTONUP) &&
703 (((*HitTest) == HTCAPTION) || ((*HitTest) == HTSYSMENU)))
704 {
705 Msg->message = WM_CONTEXTMENU;
706 Msg->wParam = (WPARAM)Window->hSelf;
707 }
708 else
709 {
710 Msg->wParam = *HitTest;
711 }
712 Msg->lParam = MAKELONG(Msg->pt.x, Msg->pt.y);
713 }
714 else if(ThreadQueue->MoveSize == NULL &&
715 ThreadQueue->MenuOwner == NULL)
716 {
717 /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
718 Msg->lParam = MAKELONG(
719 Msg->pt.x - (WORD)Window->Wnd->rcClient.left,
720 Msg->pt.y - (WORD)Window->Wnd->rcClient.top);
721 }
722 }
723
724 UserDerefObjectCo(Window);
725 return FALSE;
726 }
727
728
729 /*
730 * Internal version of PeekMessage() doing all the work
731 */
732 BOOL FASTCALL
733 co_IntPeekMessage(PUSER_MESSAGE Msg,
734 PWINDOW_OBJECT Window,
735 UINT MsgFilterMin,
736 UINT MsgFilterMax,
737 UINT RemoveMsg)
738 {
739 PTHREADINFO pti;
740 LARGE_INTEGER LargeTickCount;
741 PUSER_MESSAGE_QUEUE ThreadQueue;
742 PUSER_MESSAGE Message;
743 BOOL Present, RemoveMessages;
744 USER_REFERENCE_ENTRY Ref;
745 USHORT HitTest;
746 MOUSEHOOKSTRUCT MHook;
747
748 /* The queues and order in which they are checked are documented in the MSDN
749 article on GetMessage() */
750
751 pti = PsGetCurrentThreadWin32Thread();
752 ThreadQueue = pti->MessageQueue;
753
754 /* Inspect RemoveMsg flags */
755 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
756 RemoveMessages = RemoveMsg & PM_REMOVE;
757
758 CheckMessages:
759
760 Present = FALSE;
761
762 KeQueryTickCount(&LargeTickCount);
763 ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
764
765 /* Dispatch sent messages here. */
766 while (co_MsqDispatchOneSentMessage(ThreadQueue))
767 ;
768
769 /* Now look for a quit message. */
770
771 if (ThreadQueue->QuitPosted)
772 {
773 /* According to the PSDK, WM_QUIT messages are always returned, regardless
774 of the filter specified */
775 Msg->Msg.hwnd = NULL;
776 Msg->Msg.message = WM_QUIT;
777 Msg->Msg.wParam = ThreadQueue->QuitExitCode;
778 Msg->Msg.lParam = 0;
779 Msg->FreeLParam = FALSE;
780 if (RemoveMessages)
781 {
782 ThreadQueue->QuitPosted = FALSE;
783 }
784 goto MsgExit;
785 }
786
787 /* Now check for normal messages. */
788 Present = co_MsqFindMessage(ThreadQueue,
789 FALSE,
790 RemoveMessages,
791 Window,
792 MsgFilterMin,
793 MsgFilterMax,
794 &Message);
795 if (Present)
796 {
797 RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
798 if (RemoveMessages)
799 {
800 MsqDestroyMessage(Message);
801 }
802 goto MessageFound;
803 }
804
805 /* Check for hardware events. */
806 Present = co_MsqFindMessage(ThreadQueue,
807 TRUE,
808 RemoveMessages,
809 Window,
810 MsgFilterMin,
811 MsgFilterMax,
812 &Message);
813 if (Present)
814 {
815 RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
816 if (RemoveMessages)
817 {
818 MsqDestroyMessage(Message);
819 }
820 goto MessageFound;
821 }
822
823 /* Check for sent messages again. */
824 while (co_MsqDispatchOneSentMessage(ThreadQueue))
825 ;
826
827 /* Check for paint messages. */
828 if (IntGetPaintMessage(Window, MsgFilterMin, MsgFilterMax, pti, &Msg->Msg, RemoveMessages))
829 {
830 Msg->FreeLParam = FALSE;
831 goto MsgExit;
832 }
833
834 if (ThreadQueue->WakeMask & QS_TIMER)
835 if (PostTimerMessages(Window)) // If there are timers ready,
836 goto CheckMessages; // go back and process them.
837
838 // LOL! Polling Timer Queue? How much time is spent doing this?
839 /* Check for WM_(SYS)TIMER messages */
840 Present = MsqGetTimerMessage(ThreadQueue, Window, 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 if (hWnd == (HWND)-1 || hWnd == (HWND)0x0000FFFF || hWnd == (HWND)0xFFFFFFFF)
985 hWnd = (HWND)1;
986
987 /* Validate input */
988 if (hWnd && hWnd != (HWND)1)
989 {
990 if (!(Window = UserGetWindowObject(hWnd)))
991 {
992 RETURN(-1);
993 }
994 }
995 else
996 {
997 Window = (PWINDOW_OBJECT)hWnd;
998 }
999
1000 if (MsgFilterMax < MsgFilterMin)
1001 {
1002 MsgFilterMin = 0;
1003 MsgFilterMax = 0;
1004 }
1005
1006 Present = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, RemoveMsg);
1007 if (Present)
1008 {
1009
1010 Info.Msg = Msg.Msg;
1011 /* See if this message type is present in the table */
1012 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
1013 if (NULL == MsgMemoryEntry)
1014 {
1015 /* Not present, no copying needed */
1016 Info.LParamSize = 0;
1017 }
1018 else
1019 {
1020 /* Determine required size */
1021 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
1022 Info.Msg.lParam);
1023 /* Allocate required amount of user-mode memory */
1024 Info.LParamSize = Size;
1025 UserMem = NULL;
1026 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
1027 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
1028 if (! NT_SUCCESS(Status))
1029 {
1030 SetLastNtError(Status);
1031 RETURN( (BOOL) -1);
1032 }
1033 /* Transfer lParam data to user-mode mem */
1034 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
1035 if (! NT_SUCCESS(Status))
1036 {
1037 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
1038 &Info.LParamSize, MEM_RELEASE);
1039 SetLastNtError(Status);
1040 RETURN( (BOOL) -1);
1041 }
1042 Info.Msg.lParam = (LPARAM) UserMem;
1043 }
1044 if (RemoveMsg && Msg.FreeLParam && 0 != Msg.Msg.lParam)
1045 {
1046 ExFreePool((void *) Msg.Msg.lParam);
1047 }
1048 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
1049 if (! NT_SUCCESS(Status))
1050 {
1051 SetLastNtError(Status);
1052 RETURN( (BOOL) -1);
1053 }
1054 }
1055
1056 RETURN( Present);
1057
1058 CLEANUP:
1059 DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_);
1060 UserLeave();
1061 END_CLEANUP;
1062 }
1063
1064 static BOOL FASTCALL
1065 co_IntWaitMessage(PWINDOW_OBJECT Window,
1066 UINT MsgFilterMin,
1067 UINT MsgFilterMax)
1068 {
1069 PTHREADINFO pti;
1070 PUSER_MESSAGE_QUEUE ThreadQueue;
1071 NTSTATUS Status;
1072 USER_MESSAGE Msg;
1073
1074 pti = PsGetCurrentThreadWin32Thread();
1075 ThreadQueue = pti->MessageQueue;
1076
1077 do
1078 {
1079 if (co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, PM_NOREMOVE))
1080 {
1081 return TRUE;
1082 }
1083
1084 /* Nothing found. Wait for new messages. */
1085 Status = co_MsqWaitForNewMessages(ThreadQueue, Window, MsgFilterMin, MsgFilterMax);
1086 }
1087 while ((STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) || STATUS_TIMEOUT == Status);
1088
1089 SetLastNtError(Status);
1090
1091 return FALSE;
1092 }
1093
1094 BOOL APIENTRY
1095 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
1096 HWND hWnd,
1097 UINT MsgFilterMin,
1098 UINT MsgFilterMax)
1099 /*
1100 * FUNCTION: Get a message from the calling thread's message queue.
1101 * ARGUMENTS:
1102 * UnsafeMsg - Pointer to the structure which receives the returned message.
1103 * Wnd - Window whose messages are to be retrieved.
1104 * MsgFilterMin - Integer value of the lowest message value to be
1105 * retrieved.
1106 * MsgFilterMax - Integer value of the highest message value to be
1107 * retrieved.
1108 */
1109 {
1110 BOOL GotMessage;
1111 NTUSERGETMESSAGEINFO Info;
1112 NTSTATUS Status;
1113 /* FIXME: if initialization is removed, gcc complains that this may be used before initialization. Please review */
1114 PWINDOW_OBJECT Window = NULL;
1115 PMSGMEMORY MsgMemoryEntry;
1116 PVOID UserMem;
1117 UINT Size;
1118 USER_MESSAGE Msg;
1119 DECLARE_RETURN(BOOL);
1120 // USER_REFERENCE_ENTRY Ref;
1121
1122 DPRINT("Enter NtUserGetMessage\n");
1123 UserEnterExclusive();
1124
1125 /* Validate input */
1126 if (hWnd && !(Window = UserGetWindowObject(hWnd)))
1127 {
1128 RETURN(-1);
1129 }
1130
1131 // if (Window) UserRefObjectCo(Window, &Ref);
1132
1133 if (MsgFilterMax < MsgFilterMin)
1134 {
1135 MsgFilterMin = 0;
1136 MsgFilterMax = 0;
1137 }
1138
1139 do
1140 {
1141 GotMessage = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, PM_REMOVE);
1142 if (GotMessage)
1143 {
1144 Info.Msg = Msg.Msg;
1145 /* See if this message type is present in the table */
1146 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
1147 if (NULL == MsgMemoryEntry)
1148 {
1149 /* Not present, no copying needed */
1150 Info.LParamSize = 0;
1151 }
1152 else
1153 {
1154 /* Determine required size */
1155 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
1156 Info.Msg.lParam);
1157 /* Allocate required amount of user-mode memory */
1158 Info.LParamSize = Size;
1159 UserMem = NULL;
1160 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
1161 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
1162
1163 if (! NT_SUCCESS(Status))
1164 {
1165 SetLastNtError(Status);
1166 RETURN( (BOOL) -1);
1167 }
1168 /* Transfer lParam data to user-mode mem */
1169 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
1170 if (! NT_SUCCESS(Status))
1171 {
1172 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
1173 &Info.LParamSize, MEM_DECOMMIT);
1174 SetLastNtError(Status);
1175 RETURN( (BOOL) -1);
1176 }
1177 Info.Msg.lParam = (LPARAM) UserMem;
1178 }
1179 if (Msg.FreeLParam && 0 != Msg.Msg.lParam)
1180 {
1181 ExFreePool((void *) Msg.Msg.lParam);
1182 }
1183 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
1184 if (! NT_SUCCESS(Status))
1185 {
1186 SetLastNtError(Status);
1187 RETURN( (BOOL) -1);
1188 }
1189 }
1190 else if (! co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax))
1191 {
1192 RETURN( (BOOL) -1);
1193 }
1194 }
1195 while (! GotMessage);
1196
1197 RETURN( WM_QUIT != Info.Msg.message);
1198
1199 CLEANUP:
1200 // if (Window) UserDerefObjectCo(Window);
1201
1202 DPRINT("Leave NtUserGetMessage\n");
1203 UserLeave();
1204 END_CLEANUP;
1205 }
1206
1207
1208 static NTSTATUS FASTCALL
1209 CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
1210 {
1211 NTSTATUS Status;
1212
1213 PVOID KernelMem;
1214 UINT Size;
1215
1216 *KernelModeMsg = *UserModeMsg;
1217
1218 /* See if this message type is present in the table */
1219 if (NULL == MsgMemoryEntry)
1220 {
1221 /* Not present, no copying needed */
1222 return STATUS_SUCCESS;
1223 }
1224
1225 /* Determine required size */
1226 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
1227
1228 if (0 != Size)
1229 {
1230 /* Allocate kernel mem */
1231 KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
1232 if (NULL == KernelMem)
1233 {
1234 DPRINT1("Not enough memory to copy message to kernel mem\n");
1235 return STATUS_NO_MEMORY;
1236 }
1237 KernelModeMsg->lParam = (LPARAM) KernelMem;
1238
1239 /* Copy data if required */
1240 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
1241 {
1242 Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
1243 if (! NT_SUCCESS(Status))
1244 {
1245 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
1246 ExFreePoolWithTag(KernelMem, TAG_MSG);
1247 return Status;
1248 }
1249 }
1250 else
1251 {
1252 /* Make sure we don't pass any secrets to usermode */
1253 RtlZeroMemory(KernelMem, Size);
1254 }
1255 }
1256 else
1257 {
1258 KernelModeMsg->lParam = 0;
1259 }
1260
1261 return STATUS_SUCCESS;
1262 }
1263
1264 static NTSTATUS FASTCALL
1265 CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
1266 {
1267 NTSTATUS Status;
1268 PMSGMEMORY MsgMemoryEntry;
1269 UINT Size;
1270
1271 /* See if this message type is present in the table */
1272 MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
1273 if (NULL == MsgMemoryEntry)
1274 {
1275 /* Not present, no copying needed */
1276 return STATUS_SUCCESS;
1277 }
1278
1279 /* Determine required size */
1280 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
1281
1282 if (0 != Size)
1283 {
1284 /* Copy data if required */
1285 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
1286 {
1287 Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
1288 if (! NT_SUCCESS(Status))
1289 {
1290 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1291 ExFreePool((PVOID) KernelModeMsg->lParam);
1292 return Status;
1293 }
1294 }
1295
1296 ExFreePool((PVOID) KernelModeMsg->lParam);
1297 }
1298
1299 return STATUS_SUCCESS;
1300 }
1301
1302 BOOL FASTCALL
1303 UserPostThreadMessage( DWORD idThread,
1304 UINT Msg,
1305 WPARAM wParam,
1306 LPARAM lParam)
1307 {
1308 MSG Message;
1309 PETHREAD peThread;
1310 PTHREADINFO pThread;
1311 LARGE_INTEGER LargeTickCount;
1312 NTSTATUS Status;
1313
1314 DPRINT1("UserPostThreadMessage wParam 0x%x lParam 0x%x\n", wParam,lParam);
1315
1316 if (FindMsgMemory(Msg) != 0)
1317 {
1318 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
1319 return FALSE;
1320 }
1321
1322 Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
1323
1324 if( Status == STATUS_SUCCESS )
1325 {
1326 pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
1327 if( !pThread || !pThread->MessageQueue )
1328 {
1329 ObDereferenceObject( peThread );
1330 return FALSE;
1331 }
1332
1333 Message.hwnd = NULL;
1334 Message.message = Msg;
1335 Message.wParam = wParam;
1336 Message.lParam = lParam;
1337 IntGetCursorLocation(pThread->Desktop->WindowStation, &Message.pt);
1338 KeQueryTickCount(&LargeTickCount);
1339 pThread->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
1340 MsqPostMessage(pThread->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1341 ObDereferenceObject( peThread );
1342 return TRUE;
1343 }
1344 else
1345 {
1346 SetLastNtError( Status );
1347 }
1348 return FALSE;
1349 }
1350
1351 BOOL FASTCALL
1352 UserPostMessage(HWND Wnd,
1353 UINT Msg,
1354 WPARAM wParam,
1355 LPARAM lParam)
1356 {
1357 PTHREADINFO pti;
1358 MSG Message;
1359 LARGE_INTEGER LargeTickCount;
1360
1361 if (FindMsgMemory(Msg) != 0)
1362 {
1363 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
1364 return FALSE;
1365 }
1366
1367 if (!Wnd)
1368 return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
1369 Msg,
1370 wParam,
1371 lParam);
1372
1373 pti = PsGetCurrentThreadWin32Thread();
1374 if (Wnd == HWND_BROADCAST)
1375 {
1376 HWND *List;
1377 PWINDOW_OBJECT DesktopWindow;
1378 ULONG i;
1379
1380 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1381 List = IntWinListChildren(DesktopWindow);
1382
1383 if (List != NULL)
1384 {
1385 for (i = 0; List[i]; i++)
1386 UserPostMessage(List[i], Msg, wParam, lParam);
1387 ExFreePool(List);
1388 }
1389 }
1390 else
1391 {
1392 PWINDOW_OBJECT Window;
1393
1394 Window = UserGetWindowObject(Wnd);
1395 if (NULL == Window)
1396 {
1397 return FALSE;
1398 }
1399 if(Window->Status & WINDOWSTATUS_DESTROYING)
1400 {
1401 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
1402 /* FIXME - last error code? */
1403 return FALSE;
1404 }
1405
1406 if (WM_QUIT == Msg)
1407 {
1408 MsqPostQuitMessage(Window->MessageQueue, wParam);
1409 }
1410 else
1411 {
1412 Message.hwnd = Wnd;
1413 Message.message = Msg;
1414 Message.wParam = wParam;
1415 Message.lParam = lParam;
1416 IntGetCursorLocation(pti->Desktop->WindowStation, &Message.pt);
1417 KeQueryTickCount(&LargeTickCount);
1418 pti->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
1419 MsqPostMessage(Window->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1420 }
1421 }
1422 return TRUE;
1423 }
1424
1425
1426 BOOL APIENTRY
1427 NtUserPostMessage(HWND hWnd,
1428 UINT Msg,
1429 WPARAM wParam,
1430 LPARAM lParam)
1431 {
1432 DECLARE_RETURN(BOOL);
1433
1434 DPRINT("Enter NtUserPostMessage\n");
1435 UserEnterExclusive();
1436
1437 RETURN( UserPostMessage(hWnd, Msg, wParam, lParam));
1438
1439 CLEANUP:
1440 DPRINT("Leave NtUserPostMessage, ret=%i\n",_ret_);
1441 UserLeave();
1442 END_CLEANUP;
1443 }
1444
1445
1446
1447 BOOL APIENTRY
1448 NtUserPostThreadMessage(DWORD idThread,
1449 UINT Msg,
1450 WPARAM wParam,
1451 LPARAM lParam)
1452 {
1453 DECLARE_RETURN(BOOL);
1454
1455 DPRINT("Enter NtUserPostThreadMessage\n");
1456 UserEnterExclusive();
1457
1458 RETURN( UserPostThreadMessage( idThread,
1459 Msg,
1460 wParam,
1461 lParam));
1462
1463 CLEANUP:
1464 DPRINT("Leave NtUserPostThreadMessage, ret=%i\n",_ret_);
1465 UserLeave();
1466 END_CLEANUP;
1467 }
1468
1469 DWORD APIENTRY
1470 NtUserQuerySendMessage(DWORD Unknown0)
1471 {
1472 UNIMPLEMENTED;
1473
1474 return 0;
1475 }
1476
1477 LRESULT FASTCALL
1478 co_IntSendMessage(HWND hWnd,
1479 UINT Msg,
1480 WPARAM wParam,
1481 LPARAM lParam)
1482 {
1483 ULONG_PTR Result = 0;
1484 if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1485 {
1486 return (LRESULT)Result;
1487 }
1488 return 0;
1489 }
1490
1491 static
1492 LRESULT FASTCALL
1493 co_IntSendMessageTimeoutSingle(HWND hWnd,
1494 UINT Msg,
1495 WPARAM wParam,
1496 LPARAM lParam,
1497 UINT uFlags,
1498 UINT uTimeout,
1499 ULONG_PTR *uResult)
1500 {
1501 ULONG_PTR Result;
1502 NTSTATUS Status;
1503 PWINDOW_OBJECT Window = NULL;
1504 PMSGMEMORY MsgMemoryEntry;
1505 INT lParamBufferSize;
1506 LPARAM lParamPacked;
1507 PTHREADINFO Win32Thread;
1508 DECLARE_RETURN(LRESULT);
1509 USER_REFERENCE_ENTRY Ref;
1510
1511 if (!(Window = UserGetWindowObject(hWnd)))
1512 {
1513 RETURN( FALSE);
1514 }
1515
1516 UserRefObjectCo(Window, &Ref);
1517
1518 Win32Thread = PsGetCurrentThreadWin32Thread();
1519
1520 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1521
1522 if (NULL != Win32Thread &&
1523 Window->MessageQueue == Win32Thread->MessageQueue)
1524 {
1525 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1526 {
1527 /* Never send messages to exiting threads */
1528 RETURN( FALSE);
1529 }
1530
1531 /* See if this message type is present in the table */
1532 MsgMemoryEntry = FindMsgMemory(Msg);
1533 if (NULL == MsgMemoryEntry)
1534 {
1535 lParamBufferSize = -1;
1536 }
1537 else
1538 {
1539 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1540 }
1541
1542 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam)))
1543 {
1544 DPRINT1("Failed to pack message parameters\n");
1545 RETURN( FALSE);
1546 }
1547
1548 Result = (ULONG_PTR)co_IntCallWindowProc( Window->Wnd->lpfnWndProc,
1549 !Window->Wnd->Unicode,
1550 hWnd,
1551 Msg,
1552 wParam,
1553 lParamPacked,
1554 lParamBufferSize);
1555 if(uResult)
1556 {
1557 *uResult = Result;
1558 }
1559
1560 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1561
1562 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam)))
1563 {
1564 DPRINT1("Failed to unpack message parameters\n");
1565 RETURN( TRUE);
1566 }
1567
1568 RETURN( TRUE);
1569 }
1570
1571 if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->MessageQueue))
1572 {
1573 /* FIXME - Set a LastError? */
1574 RETURN( FALSE);
1575 }
1576
1577 if (Window->Status & WINDOWSTATUS_DESTROYING)
1578 {
1579 /* FIXME - last error? */
1580 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1581 RETURN( FALSE);
1582 }
1583
1584 do
1585 {
1586 Status = co_MsqSendMessage( Window->MessageQueue,
1587 hWnd,
1588 Msg,
1589 wParam,
1590 lParam,
1591 uTimeout,
1592 (uFlags & SMTO_BLOCK),
1593 MSQ_NORMAL,
1594 uResult);
1595 }
1596 while ((STATUS_TIMEOUT == Status) &&
1597 (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
1598 !MsqIsHung(Window->MessageQueue));
1599
1600 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1601
1602 if (STATUS_TIMEOUT == Status)
1603 {
1604 /*
1605 MSDN says:
1606 Microsoft Windows 2000: If GetLastError returns zero, then the function
1607 timed out.
1608 XP+ : If the function fails or times out, the return value is zero.
1609 To get extended error information, call GetLastError. If GetLastError
1610 returns ERROR_TIMEOUT, then the function timed out.
1611 */
1612 SetLastWin32Error(ERROR_TIMEOUT);
1613 RETURN( FALSE);
1614 }
1615 else if (! NT_SUCCESS(Status))
1616 {
1617 SetLastNtError(Status);
1618 RETURN( FALSE);
1619 }
1620
1621 RETURN( TRUE);
1622
1623 CLEANUP:
1624 if (Window) UserDerefObjectCo(Window);
1625 END_CLEANUP;
1626 }
1627
1628 LRESULT FASTCALL
1629 co_IntSendMessageTimeout(HWND hWnd,
1630 UINT Msg,
1631 WPARAM wParam,
1632 LPARAM lParam,
1633 UINT uFlags,
1634 UINT uTimeout,
1635 ULONG_PTR *uResult)
1636 {
1637 PWINDOW_OBJECT DesktopWindow;
1638 HWND *Children;
1639 HWND *Child;
1640
1641 if (HWND_BROADCAST != hWnd)
1642 {
1643 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1644 }
1645
1646 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1647 if (NULL == DesktopWindow)
1648 {
1649 SetLastWin32Error(ERROR_INTERNAL_ERROR);
1650 return 0;
1651 }
1652
1653 Children = IntWinListChildren(DesktopWindow);
1654 if (NULL == Children)
1655 {
1656 return 0;
1657 }
1658
1659 for (Child = Children; NULL != *Child; Child++)
1660 {
1661 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1662 }
1663
1664 ExFreePool(Children);
1665
1666 return (LRESULT) TRUE;
1667 }
1668
1669
1670 /* This function posts a message if the destination's message queue belongs to
1671 another thread, otherwise it sends the message. It does not support broadcast
1672 messages! */
1673 LRESULT FASTCALL
1674 co_IntPostOrSendMessage(HWND hWnd,
1675 UINT Msg,
1676 WPARAM wParam,
1677 LPARAM lParam)
1678 {
1679 ULONG_PTR Result;
1680 PTHREADINFO pti;
1681 PWINDOW_OBJECT Window;
1682
1683 if(hWnd == HWND_BROADCAST)
1684 {
1685 return 0;
1686 }
1687
1688 if(!(Window = UserGetWindowObject(hWnd)))
1689 {
1690 return 0;
1691 }
1692
1693 pti = PsGetCurrentThreadWin32Thread();
1694 if(Window->MessageQueue != pti->MessageQueue && FindMsgMemory(Msg) ==0)
1695 {
1696 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1697 }
1698 else
1699 {
1700 if(!co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result)) {
1701 Result = 0;
1702 }
1703 }
1704
1705 return (LRESULT)Result;
1706 }
1707
1708 LRESULT FASTCALL
1709 co_IntDoSendMessage(HWND hWnd,
1710 UINT Msg,
1711 WPARAM wParam,
1712 LPARAM lParam,
1713 PDOSENDMESSAGE dsm,
1714 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1715 {
1716 PTHREADINFO pti;
1717 LRESULT Result = TRUE;
1718 NTSTATUS Status;
1719 PWINDOW_OBJECT Window = NULL;
1720 NTUSERSENDMESSAGEINFO Info;
1721 MSG UserModeMsg;
1722 MSG KernelModeMsg;
1723 PMSGMEMORY MsgMemoryEntry;
1724
1725 RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));
1726
1727 /* FIXME: Call hooks. */
1728 if (HWND_BROADCAST != hWnd)
1729 {
1730 Window = UserGetWindowObject(hWnd);
1731 if (NULL == Window)
1732 {
1733 /* Tell usermode to not touch this one */
1734 Info.HandledByKernel = TRUE;
1735 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1736 return 0;
1737 }
1738 if (!Window->Wnd)
1739 return 0;
1740 }
1741
1742 /* FIXME: Check for an exiting window. */
1743
1744 /* See if the current thread can handle the message */
1745 pti = PsGetCurrentThreadWin32Thread();
1746 if (HWND_BROADCAST != hWnd && NULL != pti &&
1747 Window->MessageQueue == pti->MessageQueue)
1748 {
1749 /* Gather the information usermode needs to call the window proc directly */
1750 Info.HandledByKernel = FALSE;
1751
1752 Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi),
1753 sizeof(BOOL));
1754 if (! NT_SUCCESS(Status))
1755 {
1756 Info.Ansi = ! Window->Wnd->Unicode;
1757 }
1758
1759 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1760
1761 Info.Ansi = !Window->Wnd->Unicode;
1762 Info.Proc = Window->Wnd->lpfnWndProc;
1763
1764 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, &Result);
1765 }
1766 else
1767 {
1768 /* Must be handled by other thread */
1769 // if (HWND_BROADCAST != hWnd)
1770 // {
1771 // UserDereferenceObject(Window);
1772 // }
1773 Info.HandledByKernel = TRUE;
1774 UserModeMsg.hwnd = hWnd;
1775 UserModeMsg.message = Msg;
1776 UserModeMsg.wParam = wParam;
1777 UserModeMsg.lParam = lParam;
1778 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1779 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1780 if (! NT_SUCCESS(Status))
1781 {
1782 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1783 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1784 return (dsm ? 0 : -1);
1785 }
1786 if(!dsm)
1787 {
1788 Result = co_IntSendMessage(KernelModeMsg.hwnd, KernelModeMsg.message,
1789 KernelModeMsg.wParam, KernelModeMsg.lParam);
1790 }
1791 else
1792 {
1793 Result = co_IntSendMessageTimeout(KernelModeMsg.hwnd, KernelModeMsg.message,
1794 KernelModeMsg.wParam, KernelModeMsg.lParam,
1795 dsm->uFlags, dsm->uTimeout, &dsm->Result);
1796 }
1797 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1798 if (! NT_SUCCESS(Status))
1799 {
1800 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1801 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1802 return(dsm ? 0 : -1);
1803 }
1804 }
1805
1806 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1807 if (! NT_SUCCESS(Status))
1808 {
1809 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1810 }
1811
1812 return (LRESULT)Result;
1813 }
1814
1815 LRESULT APIENTRY
1816 NtUserSendMessageTimeout(HWND hWnd,
1817 UINT Msg,
1818 WPARAM wParam,
1819 LPARAM lParam,
1820 UINT uFlags,
1821 UINT uTimeout,
1822 ULONG_PTR *uResult,
1823 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1824 {
1825 DOSENDMESSAGE dsm;
1826 LRESULT Result;
1827 DECLARE_RETURN(BOOL);
1828
1829 DPRINT("Enter NtUserSendMessageTimeout\n");
1830 UserEnterExclusive();
1831
1832 dsm.uFlags = uFlags;
1833 dsm.uTimeout = uTimeout;
1834 Result = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
1835 if(uResult != NULL && Result != 0)
1836 {
1837 NTSTATUS Status;
1838
1839 Status = MmCopyToCaller(uResult, &dsm.Result, sizeof(ULONG_PTR));
1840 if(!NT_SUCCESS(Status))
1841 {
1842 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1843 RETURN( FALSE);
1844 }
1845 }
1846 RETURN( Result);
1847
1848 CLEANUP:
1849 DPRINT("Leave NtUserSendMessageTimeout, ret=%i\n",_ret_);
1850 UserLeave();
1851 END_CLEANUP;
1852 }
1853
1854 LRESULT APIENTRY
1855 NtUserSendMessage(HWND Wnd,
1856 UINT Msg,
1857 WPARAM wParam,
1858 LPARAM lParam,
1859 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1860 {
1861 DECLARE_RETURN(BOOL);
1862
1863 DPRINT("Enter NtUserSendMessage\n");
1864 UserEnterExclusive();
1865
1866 RETURN(co_IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo));
1867
1868 CLEANUP:
1869 DPRINT("Leave NtUserSendMessage, ret=%i\n",_ret_);
1870 UserLeave();
1871 END_CLEANUP;
1872 }
1873
1874
1875 BOOL FASTCALL
1876 UserSendNotifyMessage(HWND hWnd,
1877 UINT Msg,
1878 WPARAM wParam,
1879 LPARAM lParam)
1880 {
1881 BOOL Result = TRUE;
1882
1883 if (FindMsgMemory(Msg) != 0)
1884 {
1885 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
1886 return FALSE;
1887 }
1888
1889 // Basicly the same as IntPostOrSendMessage
1890 if (hWnd == HWND_BROADCAST) //Handle Broadcast
1891 {
1892 HWND *List;
1893 PWINDOW_OBJECT DesktopWindow;
1894 ULONG i;
1895
1896 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1897 List = IntWinListChildren(DesktopWindow);
1898
1899 if (List != NULL)
1900 {
1901 for (i = 0; List[i]; i++)
1902 {
1903 UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1904 }
1905 ExFreePool(List);
1906 }
1907 }
1908 else
1909 {
1910 ULONG_PTR PResult;
1911 PTHREADINFO pti;
1912 PWINDOW_OBJECT Window;
1913 MSG Message;
1914
1915 if(!(Window = UserGetWindowObject(hWnd))) return FALSE;
1916
1917 pti = PsGetCurrentThreadWin32Thread();
1918 if(Window->MessageQueue != pti->MessageQueue)
1919 { // Send message w/o waiting for it.
1920 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1921 }
1922 else
1923 { // Handle message and callback.
1924 Message.hwnd = hWnd;
1925 Message.message = Msg;
1926 Message.wParam = wParam;
1927 Message.lParam = lParam;
1928
1929 Result = co_IntSendMessageTimeoutSingle( hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &PResult);
1930 }
1931 }
1932 return Result;
1933 }
1934
1935
1936 BOOL APIENTRY
1937 NtUserWaitMessage(VOID)
1938 {
1939 DECLARE_RETURN(BOOL);
1940
1941 DPRINT("EnterNtUserWaitMessage\n");
1942 UserEnterExclusive();
1943
1944 RETURN(co_IntWaitMessage(NULL, 0, 0));
1945
1946 CLEANUP:
1947 DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_);
1948 UserLeave();
1949 END_CLEANUP;
1950 }
1951
1952 DWORD APIENTRY
1953 IntGetQueueStatus(BOOL ClearChanges)
1954 {
1955 PTHREADINFO pti;
1956 PUSER_MESSAGE_QUEUE Queue;
1957 DWORD Result;
1958 DECLARE_RETURN(DWORD);
1959
1960 DPRINT("Enter IntGetQueueStatus\n");
1961
1962 pti = PsGetCurrentThreadWin32Thread();
1963 Queue = pti->MessageQueue;
1964
1965 Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
1966 if (ClearChanges)
1967 {
1968 Queue->ChangedBits = 0;
1969 }
1970
1971 RETURN(Result);
1972
1973 CLEANUP:
1974 DPRINT("Leave IntGetQueueStatus, ret=%i\n",_ret_);
1975 END_CLEANUP;
1976 }
1977
1978 BOOL APIENTRY
1979 IntInitMessagePumpHook()
1980 {
1981 if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti)
1982 {
1983 ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook++;
1984 return TRUE;
1985 }
1986 return FALSE;
1987 }
1988
1989 BOOL APIENTRY
1990 IntUninitMessagePumpHook()
1991 {
1992 if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti)
1993 {
1994 if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook <= 0)
1995 {
1996 return FALSE;
1997 }
1998 ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook--;
1999 return TRUE;
2000 }
2001 return FALSE;
2002 }
2003
2004
2005 BOOL APIENTRY
2006 NtUserMessageCall(
2007 HWND hWnd,
2008 UINT Msg,
2009 WPARAM wParam,
2010 LPARAM lParam,
2011 ULONG_PTR ResultInfo,
2012 DWORD dwType, // fnID?
2013 BOOL Ansi)
2014 {
2015 LRESULT lResult = 0;
2016 BOOL Ret = FALSE;
2017 BOOL BadChk = FALSE;
2018 PWINDOW_OBJECT Window = NULL;
2019 USER_REFERENCE_ENTRY Ref;
2020
2021 UserEnterExclusive();
2022
2023 /* Validate input */
2024 if (hWnd && (hWnd != INVALID_HANDLE_VALUE) && !(Window = UserGetWindowObject(hWnd)))
2025 {
2026 UserLeave();
2027 return FALSE;
2028 }
2029 switch(dwType)
2030 {
2031 case FNID_DEFWINDOWPROC:
2032 UserRefObjectCo(Window, &Ref);
2033 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2034 Ret = TRUE;
2035 UserDerefObjectCo(Window);
2036 break;
2037 case FNID_SENDNOTIFYMESSAGE:
2038 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
2039 break;
2040 case FNID_BROADCASTSYSTEMMESSAGE:
2041 {
2042 BROADCASTPARM parm;
2043 DWORD_PTR RetVal = 0;
2044
2045 if (ResultInfo)
2046 {
2047 _SEH2_TRY
2048 {
2049 ProbeForWrite((PVOID)ResultInfo,
2050 sizeof(BROADCASTPARM),
2051 1);
2052 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
2053 }
2054 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2055 {
2056 BadChk = TRUE;
2057 }
2058 _SEH2_END;
2059 if (BadChk) break;
2060 }
2061 else
2062 break;
2063
2064 if ( parm.recipients & BSM_ALLDESKTOPS ||
2065 parm.recipients == BSM_ALLCOMPONENTS )
2066 {
2067 }
2068 else if (parm.recipients & BSM_APPLICATIONS)
2069 {
2070 if (parm.flags & BSF_QUERY)
2071 {
2072 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2073 {
2074 co_IntSendMessageTimeout( HWND_BROADCAST,
2075 Msg,
2076 wParam,
2077 lParam,
2078 SMTO_ABORTIFHUNG,
2079 2000,
2080 &RetVal);
2081 }
2082 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2083 {
2084 co_IntSendMessageTimeout( HWND_BROADCAST,
2085 Msg,
2086 wParam,
2087 lParam,
2088 SMTO_NOTIMEOUTIFNOTHUNG,
2089 2000,
2090 &RetVal);
2091 }
2092 else
2093 {
2094 co_IntSendMessageTimeout( HWND_BROADCAST,
2095 Msg,
2096 wParam,
2097 lParam,
2098 SMTO_NORMAL,
2099 2000,
2100 &RetVal);
2101 }
2102 }
2103 else if (parm.flags & BSF_POSTMESSAGE)
2104 {
2105 Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
2106 }
2107 else if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
2108 {
2109 Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
2110 }
2111 }
2112 }
2113 break;
2114 case FNID_SENDMESSAGECALLBACK:
2115 break;
2116 // CallNextHook bypass.
2117 case FNID_CALLWNDPROC:
2118 case FNID_CALLWNDPROCRET:
2119 {
2120 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
2121 PHOOK NextObj, Hook = ClientInfo->phkCurrent;
2122
2123 if (!ClientInfo || !Hook) break;
2124
2125 UserReferenceObject(Hook);
2126
2127 if (Hook->Thread && (Hook->Thread != PsGetCurrentThread()))
2128 {
2129 UserDereferenceObject(Hook);
2130 break;
2131 }
2132
2133 NextObj = IntGetNextHook(Hook);
2134 ClientInfo->phkCurrent = NextObj;
2135
2136 if ( Hook->HookId == WH_CALLWNDPROC)
2137 {
2138 CWPSTRUCT CWP;
2139 CWP.hwnd = hWnd;
2140 CWP.message = Msg;
2141 CWP.wParam = wParam;
2142 CWP.lParam = lParam;
2143 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
2144
2145 lResult = co_IntCallHookProc( Hook->HookId,
2146 HC_ACTION,
2147 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2148 (LPARAM)&CWP,
2149 Hook->Proc,
2150 Hook->Ansi,
2151 &Hook->ModuleName);
2152 }
2153 else
2154 {
2155 CWPRETSTRUCT CWPR;
2156 CWPR.hwnd = hWnd;
2157 CWPR.message = Msg;
2158 CWPR.wParam = wParam;
2159 CWPR.lParam = lParam;
2160 CWPR.lResult = ClientInfo->dwHookData;
2161
2162 lResult = co_IntCallHookProc( Hook->HookId,
2163 HC_ACTION,
2164 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2165 (LPARAM)&CWPR,
2166 Hook->Proc,
2167 Hook->Ansi,
2168 &Hook->ModuleName);
2169 }
2170 UserDereferenceObject(Hook);
2171 lResult = (LRESULT) NextObj;
2172 }
2173 break;
2174 }
2175
2176 switch(dwType)
2177 {
2178 case FNID_DEFWINDOWPROC:
2179 case FNID_CALLWNDPROC:
2180 case FNID_CALLWNDPROCRET:
2181 if (ResultInfo)
2182 {
2183 _SEH2_TRY
2184 {
2185 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2186 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2187 }
2188 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2189 {
2190 BadChk = TRUE;
2191 }
2192 _SEH2_END;
2193 }
2194 break;
2195 default:
2196 break;
2197 }
2198
2199 UserLeave();
2200
2201 return BadChk ? FALSE : Ret;
2202 }
2203
2204 #define INFINITE 0xFFFFFFFF
2205 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2206
2207 DWORD
2208 APIENTRY
2209 NtUserWaitForInputIdle(
2210 IN HANDLE hProcess,
2211 IN DWORD dwMilliseconds,
2212 IN BOOL Unknown2)
2213 {
2214 PEPROCESS Process;
2215 PPROCESSINFO W32Process;
2216 NTSTATUS Status;
2217 HANDLE Handles[2];
2218 LARGE_INTEGER Timeout;
2219 ULONGLONG StartTime, Run, Elapsed = 0;
2220
2221 UserEnterExclusive();
2222
2223 Status = ObReferenceObjectByHandle(hProcess,
2224 PROCESS_QUERY_INFORMATION,
2225 PsProcessType,
2226 UserMode,
2227 (PVOID*)&Process,
2228 NULL);
2229
2230 if (!NT_SUCCESS(Status))
2231 {
2232 UserLeave();
2233 SetLastNtError(Status);
2234 return WAIT_FAILED;
2235 }
2236
2237 W32Process = (PPROCESSINFO)Process->Win32Process;
2238 if (!W32Process)
2239 {
2240 ObDereferenceObject(Process);
2241 UserLeave();
2242 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2243 return WAIT_FAILED;
2244 }
2245
2246 EngCreateEvent((PEVENT *)&W32Process->InputIdleEvent);
2247
2248 Handles[0] = Process;
2249 Handles[1] = W32Process->InputIdleEvent;
2250
2251 if (!Handles[1])
2252 {
2253 ObDereferenceObject(Process);
2254 UserLeave();
2255 return STATUS_SUCCESS; /* no event to wait on */
2256 }
2257
2258 StartTime = EngGetTickCount();
2259
2260 Run = dwMilliseconds;
2261
2262 DPRINT("WFII: waiting for %p\n", Handles[1] );
2263 do
2264 {
2265 Timeout.QuadPart = Run - Elapsed;
2266 UserLeave();
2267 Status = KeWaitForMultipleObjects( 2,
2268 Handles,
2269 WaitAny,
2270 UserRequest,
2271 UserMode,
2272 FALSE,
2273 dwMilliseconds == INFINITE ? NULL : &Timeout,
2274 NULL);
2275 UserEnterExclusive();
2276
2277 if (!NT_SUCCESS(Status))
2278 {
2279 SetLastNtError(Status);
2280 Status = WAIT_FAILED;
2281 goto WaitExit;
2282 }
2283
2284 switch (Status)
2285 {
2286 case STATUS_WAIT_0:
2287 Status = WAIT_FAILED;
2288 goto WaitExit;
2289
2290 case STATUS_WAIT_2:
2291 {
2292 USER_MESSAGE Msg;
2293 co_IntPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE );
2294 break;
2295 }
2296
2297 case STATUS_USER_APC:
2298 case STATUS_ALERTED:
2299 case STATUS_TIMEOUT:
2300 DPRINT1("WFII: timeout\n");
2301 Status = STATUS_TIMEOUT;
2302 goto WaitExit;
2303
2304 default:
2305 DPRINT1("WFII: finished\n");
2306 Status = STATUS_SUCCESS;
2307 goto WaitExit;
2308 }
2309
2310 if (dwMilliseconds != INFINITE)
2311 {
2312 Elapsed = EngGetTickCount() - StartTime;
2313
2314 if (Elapsed > Run)
2315 Status = STATUS_TIMEOUT;
2316 break;
2317 }
2318 }
2319 while (1);
2320
2321 WaitExit:
2322 if (W32Process->InputIdleEvent)
2323 {
2324 EngDeleteEvent((PEVENT)W32Process->InputIdleEvent);
2325 W32Process->InputIdleEvent = NULL;
2326 }
2327 ObDereferenceObject(Process);
2328 UserLeave();
2329 return Status;
2330 }
2331
2332 /* EOF */