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