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