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