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