Fix typo.
[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 BOOL SameThread = FALSE;
1392
1393 /* FIXME: Call hooks. */
1394 if (!(Window = UserGetWindowObject(hWnd)))
1395 {
1396 RETURN( FALSE);
1397 }
1398
1399 UserRefObjectCo(Window, &Ref);
1400
1401 Win32Thread = PsGetCurrentThreadWin32Thread();
1402
1403 if (NULL != Win32Thread &&
1404 Window->MessageQueue == Win32Thread->MessageQueue)
1405 {
1406 if (Win32Thread->IsExiting)
1407 {
1408 /* Never send messages to exiting threads */
1409 RETURN( FALSE);
1410 }
1411
1412 /* See if this message type is present in the table */
1413 MsgMemoryEntry = FindMsgMemory(Msg);
1414 if (NULL == MsgMemoryEntry)
1415 {
1416 lParamBufferSize = -1;
1417 }
1418 else
1419 {
1420 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1421 }
1422
1423 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam)))
1424 {
1425 DPRINT1("Failed to pack message parameters\n");
1426 RETURN( FALSE);
1427 }
1428
1429 if (Window->ti == Win32Thread->ThreadInfo)
1430 SameThread = TRUE;
1431
1432 if ((!SameThread && (Window->ti->Hooks & HOOKID_TO_FLAG(WH_CALLWNDPROC))) ||
1433 (SameThread && ISITHOOKED(WH_CALLWNDPROC)) )
1434 {
1435 CWPSTRUCT CWP;
1436 CWP.hwnd = hWnd;
1437 CWP.message = Msg;
1438 CWP.wParam = wParam;
1439 CWP.lParam = lParam;
1440 co_HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, SameThread, (LPARAM)&CWP );
1441 }
1442
1443 Result = (ULONG_PTR)co_IntCallWindowProc(Window->Wnd->WndProc, !Window->Wnd->Unicode, hWnd, Msg, wParam,
1444 lParamPacked,lParamBufferSize);
1445
1446 if(uResult)
1447 {
1448 *uResult = Result;
1449 }
1450
1451 if ((!SameThread && (Window->ti->Hooks & HOOKID_TO_FLAG(WH_CALLWNDPROCRET))) ||
1452 (SameThread && ISITHOOKED(WH_CALLWNDPROCRET)) )
1453 {
1454 CWPRETSTRUCT CWPR;
1455 CWPR.hwnd = hWnd;
1456 CWPR.message = Msg;
1457 CWPR.wParam = wParam;
1458 CWPR.lParam = lParam;
1459 CWPR.lResult = Result;
1460 co_HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, SameThread, (LPARAM)&CWPR );
1461 }
1462
1463 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam)))
1464 {
1465 DPRINT1("Failed to unpack message parameters\n");
1466 RETURN( TRUE);
1467 }
1468
1469 RETURN( TRUE);
1470 }
1471
1472 if(uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->MessageQueue))
1473 {
1474 /* FIXME - Set a LastError? */
1475 RETURN( FALSE);
1476 }
1477
1478 if(Window->Status & WINDOWSTATUS_DESTROYING)
1479 {
1480 /* FIXME - last error? */
1481 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1482 RETURN( FALSE);
1483 }
1484
1485 Status = co_MsqSendMessage(Window->MessageQueue, hWnd, Msg, wParam, lParam,
1486 uTimeout, (uFlags & SMTO_BLOCK), FALSE, uResult);
1487
1488
1489 if (STATUS_TIMEOUT == Status)
1490 {
1491 /* MSDN says GetLastError() should return 0 after timeout */
1492 SetLastWin32Error(0);
1493 RETURN( FALSE);
1494 }
1495 else if (! NT_SUCCESS(Status))
1496 {
1497 SetLastNtError(Status);
1498 RETURN( FALSE);
1499 }
1500
1501 RETURN( TRUE);
1502
1503 CLEANUP:
1504 if (Window) UserDerefObjectCo(Window);
1505 END_CLEANUP;
1506 }
1507
1508 LRESULT FASTCALL
1509 co_IntSendMessageTimeout(HWND hWnd,
1510 UINT Msg,
1511 WPARAM wParam,
1512 LPARAM lParam,
1513 UINT uFlags,
1514 UINT uTimeout,
1515 ULONG_PTR *uResult)
1516 {
1517 PWINDOW_OBJECT DesktopWindow;
1518 HWND *Children;
1519 HWND *Child;
1520
1521 if (HWND_BROADCAST != hWnd)
1522 {
1523 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1524 }
1525
1526 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1527 if (NULL == DesktopWindow)
1528 {
1529 SetLastWin32Error(ERROR_INTERNAL_ERROR);
1530 return 0;
1531 }
1532
1533 Children = IntWinListChildren(DesktopWindow);
1534 if (NULL == Children)
1535 {
1536 return 0;
1537 }
1538
1539 for (Child = Children; NULL != *Child; Child++)
1540 {
1541 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1542 }
1543
1544 ExFreePool(Children);
1545
1546 return (LRESULT) TRUE;
1547 }
1548
1549
1550 /* This function posts a message if the destination's message queue belongs to
1551 another thread, otherwise it sends the message. It does not support broadcast
1552 messages! */
1553 LRESULT FASTCALL
1554 co_IntPostOrSendMessage(HWND hWnd,
1555 UINT Msg,
1556 WPARAM wParam,
1557 LPARAM lParam)
1558 {
1559 ULONG_PTR Result;
1560 PWINDOW_OBJECT Window;
1561
1562 if(hWnd == HWND_BROADCAST)
1563 {
1564 return 0;
1565 }
1566
1567 if(!(Window = UserGetWindowObject(hWnd)))
1568 {
1569 return 0;
1570 }
1571
1572 if(Window->MessageQueue != PsGetCurrentThreadWin32Thread()->MessageQueue)
1573 {
1574 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1575 }
1576 else
1577 {
1578 if(!co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result)) {
1579 Result = 0;
1580 }
1581 }
1582
1583 return (LRESULT)Result;
1584 }
1585
1586 LRESULT FASTCALL
1587 co_IntDoSendMessage(HWND hWnd,
1588 UINT Msg,
1589 WPARAM wParam,
1590 LPARAM lParam,
1591 PDOSENDMESSAGE dsm,
1592 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1593 {
1594 LRESULT Result = TRUE;
1595 NTSTATUS Status;
1596 PWINDOW_OBJECT Window;
1597 NTUSERSENDMESSAGEINFO Info;
1598 MSG UserModeMsg;
1599 MSG KernelModeMsg;
1600 PMSGMEMORY MsgMemoryEntry;
1601
1602 RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));
1603
1604 /* FIXME: Call hooks. */
1605 if (HWND_BROADCAST != hWnd)
1606 {
1607 Window = UserGetWindowObject(hWnd);
1608 if (NULL == Window)
1609 {
1610 /* Tell usermode to not touch this one */
1611 Info.HandledByKernel = TRUE;
1612 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1613 return 0;
1614 }
1615 if (!Window->Wnd)
1616 return 0;
1617 }
1618
1619 /* FIXME: Check for an exiting window. */
1620
1621 /* See if the current thread can handle the message */
1622 if (HWND_BROADCAST != hWnd && NULL != PsGetCurrentThreadWin32Thread() &&
1623 Window->MessageQueue == PsGetCurrentThreadWin32Thread()->MessageQueue)
1624 {
1625 /* Gather the information usermode needs to call the window proc directly */
1626 Info.HandledByKernel = FALSE;
1627
1628 Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi),
1629 sizeof(BOOL));
1630 if (! NT_SUCCESS(Status))
1631 {
1632 Info.Ansi = ! Window->Wnd->Unicode;
1633 }
1634
1635 if (Window->Wnd->IsSystem)
1636 {
1637 Info.Proc = (!Info.Ansi ? Window->Wnd->WndProc : Window->Wnd->WndProcExtra);
1638 }
1639 else
1640 {
1641 Info.Ansi = !Window->Wnd->Unicode;
1642 Info.Proc = Window->Wnd->WndProc;
1643 }
1644 }
1645 else
1646 {
1647 /* Must be handled by other thread */
1648 // if (HWND_BROADCAST != hWnd)
1649 // {
1650 // UserDereferenceObject(Window);
1651 // }
1652 Info.HandledByKernel = TRUE;
1653 UserModeMsg.hwnd = hWnd;
1654 UserModeMsg.message = Msg;
1655 UserModeMsg.wParam = wParam;
1656 UserModeMsg.lParam = lParam;
1657 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1658 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1659 if (! NT_SUCCESS(Status))
1660 {
1661 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1662 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1663 return (dsm ? 0 : -1);
1664 }
1665 if(!dsm)
1666 {
1667 Result = co_IntSendMessage(KernelModeMsg.hwnd, KernelModeMsg.message,
1668 KernelModeMsg.wParam, KernelModeMsg.lParam);
1669 }
1670 else
1671 {
1672 Result = co_IntSendMessageTimeout(KernelModeMsg.hwnd, KernelModeMsg.message,
1673 KernelModeMsg.wParam, KernelModeMsg.lParam,
1674 dsm->uFlags, dsm->uTimeout, &dsm->Result);
1675 }
1676 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1677 if (! NT_SUCCESS(Status))
1678 {
1679 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1680 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1681 return(dsm ? 0 : -1);
1682 }
1683 }
1684
1685 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1686 if (! NT_SUCCESS(Status))
1687 {
1688 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1689 }
1690
1691 return (LRESULT)Result;
1692 }
1693
1694 LRESULT STDCALL
1695 NtUserSendMessageTimeout(HWND hWnd,
1696 UINT Msg,
1697 WPARAM wParam,
1698 LPARAM lParam,
1699 UINT uFlags,
1700 UINT uTimeout,
1701 ULONG_PTR *uResult,
1702 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1703 {
1704 DOSENDMESSAGE dsm;
1705 LRESULT Result;
1706 DECLARE_RETURN(BOOL);
1707
1708 DPRINT("Enter NtUserSendMessageTimeout\n");
1709 UserEnterExclusive();
1710
1711 dsm.uFlags = uFlags;
1712 dsm.uTimeout = uTimeout;
1713 Result = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
1714 if(uResult != NULL && Result != 0)
1715 {
1716 NTSTATUS Status;
1717
1718 Status = MmCopyToCaller(uResult, &dsm.Result, sizeof(ULONG_PTR));
1719 if(!NT_SUCCESS(Status))
1720 {
1721 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1722 RETURN( FALSE);
1723 }
1724 }
1725 RETURN( Result);
1726
1727 CLEANUP:
1728 DPRINT("Leave NtUserSendMessageTimeout, ret=%i\n",_ret_);
1729 UserLeave();
1730 END_CLEANUP;
1731 }
1732
1733 LRESULT STDCALL
1734 NtUserSendMessage(HWND Wnd,
1735 UINT Msg,
1736 WPARAM wParam,
1737 LPARAM lParam,
1738 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1739 {
1740 DECLARE_RETURN(BOOL);
1741
1742 DPRINT("Enter NtUserSendMessage\n");
1743 UserEnterExclusive();
1744
1745 RETURN(co_IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo));
1746
1747 CLEANUP:
1748 DPRINT("Leave NtUserSendMessage, ret=%i\n",_ret_);
1749 UserLeave();
1750 END_CLEANUP;
1751 }
1752
1753
1754 BOOL FASTCALL
1755 UserSendNotifyMessage(HWND hWnd,
1756 UINT Msg,
1757 WPARAM wParam,
1758 LPARAM lParam)
1759 {
1760 BOOL Result = TRUE;
1761 // Basicly the same as IntPostOrSendMessage
1762 if (hWnd == HWND_BROADCAST) //Handle Broadcast
1763 {
1764 HWND *List;
1765 PWINDOW_OBJECT DesktopWindow;
1766 ULONG i;
1767
1768 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1769 List = IntWinListChildren(DesktopWindow);
1770
1771 if (List != NULL)
1772 {
1773 for (i = 0; List[i]; i++)
1774 {
1775 UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1776 }
1777 ExFreePool(List);
1778 }
1779 }
1780 else
1781 {
1782 ULONG_PTR PResult;
1783 PWINDOW_OBJECT Window;
1784 NTSTATUS Status;
1785 MSG UserModeMsg;
1786 MSG KernelModeMsg;
1787 PMSGMEMORY MsgMemoryEntry;
1788
1789 if(!(Window = UserGetWindowObject(hWnd))) return FALSE;
1790
1791 if(Window->MessageQueue != PsGetCurrentThreadWin32Thread()->MessageQueue)
1792 { // Send message w/o waiting for it.
1793 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1794 }
1795 else
1796 { // Handle message and callback.
1797 UserModeMsg.hwnd = hWnd;
1798 UserModeMsg.message = Msg;
1799 UserModeMsg.wParam = wParam;
1800 UserModeMsg.lParam = lParam;
1801 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1802 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1803 if (! NT_SUCCESS(Status))
1804 {
1805 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1806 return FALSE;
1807 }
1808 Result = co_IntSendMessageTimeoutSingle(
1809 KernelModeMsg.hwnd, KernelModeMsg.message,
1810 KernelModeMsg.wParam, KernelModeMsg.lParam,
1811 SMTO_NORMAL, 0, &PResult);
1812
1813 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1814 if (! NT_SUCCESS(Status))
1815 {
1816 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1817 return FALSE;
1818 }
1819 }
1820 }
1821 return Result;
1822 }
1823
1824
1825 BOOL STDCALL
1826 NtUserSendNotifyMessage(HWND hWnd,
1827 UINT Msg,
1828 WPARAM wParam,
1829 LPARAM lParam)
1830 {
1831 DECLARE_RETURN(BOOL);
1832
1833 DPRINT("EnterNtUserSendNotifyMessage\n");
1834 UserEnterExclusive();
1835
1836 RETURN(UserSendNotifyMessage(hWnd, Msg, wParam, lParam));
1837
1838 CLEANUP:
1839 DPRINT("Leave NtUserSendNotifyMessage, ret=%i\n",_ret_);
1840 UserLeave();
1841 END_CLEANUP;
1842
1843 }
1844
1845
1846 BOOL STDCALL
1847 NtUserWaitMessage(VOID)
1848 {
1849 DECLARE_RETURN(BOOL);
1850
1851 DPRINT("EnterNtUserWaitMessage\n");
1852 UserEnterExclusive();
1853
1854 RETURN(co_IntWaitMessage(NULL, 0, 0));
1855
1856 CLEANUP:
1857 DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_);
1858 UserLeave();
1859 END_CLEANUP;
1860 }
1861
1862 DWORD STDCALL
1863 IntGetQueueStatus(BOOL ClearChanges)
1864 {
1865 PUSER_MESSAGE_QUEUE Queue;
1866 DWORD Result;
1867 DECLARE_RETURN(DWORD);
1868
1869 DPRINT("Enter IntGetQueueStatus\n");
1870
1871 Queue = PsGetCurrentThreadWin32Thread()->MessageQueue;
1872
1873 Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
1874 if (ClearChanges)
1875 {
1876 Queue->ChangedBits = 0;
1877 }
1878
1879 RETURN(Result);
1880
1881 CLEANUP:
1882 DPRINT("Leave IntGetQueueStatus, ret=%i\n",_ret_);
1883 END_CLEANUP;
1884 }
1885
1886 BOOL STDCALL
1887 IntInitMessagePumpHook()
1888 {
1889 if (((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo)
1890 {
1891 ((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook++;
1892 return TRUE;
1893 }
1894 return FALSE;
1895 }
1896
1897 BOOL STDCALL
1898 IntUninitMessagePumpHook()
1899 {
1900 if (((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo)
1901 {
1902 if (((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook <= 0)
1903 {
1904 return FALSE;
1905 }
1906 ((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->ThreadInfo->ClientThreadInfo.dwcPumpHook--;
1907 return TRUE;
1908 }
1909 return FALSE;
1910 }
1911
1912
1913 LRESULT STDCALL
1914 NtUserMessageCall(
1915 HWND hWnd,
1916 UINT Msg,
1917 WPARAM wParam,
1918 LPARAM lParam,
1919 ULONG_PTR ResultInfo,
1920 DWORD dwType, // fnID?
1921 BOOL Ansi)
1922 {
1923 LRESULT lResult = 0;
1924 PWINDOW_OBJECT Window = NULL;
1925 USER_REFERENCE_ENTRY Ref;
1926
1927 UserEnterExclusive();
1928
1929 /* Validate input */
1930 if (hWnd && (hWnd != INVALID_HANDLE_VALUE) && !(Window = UserGetWindowObject(hWnd)))
1931 {
1932 return 0;
1933 }
1934 switch(dwType)
1935 {
1936 case FNID_DEFWINDOWPROC:
1937 UserRefObjectCo(Window, &Ref);
1938 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
1939 UserDerefObjectCo(Window);
1940 break;
1941 case FNID_BROADCASTSYSTEMMESSAGE:
1942 {
1943 PBROADCASTPARM parm;
1944 BOOL BadChk = FALSE;
1945 DWORD_PTR RetVal = 0;
1946 lResult = -1;
1947
1948 if (ResultInfo)
1949 {
1950 _SEH_TRY
1951 {
1952 ProbeForWrite((PVOID)ResultInfo,
1953 sizeof(BROADCASTPARM),
1954 1);
1955 parm = (PBROADCASTPARM)ResultInfo;
1956 }
1957 _SEH_HANDLE
1958 {
1959 BadChk = TRUE;
1960 }
1961 _SEH_END;
1962 if (BadChk) break;
1963 }
1964 else
1965 break;
1966
1967 if ( parm->recipients & BSM_ALLDESKTOPS ||
1968 parm->recipients == BSM_ALLCOMPONENTS )
1969 {
1970 }
1971 else if (parm->recipients & BSM_APPLICATIONS)
1972 {
1973 if (parm->flags & BSF_QUERY)
1974 {
1975 if (parm->flags & BSF_FORCEIFHUNG || parm->flags & BSF_NOHANG)
1976 {
1977 co_IntSendMessageTimeout( HWND_BROADCAST,
1978 Msg,
1979 wParam,
1980 lParam,
1981 SMTO_ABORTIFHUNG,
1982 2000,
1983 &RetVal);
1984 }
1985 else if (parm->flags & BSF_NOTIMEOUTIFNOTHUNG)
1986 {
1987 co_IntSendMessageTimeout( HWND_BROADCAST,
1988 Msg,
1989 wParam,
1990 lParam,
1991 SMTO_NOTIMEOUTIFNOTHUNG,
1992 2000,
1993 &RetVal);
1994 }
1995 else
1996 {
1997 co_IntSendMessageTimeout( HWND_BROADCAST,
1998 Msg,
1999 wParam,
2000 lParam,
2001 SMTO_NORMAL,
2002 2000,
2003 &RetVal);
2004 }
2005 }
2006 else if (parm->flags & BSF_POSTMESSAGE)
2007 {
2008 lResult = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
2009 }
2010 else if ( parm->flags & BSF_SENDNOTIFYMESSAGE)
2011 {
2012 lResult = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
2013 }
2014 }
2015 }
2016 break;
2017 case FNID_SENDMESSAGECALLBACK:
2018 break;
2019 case FNID_CALLWNDPROC:
2020 {
2021 CWPSTRUCT CWP;
2022 PW32CLIENTINFO ClientInfo = GetWin32ClientInfo();
2023 CWP.hwnd = hWnd;
2024 CWP.message = Msg;
2025 CWP.wParam = wParam;
2026 CWP.lParam = lParam;
2027 lResult = co_HOOK_CallHooks( WH_CALLWNDPROC,
2028 HC_ACTION,
2029 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2030 (LPARAM)&CWP );
2031 }
2032 break;
2033 case FNID_CALLWNDPROCRET:
2034 {
2035 CWPRETSTRUCT CWPR;
2036 PW32CLIENTINFO ClientInfo = GetWin32ClientInfo();
2037 CWPR.hwnd = hWnd;
2038 CWPR.message = Msg;
2039 CWPR.wParam = wParam;
2040 CWPR.lParam = lParam;
2041 CWPR.lResult = ClientInfo->dwHookData;
2042 lResult = co_HOOK_CallHooks( WH_CALLWNDPROCRET,
2043 HC_ACTION,
2044 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2045 (LPARAM)&CWPR );
2046 }
2047 break;
2048 }
2049 UserLeave();
2050 return lResult;
2051 }
2052
2053 #define INFINITE 0xFFFFFFFF
2054 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2055
2056 DWORD
2057 NTAPI
2058 NtUserWaitForInputIdle(
2059 IN HANDLE hProcess,
2060 IN DWORD dwMilliseconds,
2061 IN BOOL Unknown2)
2062 {
2063 PEPROCESS Process;
2064 PW32PROCESS W32Process;
2065 NTSTATUS Status;
2066 HANDLE Handles[2];
2067 LARGE_INTEGER Timeout;
2068 ULONGLONG StartTime, Run, Elapsed = 0;
2069
2070 UserEnterExclusive();
2071
2072 Status = ObReferenceObjectByHandle(hProcess,
2073 PROCESS_QUERY_INFORMATION,
2074 PsProcessType,
2075 UserMode,
2076 (PVOID*)&Process,
2077 NULL);
2078
2079 if (!NT_SUCCESS(Status))
2080 {
2081 UserLeave();
2082 SetLastNtError(Status);
2083 return WAIT_FAILED;
2084 }
2085
2086 W32Process = (PW32PROCESS)Process->Win32Process;
2087 if (!W32Process)
2088 {
2089 ObDereferenceObject(Process);
2090 UserLeave();
2091 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2092 return WAIT_FAILED;
2093 }
2094
2095 EngCreateEvent((PEVENT *)&W32Process->InputIdleEvent);
2096
2097 Handles[0] = Process;
2098 Handles[1] = W32Process->InputIdleEvent;
2099
2100 if (!Handles[1])
2101 {
2102 ObDereferenceObject(Process);
2103 UserLeave();
2104 return STATUS_SUCCESS; /* no event to wait on */
2105 }
2106
2107 StartTime = ((ULONGLONG)SharedUserData->TickCountLowDeprecated *
2108 SharedUserData->TickCountMultiplier / 16777216);
2109
2110 Run = dwMilliseconds;
2111
2112 DPRINT("WFII: waiting for %p\n", Handles[1] );
2113 do
2114 {
2115 Timeout.QuadPart = Run - Elapsed;
2116 UserLeave();
2117 Status = KeWaitForMultipleObjects( 2,
2118 Handles,
2119 WaitAny,
2120 UserRequest,
2121 UserMode,
2122 FALSE,
2123 dwMilliseconds == INFINITE ? NULL : &Timeout,
2124 NULL);
2125 UserEnterExclusive();
2126
2127 if (!NT_SUCCESS(Status))
2128 {
2129 SetLastNtError(Status);
2130 Status = WAIT_FAILED;
2131 goto WaitExit;
2132 }
2133
2134 switch (Status)
2135 {
2136 case STATUS_WAIT_0:
2137 Status = WAIT_FAILED;
2138 goto WaitExit;
2139
2140 case STATUS_WAIT_2:
2141 {
2142 USER_MESSAGE Msg;
2143 co_IntPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE );
2144 break;
2145 }
2146
2147 case STATUS_USER_APC:
2148 case STATUS_ALERTED:
2149 case STATUS_TIMEOUT:
2150 DPRINT1("WFII: timeout\n");
2151 Status = STATUS_TIMEOUT;
2152 goto WaitExit;
2153
2154 default:
2155 DPRINT1("WFII: finished\n");
2156 Status = STATUS_SUCCESS;
2157 goto WaitExit;
2158 }
2159
2160 if (dwMilliseconds != INFINITE)
2161 {
2162 Elapsed = ((ULONGLONG)SharedUserData->TickCountLowDeprecated *
2163 SharedUserData->TickCountMultiplier / 16777216)
2164 - StartTime;
2165
2166 if (Elapsed > Run)
2167 Status = STATUS_TIMEOUT;
2168 break;
2169 }
2170 }
2171 while (1);
2172
2173 WaitExit:
2174 if (W32Process->InputIdleEvent)
2175 {
2176 EngDeleteEvent((PEVENT)W32Process->InputIdleEvent);
2177 W32Process->InputIdleEvent = NULL;
2178 }
2179 ObDereferenceObject(Process);
2180 UserLeave();
2181 return Status;
2182 }
2183
2184 /* EOF */