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