e7265c062205691c2b119b1211d9923407f069ce
[reactos.git] / 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 = IntSysCreateRectRgn( 0, 0, 0, 0 );
420 co_UserGetUpdateRgn( Window, hrgn, TRUE );
421 REGION_FreeRgnByHandle( 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->pti->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->pti->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->pti->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 /* Note:
675 The only flag we process is PM_REMOVE.
676 Processing (High word) PM_QS_Xx Is needed. This and MsgFilterXxx can result
677 with QS_Xx flags to be used to isolate which message check to test for.
678 ATM, we look at all messages and the filters are sent to co_MsqFindMessage
679 and there, it is cross checked.
680 Example: Wine server/queue.c is_keyboard_msg, check_msg_filter and
681 filter_contains_hw_range.
682 */
683 RemoveMessages = RemoveMsg & PM_REMOVE;
684
685 /*
686 If no filter is specified, messages are processed in the following order:
687
688 * Sent messages
689 * Posted messages
690 * Input (hardware) messages and system internal events
691 * Sent messages (again)
692 * WM_PAINT messages
693 * WM_TIMER messages
694 */
695 CheckMessages:
696
697 Present = FALSE;
698
699 KeQueryTickCount(&LargeTickCount);
700 ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
701
702 /* Dispatch sent messages here. */
703 while (co_MsqDispatchOneSentMessage(ThreadQueue))
704 ;
705
706 /* Now look for a quit message. */
707
708 if (ThreadQueue->QuitPosted)
709 {
710 /* According to the PSDK, WM_QUIT messages are always returned, regardless
711 of the filter specified */
712 Msg->Msg.hwnd = NULL;
713 Msg->Msg.message = WM_QUIT;
714 Msg->Msg.wParam = ThreadQueue->QuitExitCode;
715 Msg->Msg.lParam = 0;
716 Msg->FreeLParam = FALSE;
717 if (RemoveMessages)
718 {
719 ThreadQueue->QuitPosted = FALSE;
720 }
721 goto MsgExit;
722 }
723
724 /* Now check for normal messages. */
725 Present = co_MsqFindMessage( ThreadQueue,
726 FALSE,
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 hardware events. */
743 Present = co_MsqFindMessage( ThreadQueue,
744 TRUE,
745 RemoveMessages,
746 Window,
747 MsgFilterMin,
748 MsgFilterMax,
749 &Message );
750 if (Present)
751 {
752 RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
753 if (RemoveMessages)
754 {
755 MsqDestroyMessage(Message);
756 }
757 goto MessageFound;
758 }
759
760 /* Check for sent messages again. */
761 while (co_MsqDispatchOneSentMessage(ThreadQueue))
762 ;
763
764 /* Check for paint messages. */
765 if ( IntGetPaintMessage( Window,
766 MsgFilterMin,
767 MsgFilterMax,
768 pti,
769 &Msg->Msg,
770 RemoveMessages))
771 {
772 Msg->FreeLParam = FALSE;
773 goto MsgExit;
774 }
775
776 if (ThreadQueue->WakeMask & QS_TIMER)
777 if (PostTimerMessages(Window)) // If there are timers ready,
778 goto CheckMessages; // go back and process them.
779
780 // LOL! Polling Timer Queue? How much time is spent doing this?
781 /* Check for WM_(SYS)TIMER messages */
782 Present = MsqGetTimerMessage( ThreadQueue,
783 Window,
784 MsgFilterMin,
785 MsgFilterMax,
786 &Msg->Msg,
787 RemoveMessages);
788 if (Present)
789 {
790 Msg->FreeLParam = FALSE;
791 goto MessageFound;
792 }
793
794 if(Present)
795 {
796 MessageFound:
797
798 if(RemoveMessages)
799 {
800 PWINDOW_OBJECT MsgWindow = NULL;
801
802 /* Mouse message process */
803
804 if( Msg->Msg.hwnd &&
805 ( MsgWindow = UserGetWindowObject(Msg->Msg.hwnd) ) &&
806 Msg->Msg.message >= WM_MOUSEFIRST &&
807 Msg->Msg.message <= WM_MOUSELAST )
808 {
809 USHORT HitTest;
810
811 UserRefObjectCo(MsgWindow, &Ref);
812
813 if ( co_IntTranslateMouseMessage( ThreadQueue,
814 &Msg->Msg,
815 &HitTest,
816 TRUE))
817 /* FIXME - check message filter again, if the message doesn't match anymore,
818 search again */
819 {
820 UserDerefObjectCo(MsgWindow);
821 /* eat the message, search again */
822 goto CheckMessages;
823 }
824
825 if(ThreadQueue->CaptureWindow == NULL)
826 {
827 co_IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
828
829 if ( ( Msg->Msg.message != WM_MOUSEMOVE &&
830 Msg->Msg.message != WM_NCMOUSEMOVE ) &&
831 IS_BTN_MESSAGE(Msg->Msg.message, DOWN) &&
832 co_IntActivateWindowMouse(ThreadQueue, &Msg->Msg, MsgWindow, &HitTest) )
833 {
834 UserDerefObjectCo(MsgWindow);
835 /* eat the message, search again */
836 goto CheckMessages;
837 }
838 }
839
840 UserDerefObjectCo(MsgWindow);
841 }
842 else
843 {
844 co_IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
845 }
846
847 // if(MsgWindow)
848 // {
849 // UserDereferenceObject(MsgWindow);
850 // }
851
852 goto MsgExit;
853 }
854
855 if ( ( Msg->Msg.hwnd &&
856 Msg->Msg.message >= WM_MOUSEFIRST &&
857 Msg->Msg.message <= WM_MOUSELAST ) &&
858 co_IntTranslateMouseMessage( ThreadQueue,
859 &Msg->Msg,
860 &HitTest,
861 FALSE) )
862 /* FIXME - check message filter again, if the message doesn't match anymore,
863 search again */
864 {
865 /* eat the message, search again */
866 goto CheckMessages;
867 }
868
869 MsgExit:
870 if ( ISITHOOKED(WH_MOUSE) &&
871 Msg->Msg.message >= WM_MOUSEFIRST &&
872 Msg->Msg.message <= WM_MOUSELAST )
873 {
874 MHook.pt = Msg->Msg.pt;
875 MHook.hwnd = Msg->Msg.hwnd;
876 MHook.wHitTestCode = HitTest;
877 MHook.dwExtraInfo = 0;
878 if (co_HOOK_CallHooks( WH_MOUSE,
879 RemoveMsg ? HC_ACTION : HC_NOREMOVE,
880 Msg->Msg.message,
881 (LPARAM)&MHook ))
882 {
883 if (ISITHOOKED(WH_CBT))
884 {
885 MHook.pt = Msg->Msg.pt;
886 MHook.hwnd = Msg->Msg.hwnd;
887 MHook.wHitTestCode = HitTest;
888 MHook.dwExtraInfo = 0;
889 co_HOOK_CallHooks( WH_CBT,
890 HCBT_CLICKSKIPPED,
891 Msg->Msg.message,
892 (LPARAM)&MHook);
893 }
894 return FALSE;
895 }
896 }
897
898 if ( ISITHOOKED(WH_KEYBOARD) &&
899 (Msg->Msg.message == WM_KEYDOWN || Msg->Msg.message == WM_KEYUP) )
900 {
901 if (co_HOOK_CallHooks( WH_KEYBOARD,
902 RemoveMsg ? HC_ACTION : HC_NOREMOVE,
903 LOWORD(Msg->Msg.wParam),
904 Msg->Msg.lParam))
905 {
906 if (ISITHOOKED(WH_CBT))
907 {
908 /* skip this message */
909 co_HOOK_CallHooks( WH_CBT,
910 HCBT_KEYSKIPPED,
911 LOWORD(Msg->Msg.wParam),
912 Msg->Msg.lParam );
913 }
914 return FALSE;
915 }
916 }
917 // The WH_GETMESSAGE hook enables an application to monitor messages about to
918 // be returned by the GetMessage or PeekMessage function.
919 if (ISITHOOKED(WH_GETMESSAGE))
920 {
921 //DPRINT1("Peek WH_GETMESSAGE -> %x\n",&Msg);
922 co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)&Msg->Msg);
923 }
924 return TRUE;
925 }
926
927 return Present;
928 }
929
930 static NTSTATUS FASTCALL
931 CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
932 {
933 NTSTATUS Status;
934
935 PVOID KernelMem;
936 UINT Size;
937
938 *KernelModeMsg = *UserModeMsg;
939
940 /* See if this message type is present in the table */
941 if (NULL == MsgMemoryEntry)
942 {
943 /* Not present, no copying needed */
944 return STATUS_SUCCESS;
945 }
946
947 /* Determine required size */
948 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
949
950 if (0 != Size)
951 {
952 /* Allocate kernel mem */
953 KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
954 if (NULL == KernelMem)
955 {
956 DPRINT1("Not enough memory to copy message to kernel mem\n");
957 return STATUS_NO_MEMORY;
958 }
959 KernelModeMsg->lParam = (LPARAM) KernelMem;
960
961 /* Copy data if required */
962 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
963 {
964 Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
965 if (! NT_SUCCESS(Status))
966 {
967 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
968 ExFreePoolWithTag(KernelMem, TAG_MSG);
969 return Status;
970 }
971 }
972 else
973 {
974 /* Make sure we don't pass any secrets to usermode */
975 RtlZeroMemory(KernelMem, Size);
976 }
977 }
978 else
979 {
980 KernelModeMsg->lParam = 0;
981 }
982
983 return STATUS_SUCCESS;
984 }
985
986 static NTSTATUS FASTCALL
987 CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
988 {
989 NTSTATUS Status;
990 PMSGMEMORY MsgMemoryEntry;
991 UINT Size;
992
993 /* See if this message type is present in the table */
994 MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
995 if (NULL == MsgMemoryEntry)
996 {
997 /* Not present, no copying needed */
998 return STATUS_SUCCESS;
999 }
1000
1001 /* Determine required size */
1002 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
1003
1004 if (0 != Size)
1005 {
1006 /* Copy data if required */
1007 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
1008 {
1009 Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
1010 if (! NT_SUCCESS(Status))
1011 {
1012 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1013 ExFreePool((PVOID) KernelModeMsg->lParam);
1014 return Status;
1015 }
1016 }
1017
1018 ExFreePool((PVOID) KernelModeMsg->lParam);
1019 }
1020
1021 return STATUS_SUCCESS;
1022 }
1023
1024 static BOOL FASTCALL
1025 co_IntWaitMessage( PWINDOW_OBJECT Window,
1026 UINT MsgFilterMin,
1027 UINT MsgFilterMax )
1028 {
1029 PTHREADINFO pti;
1030 PUSER_MESSAGE_QUEUE ThreadQueue;
1031 NTSTATUS Status = STATUS_SUCCESS;
1032 USER_MESSAGE Msg;
1033
1034 pti = PsGetCurrentThreadWin32Thread();
1035 ThreadQueue = pti->MessageQueue;
1036
1037 do
1038 {
1039 if ( co_IntPeekMessage( &Msg,
1040 Window,
1041 MsgFilterMin,
1042 MsgFilterMax,
1043 PM_NOREMOVE))
1044 {
1045 return TRUE;
1046 }
1047 /* Nothing found. Wait for new messages. */
1048 Status = co_MsqWaitForNewMessages( ThreadQueue,
1049 Window,
1050 MsgFilterMin,
1051 MsgFilterMax);
1052 }
1053 while ( (STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) ||
1054 STATUS_TIMEOUT == Status );
1055
1056 if (!NT_SUCCESS(Status))
1057 {
1058 SetLastNtError(Status);
1059 DPRINT1("Exit co_IntWaitMessage on error!\n");
1060 }
1061
1062 return FALSE;
1063 }
1064
1065 BOOL FASTCALL
1066 co_IntGetPeekMessage( PMSG pMsg,
1067 HWND hWnd,
1068 UINT MsgFilterMin,
1069 UINT MsgFilterMax,
1070 UINT RemoveMsg,
1071 BOOL bGMSG )
1072 {
1073 BOOL Present;
1074 PWINDOW_OBJECT Window;
1075 USER_MESSAGE Msg;
1076
1077 if ( hWnd == HWND_TOPMOST ||
1078 hWnd == HWND_BROADCAST )
1079 hWnd = HWND_BOTTOM;
1080
1081 /* Validate input */
1082 if (hWnd && hWnd != HWND_BOTTOM)
1083 {
1084 if (!(Window = UserGetWindowObject(hWnd)))
1085 {
1086 if (bGMSG)
1087 return -1;
1088 else
1089 return FALSE;
1090 }
1091 }
1092 else
1093 {
1094 Window = (PWINDOW_OBJECT)hWnd;
1095 }
1096
1097 if (MsgFilterMax < MsgFilterMin)
1098 {
1099 MsgFilterMin = 0;
1100 MsgFilterMax = 0;
1101 }
1102
1103 do
1104 {
1105 Present = co_IntPeekMessage( &Msg,
1106 Window,
1107 MsgFilterMin,
1108 MsgFilterMax,
1109 RemoveMsg );
1110 if (Present)
1111 {
1112 RtlCopyMemory( pMsg, &Msg.Msg, sizeof(MSG));
1113
1114 if (bGMSG)
1115 return (WM_QUIT != pMsg->message);
1116 else
1117 return TRUE;
1118 }
1119
1120 if ( bGMSG && !co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax) )
1121 {
1122 return -1;
1123 }
1124 else
1125 {
1126 if (!(RemoveMsg & PM_NOYIELD))
1127 {
1128 // Yield this thread!
1129 UserLeave();
1130 ZwYieldExecution();
1131 UserEnterExclusive();
1132 // Fall through to fail.
1133 }
1134 }
1135 }
1136 while( bGMSG && !Present );
1137
1138 return FALSE;
1139 }
1140
1141 BOOL FASTCALL
1142 UserPostThreadMessage( DWORD idThread,
1143 UINT Msg,
1144 WPARAM wParam,
1145 LPARAM lParam )
1146 {
1147 MSG Message;
1148 PETHREAD peThread;
1149 PTHREADINFO pThread;
1150 LARGE_INTEGER LargeTickCount;
1151 NTSTATUS Status;
1152
1153 DPRINT1("UserPostThreadMessage wParam 0x%x lParam 0x%x\n", wParam,lParam);
1154
1155 if (FindMsgMemory(Msg) != 0)
1156 {
1157 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
1158 return FALSE;
1159 }
1160
1161 Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
1162
1163 if( Status == STATUS_SUCCESS )
1164 {
1165 pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
1166 if( !pThread ||
1167 !pThread->MessageQueue ||
1168 (pThread->TIF_flags & TIF_INCLEANUP))
1169 {
1170 ObDereferenceObject( peThread );
1171 return FALSE;
1172 }
1173
1174 Message.hwnd = NULL;
1175 Message.message = Msg;
1176 Message.wParam = wParam;
1177 Message.lParam = lParam;
1178 Message.pt = gpsi->ptCursor;
1179
1180 KeQueryTickCount(&LargeTickCount);
1181 pThread->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
1182 MsqPostMessage(pThread->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1183 ObDereferenceObject( peThread );
1184 return TRUE;
1185 }
1186 else
1187 {
1188 SetLastNtError( Status );
1189 }
1190 return FALSE;
1191 }
1192
1193 BOOL FASTCALL
1194 UserPostMessage( HWND Wnd,
1195 UINT Msg,
1196 WPARAM wParam,
1197 LPARAM lParam )
1198 {
1199 PTHREADINFO pti;
1200 MSG Message;
1201 LARGE_INTEGER LargeTickCount;
1202
1203 if (FindMsgMemory(Msg) != 0)
1204 {
1205 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
1206 return FALSE;
1207 }
1208
1209 if (!Wnd)
1210 return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
1211 Msg,
1212 wParam,
1213 lParam);
1214
1215 if (Wnd == HWND_BROADCAST)
1216 {
1217 HWND *List;
1218 PWINDOW_OBJECT DesktopWindow;
1219 ULONG i;
1220
1221 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1222 List = IntWinListChildren(DesktopWindow);
1223
1224 if (List != NULL)
1225 {
1226 for (i = 0; List[i]; i++)
1227 UserPostMessage(List[i], Msg, wParam, lParam);
1228 ExFreePool(List);
1229 }
1230 }
1231 else
1232 {
1233 PWINDOW_OBJECT Window;
1234
1235 Window = UserGetWindowObject(Wnd);
1236 if ( !Window || !Window->Wnd )
1237 {
1238 return FALSE;
1239 }
1240
1241 pti = Window->Wnd->head.pti;
1242 if ( pti->TIF_flags & TIF_INCLEANUP )
1243 {
1244 DPRINT1("Attempted to post message to window 0x%x when the thread is in cleanup!\n", Wnd);
1245 return FALSE;
1246 }
1247
1248 if ( Window->state & WINDOWSTATUS_DESTROYING )
1249 {
1250 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
1251 /* FIXME - last error code? */
1252 return FALSE;
1253 }
1254
1255 if (WM_QUIT == Msg)
1256 {
1257 MsqPostQuitMessage(Window->pti->MessageQueue, wParam);
1258 }
1259 else
1260 {
1261 Message.hwnd = Wnd;
1262 Message.message = Msg;
1263 Message.wParam = wParam;
1264 Message.lParam = lParam;
1265 Message.pt = gpsi->ptCursor;
1266 KeQueryTickCount(&LargeTickCount);
1267 pti->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
1268 MsqPostMessage(Window->pti->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1269 }
1270 }
1271 return TRUE;
1272 }
1273
1274
1275 LRESULT FASTCALL
1276 co_IntSendMessage( HWND hWnd,
1277 UINT Msg,
1278 WPARAM wParam,
1279 LPARAM lParam )
1280 {
1281 ULONG_PTR Result = 0;
1282 if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1283 {
1284 return (LRESULT)Result;
1285 }
1286 return 0;
1287 }
1288
1289 static
1290 LRESULT FASTCALL
1291 co_IntSendMessageTimeoutSingle( HWND hWnd,
1292 UINT Msg,
1293 WPARAM wParam,
1294 LPARAM lParam,
1295 UINT uFlags,
1296 UINT uTimeout,
1297 ULONG_PTR *uResult )
1298 {
1299 ULONG_PTR Result;
1300 NTSTATUS Status;
1301 PWINDOW_OBJECT Window = NULL;
1302 PMSGMEMORY MsgMemoryEntry;
1303 INT lParamBufferSize;
1304 LPARAM lParamPacked;
1305 PTHREADINFO Win32Thread;
1306 DECLARE_RETURN(LRESULT);
1307 USER_REFERENCE_ENTRY Ref;
1308
1309 if (!(Window = UserGetWindowObject(hWnd)))
1310 {
1311 RETURN( FALSE);
1312 }
1313
1314 UserRefObjectCo(Window, &Ref);
1315
1316 Win32Thread = PsGetCurrentThreadWin32Thread();
1317
1318 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1319
1320 if ( NULL != Win32Thread &&
1321 Window->pti->MessageQueue == Win32Thread->MessageQueue)
1322 {
1323 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1324 {
1325 /* Never send messages to exiting threads */
1326 RETURN( FALSE);
1327 }
1328
1329 /* See if this message type is present in the table */
1330 MsgMemoryEntry = FindMsgMemory(Msg);
1331 if (NULL == MsgMemoryEntry)
1332 {
1333 lParamBufferSize = -1;
1334 }
1335 else
1336 {
1337 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1338 }
1339
1340 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam)))
1341 {
1342 DPRINT1("Failed to pack message parameters\n");
1343 RETURN( FALSE);
1344 }
1345
1346 Result = (ULONG_PTR)co_IntCallWindowProc( Window->Wnd->lpfnWndProc,
1347 !Window->Wnd->Unicode,
1348 hWnd,
1349 Msg,
1350 wParam,
1351 lParamPacked,
1352 lParamBufferSize );
1353 if(uResult)
1354 {
1355 *uResult = Result;
1356 }
1357
1358 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1359
1360 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam)))
1361 {
1362 DPRINT1("Failed to unpack message parameters\n");
1363 RETURN( TRUE);
1364 }
1365
1366 RETURN( TRUE);
1367 }
1368
1369 if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->pti->MessageQueue))
1370 {
1371 /* FIXME - Set a LastError? */
1372 RETURN( FALSE);
1373 }
1374
1375 if (Window->state & WINDOWSTATUS_DESTROYING)
1376 {
1377 /* FIXME - last error? */
1378 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1379 RETURN( FALSE);
1380 }
1381
1382 do
1383 {
1384 Status = co_MsqSendMessage( Window->pti->MessageQueue,
1385 hWnd,
1386 Msg,
1387 wParam,
1388 lParam,
1389 uTimeout,
1390 (uFlags & SMTO_BLOCK),
1391 MSQ_NORMAL,
1392 uResult );
1393 }
1394 while ((STATUS_TIMEOUT == Status) &&
1395 (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
1396 !MsqIsHung(Window->pti->MessageQueue));
1397
1398 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1399
1400 if (STATUS_TIMEOUT == Status)
1401 {
1402 /*
1403 MSDN says:
1404 Microsoft Windows 2000: If GetLastError returns zero, then the function
1405 timed out.
1406 XP+ : If the function fails or times out, the return value is zero.
1407 To get extended error information, call GetLastError. If GetLastError
1408 returns ERROR_TIMEOUT, then the function timed out.
1409 */
1410 SetLastWin32Error(ERROR_TIMEOUT);
1411 RETURN( FALSE);
1412 }
1413 else if (! NT_SUCCESS(Status))
1414 {
1415 SetLastNtError(Status);
1416 RETURN( FALSE);
1417 }
1418
1419 RETURN( TRUE);
1420
1421 CLEANUP:
1422 if (Window) UserDerefObjectCo(Window);
1423 END_CLEANUP;
1424 }
1425
1426 LRESULT FASTCALL
1427 co_IntSendMessageTimeout( HWND hWnd,
1428 UINT Msg,
1429 WPARAM wParam,
1430 LPARAM lParam,
1431 UINT uFlags,
1432 UINT uTimeout,
1433 ULONG_PTR *uResult )
1434 {
1435 PWINDOW_OBJECT DesktopWindow;
1436 HWND *Children;
1437 HWND *Child;
1438
1439 if (HWND_BROADCAST != hWnd)
1440 {
1441 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1442 }
1443
1444 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1445 if (NULL == DesktopWindow)
1446 {
1447 SetLastWin32Error(ERROR_INTERNAL_ERROR);
1448 return 0;
1449 }
1450
1451 Children = IntWinListChildren(DesktopWindow);
1452 if (NULL == Children)
1453 {
1454 return 0;
1455 }
1456
1457 for (Child = Children; NULL != *Child; Child++)
1458 {
1459 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1460 }
1461
1462 ExFreePool(Children);
1463
1464 return (LRESULT) TRUE;
1465 }
1466
1467
1468 /* This function posts a message if the destination's message queue belongs to
1469 another thread, otherwise it sends the message. It does not support broadcast
1470 messages! */
1471 LRESULT FASTCALL
1472 co_IntPostOrSendMessage( HWND hWnd,
1473 UINT Msg,
1474 WPARAM wParam,
1475 LPARAM lParam )
1476 {
1477 ULONG_PTR Result;
1478 PTHREADINFO pti;
1479 PWINDOW_OBJECT Window;
1480
1481 if ( hWnd == HWND_BROADCAST )
1482 {
1483 return 0;
1484 }
1485
1486 if(!(Window = UserGetWindowObject(hWnd)))
1487 {
1488 return 0;
1489 }
1490
1491 pti = PsGetCurrentThreadWin32Thread();
1492
1493 if ( Window->pti->MessageQueue != pti->MessageQueue &&
1494 FindMsgMemory(Msg) == 0 )
1495 {
1496 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1497 }
1498 else
1499 {
1500 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
1501 {
1502 Result = 0;
1503 }
1504 }
1505
1506 return (LRESULT)Result;
1507 }
1508
1509 LRESULT FASTCALL
1510 co_IntDoSendMessage( HWND hWnd,
1511 UINT Msg,
1512 WPARAM wParam,
1513 LPARAM lParam,
1514 PDOSENDMESSAGE dsm,
1515 PNTUSERSENDMESSAGEINFO UnsafeInfo )
1516 {
1517 PTHREADINFO pti;
1518 LRESULT Result = TRUE;
1519 NTSTATUS Status;
1520 PWINDOW_OBJECT Window = NULL;
1521 NTUSERSENDMESSAGEINFO Info;
1522 MSG UserModeMsg;
1523 MSG KernelModeMsg;
1524 PMSGMEMORY MsgMemoryEntry;
1525
1526 RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));
1527
1528 /* FIXME: Call hooks. */
1529 if (HWND_BROADCAST != hWnd)
1530 {
1531 Window = UserGetWindowObject(hWnd);
1532 if ( !Window || !Window->Wnd )
1533 {
1534 /* Tell usermode to not touch this one */
1535 Info.HandledByKernel = TRUE;
1536 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1537 return 0;
1538 }
1539 }
1540
1541 /* Check for an exiting window. */
1542 if (Window && Window->state & WINDOWSTATUS_DESTROYING)
1543 {
1544 DPRINT1("co_IntDoSendMessage Window Exiting!\n");
1545 }
1546
1547 /* See if the current thread can handle the message */
1548 pti = PsGetCurrentThreadWin32Thread();
1549
1550 // This is checked in user mode!!!!!!!
1551 if ( HWND_BROADCAST != hWnd &&
1552 NULL != pti &&
1553 Window->pti->MessageQueue == pti->MessageQueue &&
1554 !ISITHOOKED(WH_CALLWNDPROC) &&
1555 !ISITHOOKED(WH_CALLWNDPROCRET) &&
1556 ( Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST ) )
1557 {
1558 /* Gather the information usermode needs to call the window proc directly */
1559 Info.HandledByKernel = FALSE;
1560
1561 Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi),
1562 sizeof(BOOL));
1563 if (! NT_SUCCESS(Status))
1564 {
1565 Info.Ansi = ! Window->Wnd->Unicode;
1566 }
1567
1568 Info.Ansi = !Window->Wnd->Unicode;
1569 Info.Proc = Window->Wnd->lpfnWndProc;
1570 }
1571 else
1572 {
1573 /* Must be handled by other thread */
1574 // if (HWND_BROADCAST != hWnd)
1575 // {
1576 // UserDereferenceObject(Window);
1577 // }
1578 Info.HandledByKernel = TRUE;
1579 UserModeMsg.hwnd = hWnd;
1580 UserModeMsg.message = Msg;
1581 UserModeMsg.wParam = wParam;
1582 UserModeMsg.lParam = lParam;
1583 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1584
1585 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1586 if (! NT_SUCCESS(Status))
1587 {
1588 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1589 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1590 return (dsm ? 0 : -1);
1591 }
1592
1593 if(!dsm)
1594 {
1595 Result = co_IntSendMessage( KernelModeMsg.hwnd,
1596 KernelModeMsg.message,
1597 KernelModeMsg.wParam,
1598 KernelModeMsg.lParam );
1599 }
1600 else
1601 {
1602 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1603 KernelModeMsg.message,
1604 KernelModeMsg.wParam,
1605 KernelModeMsg.lParam,
1606 dsm->uFlags,
1607 dsm->uTimeout,
1608 &dsm->Result );
1609 }
1610
1611 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1612 if (! NT_SUCCESS(Status))
1613 {
1614 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1615 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1616 return(dsm ? 0 : -1);
1617 }
1618 }
1619
1620 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1621 if (! NT_SUCCESS(Status))
1622 {
1623 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1624 }
1625
1626 return (LRESULT)Result;
1627 }
1628
1629
1630 BOOL FASTCALL
1631 UserSendNotifyMessage( HWND hWnd,
1632 UINT Msg,
1633 WPARAM wParam,
1634 LPARAM lParam )
1635 {
1636 BOOL Result = TRUE;
1637
1638 if (FindMsgMemory(Msg) != 0)
1639 {
1640 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
1641 return FALSE;
1642 }
1643
1644 // Basicly the same as IntPostOrSendMessage
1645 if (hWnd == HWND_BROADCAST) //Handle Broadcast
1646 {
1647 HWND *List;
1648 PWINDOW_OBJECT DesktopWindow;
1649 ULONG i;
1650
1651 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1652 List = IntWinListChildren(DesktopWindow);
1653
1654 if (List != NULL)
1655 {
1656 for (i = 0; List[i]; i++)
1657 {
1658 UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1659 }
1660 ExFreePool(List);
1661 }
1662 }
1663 else
1664 {
1665 ULONG_PTR PResult;
1666 PTHREADINFO pti;
1667 PWINDOW_OBJECT Window;
1668 MSG Message;
1669
1670 if ( !(Window = UserGetWindowObject(hWnd)) ) return FALSE;
1671
1672 pti = PsGetCurrentThreadWin32Thread();
1673
1674 if (Window->pti->MessageQueue != pti->MessageQueue)
1675 { // Send message w/o waiting for it.
1676 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1677 }
1678 else
1679 { // Handle message and callback.
1680 Message.hwnd = hWnd;
1681 Message.message = Msg;
1682 Message.wParam = wParam;
1683 Message.lParam = lParam;
1684
1685 Result = co_IntSendMessageTimeoutSingle( hWnd,
1686 Msg,
1687 wParam,
1688 lParam,
1689 SMTO_NORMAL,
1690 0,
1691 &PResult );
1692 }
1693 }
1694 return Result;
1695 }
1696
1697
1698 DWORD APIENTRY
1699 IntGetQueueStatus(BOOL ClearChanges)
1700 {
1701 PTHREADINFO pti;
1702 PUSER_MESSAGE_QUEUE Queue;
1703 DWORD Result;
1704 DECLARE_RETURN(DWORD);
1705
1706 DPRINT("Enter IntGetQueueStatus\n");
1707
1708 pti = PsGetCurrentThreadWin32Thread();
1709 Queue = pti->MessageQueue;
1710
1711 Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
1712 if (ClearChanges)
1713 {
1714 Queue->ChangedBits = 0;
1715 }
1716
1717 RETURN(Result);
1718
1719 CLEANUP:
1720 DPRINT("Leave IntGetQueueStatus, ret=%i\n",_ret_);
1721 END_CLEANUP;
1722 }
1723
1724 BOOL APIENTRY
1725 IntInitMessagePumpHook()
1726 {
1727 if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti)
1728 {
1729 ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook++;
1730 return TRUE;
1731 }
1732 return FALSE;
1733 }
1734
1735 BOOL APIENTRY
1736 IntUninitMessagePumpHook()
1737 {
1738 if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti)
1739 {
1740 if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook <= 0)
1741 {
1742 return FALSE;
1743 }
1744 ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook--;
1745 return TRUE;
1746 }
1747 return FALSE;
1748 }
1749
1750 /** Functions ******************************************************************/
1751
1752 BOOL APIENTRY
1753 NtUserPostMessage(HWND hWnd,
1754 UINT Msg,
1755 WPARAM wParam,
1756 LPARAM lParam)
1757 {
1758 DECLARE_RETURN(BOOL);
1759
1760 DPRINT("Enter NtUserPostMessage\n");
1761 UserEnterExclusive();
1762
1763 RETURN( UserPostMessage(hWnd, Msg, wParam, lParam));
1764
1765 CLEANUP:
1766 DPRINT("Leave NtUserPostMessage, ret=%i\n",_ret_);
1767 UserLeave();
1768 END_CLEANUP;
1769 }
1770
1771 BOOL APIENTRY
1772 NtUserPostThreadMessage(DWORD idThread,
1773 UINT Msg,
1774 WPARAM wParam,
1775 LPARAM lParam)
1776 {
1777 DECLARE_RETURN(BOOL);
1778
1779 DPRINT("Enter NtUserPostThreadMessage\n");
1780 UserEnterExclusive();
1781
1782 RETURN( UserPostThreadMessage( idThread,
1783 Msg,
1784 wParam,
1785 lParam));
1786
1787 CLEANUP:
1788 DPRINT("Leave NtUserPostThreadMessage, ret=%i\n",_ret_);
1789 UserLeave();
1790 END_CLEANUP;
1791 }
1792
1793 DWORD APIENTRY
1794 NtUserQuerySendMessage(DWORD Unknown0)
1795 {
1796 UNIMPLEMENTED;
1797
1798 return 0;
1799 }
1800
1801
1802 ////////// API on the way out!
1803 LRESULT APIENTRY
1804 NtUserSendMessageTimeout( HWND hWnd,
1805 UINT Msg,
1806 WPARAM wParam,
1807 LPARAM lParam,
1808 UINT uFlags,
1809 UINT uTimeout,
1810 ULONG_PTR *uResult,
1811 PNTUSERSENDMESSAGEINFO UnsafeInfo )
1812 {
1813 DOSENDMESSAGE dsm;
1814 LRESULT Result;
1815 DECLARE_RETURN(BOOL);
1816
1817 DPRINT("Enter NtUserSendMessageTimeout\n");
1818 UserEnterExclusive();
1819
1820 dsm.uFlags = uFlags;
1821 dsm.uTimeout = uTimeout;
1822 Result = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
1823 if(uResult != NULL && Result != 0)
1824 {
1825 NTSTATUS Status;
1826
1827 Status = MmCopyToCaller(uResult, &dsm.Result, sizeof(ULONG_PTR));
1828 if(!NT_SUCCESS(Status))
1829 {
1830 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1831 RETURN( FALSE);
1832 }
1833 }
1834 RETURN( Result);
1835
1836 CLEANUP:
1837 DPRINT("Leave NtUserSendMessageTimeout, ret=%i\n",_ret_);
1838 UserLeave();
1839 END_CLEANUP;
1840 }
1841
1842 LRESULT APIENTRY
1843 NtUserSendMessage( HWND Wnd,
1844 UINT Msg,
1845 WPARAM wParam,
1846 LPARAM lParam,
1847 PNTUSERSENDMESSAGEINFO UnsafeInfo )
1848 {
1849 DECLARE_RETURN(BOOL);
1850
1851 DPRINT("Enter NtUserSendMessage\n");
1852 UserEnterExclusive();
1853
1854 RETURN(co_IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo));
1855
1856 CLEANUP:
1857 DPRINT("Leave NtUserSendMessage, ret=%i\n",_ret_);
1858 UserLeave();
1859 END_CLEANUP;
1860 }
1861 //////////
1862
1863 BOOL APIENTRY
1864 NtUserWaitMessage(VOID)
1865 {
1866 DECLARE_RETURN(BOOL);
1867
1868 DPRINT("EnterNtUserWaitMessage\n");
1869 UserEnterExclusive();
1870
1871 RETURN(co_IntWaitMessage(NULL, 0, 0));
1872
1873 CLEANUP:
1874 DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_);
1875 UserLeave();
1876 END_CLEANUP;
1877 }
1878
1879
1880 BOOL APIENTRY
1881 NtUserGetMessage( PNTUSERGETMESSAGEINFO UnsafeInfo,
1882 HWND hWnd,
1883 UINT MsgFilterMin,
1884 UINT MsgFilterMax )
1885 /*
1886 * FUNCTION: Get a message from the calling thread's message queue.
1887 * ARGUMENTS:
1888 * UnsafeMsg - Pointer to the structure which receives the returned message.
1889 * Wnd - Window whose messages are to be retrieved.
1890 * MsgFilterMin - Integer value of the lowest message value to be
1891 * retrieved.
1892 * MsgFilterMax - Integer value of the highest message value to be
1893 * retrieved.
1894 */
1895 {
1896 BOOL GotMessage;
1897 NTUSERGETMESSAGEINFO Info;
1898 NTSTATUS Status;
1899 /* FIXME: if initialization is removed, gcc complains that this may be used before initialization. Please review */
1900 PWINDOW_OBJECT Window = NULL;
1901 PMSGMEMORY MsgMemoryEntry;
1902 PVOID UserMem;
1903 UINT Size;
1904 USER_MESSAGE Msg;
1905 DECLARE_RETURN(BOOL);
1906 // USER_REFERENCE_ENTRY Ref;
1907
1908 DPRINT("Enter NtUserGetMessage\n");
1909 UserEnterExclusive();
1910
1911 /* Validate input */
1912 if (hWnd && !(Window = UserGetWindowObject(hWnd)))
1913 {
1914 RETURN(-1);
1915 }
1916
1917 // if (Window) UserRefObjectCo(Window, &Ref);
1918
1919 if (MsgFilterMax < MsgFilterMin)
1920 {
1921 MsgFilterMin = 0;
1922 MsgFilterMax = 0;
1923 }
1924
1925 do
1926 {
1927 GotMessage = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, PM_REMOVE);
1928 if (GotMessage)
1929 {
1930 Info.Msg = Msg.Msg;
1931 /* See if this message type is present in the table */
1932 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
1933 if (NULL == MsgMemoryEntry)
1934 {
1935 /* Not present, no copying needed */
1936 Info.LParamSize = 0;
1937 }
1938 else
1939 {
1940 /* Determine required size */
1941 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
1942 Info.Msg.lParam);
1943 /* Allocate required amount of user-mode memory */
1944 Info.LParamSize = Size;
1945 UserMem = NULL;
1946 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
1947 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
1948
1949 if (! NT_SUCCESS(Status))
1950 {
1951 SetLastNtError(Status);
1952 RETURN( (BOOL) -1);
1953 }
1954 /* Transfer lParam data to user-mode mem */
1955 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
1956 if (! NT_SUCCESS(Status))
1957 {
1958 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
1959 &Info.LParamSize, MEM_DECOMMIT);
1960 SetLastNtError(Status);
1961 RETURN( (BOOL) -1);
1962 }
1963 Info.Msg.lParam = (LPARAM) UserMem;
1964 }
1965 if (Msg.FreeLParam && 0 != Msg.Msg.lParam)
1966 {
1967 ExFreePool((void *) Msg.Msg.lParam);
1968 }
1969 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
1970 if (! NT_SUCCESS(Status))
1971 {
1972 SetLastNtError(Status);
1973 RETURN( (BOOL) -1);
1974 }
1975 }
1976 else if (! co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax))
1977 {
1978 RETURN( (BOOL) -1);
1979 }
1980 }
1981 while (! GotMessage);
1982
1983 RETURN( WM_QUIT != Info.Msg.message);
1984
1985 CLEANUP:
1986 // if (Window) UserDerefObjectCo(Window);
1987
1988 DPRINT("Leave NtUserGetMessage\n");
1989 UserLeave();
1990 END_CLEANUP;
1991 }
1992
1993
1994 BOOL
1995 APIENTRY
1996 NtUserGetMessageX(
1997 PMSG pMsg,
1998 HWND hWnd,
1999 UINT MsgFilterMin,
2000 UINT MsgFilterMax)
2001 {
2002 MSG Msg;
2003 BOOL Ret = FALSE;
2004 DECLARE_RETURN(BOOL);
2005
2006 DPRINT("Enter NtUserGetMessage\n");
2007 UserEnterExclusive();
2008
2009 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
2010 {
2011 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2012 RETURN( Ret);
2013 }
2014
2015 RtlZeroMemory(&Msg, sizeof(MSG));
2016
2017 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
2018
2019 if (Ret)
2020 {
2021 _SEH2_TRY
2022 {
2023 ProbeForWrite(pMsg, sizeof(MSG), 1);
2024 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
2025 }
2026 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2027 {
2028 SetLastNtError(_SEH2_GetExceptionCode());
2029 Ret = FALSE;
2030 }
2031 _SEH2_END;
2032 }
2033 RETURN( Ret);
2034
2035 CLEANUP:
2036 DPRINT("Leave NtUserGetMessage\n");
2037 UserLeave();
2038 END_CLEANUP;
2039 }
2040
2041 BOOL APIENTRY
2042 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
2043 HWND hWnd,
2044 UINT MsgFilterMin,
2045 UINT MsgFilterMax,
2046 UINT RemoveMsg)
2047 {
2048 NTSTATUS Status;
2049 BOOL Present;
2050 NTUSERGETMESSAGEINFO Info;
2051 PWINDOW_OBJECT Window;
2052 PMSGMEMORY MsgMemoryEntry;
2053 PVOID UserMem;
2054 UINT Size;
2055 USER_MESSAGE Msg;
2056 DECLARE_RETURN(BOOL);
2057
2058 DPRINT("Enter NtUserPeekMessage\n");
2059 UserEnterExclusive();
2060
2061 if (hWnd == (HWND)-1 || hWnd == (HWND)0x0000FFFF || hWnd == (HWND)0xFFFFFFFF)
2062 hWnd = (HWND)1;
2063
2064 /* Validate input */
2065 if (hWnd && hWnd != (HWND)1)
2066 {
2067 if (!(Window = UserGetWindowObject(hWnd)))
2068 {
2069 RETURN(-1);
2070 }
2071 }
2072 else
2073 {
2074 Window = (PWINDOW_OBJECT)hWnd;
2075 }
2076
2077 if (MsgFilterMax < MsgFilterMin)
2078 {
2079 MsgFilterMin = 0;
2080 MsgFilterMax = 0;
2081 }
2082
2083 Present = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, RemoveMsg);
2084 if (Present)
2085 {
2086
2087 Info.Msg = Msg.Msg;
2088 /* See if this message type is present in the table */
2089 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
2090 if (NULL == MsgMemoryEntry)
2091 {
2092 /* Not present, no copying needed */
2093 Info.LParamSize = 0;
2094 }
2095 else
2096 {
2097 /* Determine required size */
2098 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
2099 Info.Msg.lParam);
2100 /* Allocate required amount of user-mode memory */
2101 Info.LParamSize = Size;
2102 UserMem = NULL;
2103 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
2104 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
2105 if (! NT_SUCCESS(Status))
2106 {
2107 SetLastNtError(Status);
2108 RETURN( (BOOL) -1);
2109 }
2110 /* Transfer lParam data to user-mode mem */
2111 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
2112 if (! NT_SUCCESS(Status))
2113 {
2114 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
2115 &Info.LParamSize, MEM_RELEASE);
2116 SetLastNtError(Status);
2117 RETURN( (BOOL) -1);
2118 }
2119 Info.Msg.lParam = (LPARAM) UserMem;
2120 }
2121 if (RemoveMsg && Msg.FreeLParam && 0 != Msg.Msg.lParam)
2122 {
2123 ExFreePool((void *) Msg.Msg.lParam);
2124 }
2125 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
2126 if (! NT_SUCCESS(Status))
2127 {
2128 SetLastNtError(Status);
2129 RETURN( (BOOL) -1);
2130 }
2131 }
2132
2133 RETURN( Present);
2134
2135 CLEANUP:
2136 DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_);
2137 UserLeave();
2138 END_CLEANUP;
2139 }
2140
2141 BOOL
2142 APIENTRY
2143 NtUserPeekMessageX(
2144 PMSG pMsg,
2145 HWND hWnd,
2146 UINT MsgFilterMin,
2147 UINT MsgFilterMax,
2148 UINT RemoveMsg)
2149 {
2150 MSG Msg;
2151 BOOL Ret = FALSE;
2152 DECLARE_RETURN(BOOL);
2153
2154 DPRINT("Enter NtUserPeekMessage\n");
2155 UserEnterExclusive();
2156
2157 if ( RemoveMsg & PM_BADMSGFLAGS )
2158 {
2159 SetLastWin32Error(ERROR_INVALID_FLAGS);
2160 RETURN( Ret);
2161 }
2162
2163 RtlZeroMemory(&Msg, sizeof(MSG));
2164
2165 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
2166
2167 if (Ret)
2168 {
2169 _SEH2_TRY
2170 {
2171 ProbeForWrite(pMsg, sizeof(MSG), 1);
2172 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
2173 }
2174 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2175 {
2176 SetLastNtError(_SEH2_GetExceptionCode());
2177 Ret = FALSE;
2178 }
2179 _SEH2_END;
2180 }
2181 RETURN( Ret);
2182
2183 CLEANUP:
2184 DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_);
2185 UserLeave();
2186 END_CLEANUP;
2187 }
2188
2189 BOOL
2190 APIENTRY
2191 NtUserCallMsgFilter(
2192 LPMSG lpmsg,
2193 INT code)
2194 {
2195 BOOL BadChk = FALSE, Ret = FALSE;
2196 MSG Msg;
2197 DECLARE_RETURN(BOOL);
2198
2199 DPRINT("Enter NtUserCallMsgFilter\n");
2200 UserEnterExclusive();
2201 if (lpmsg)
2202 {
2203 _SEH2_TRY
2204 {
2205 ProbeForRead((PVOID)lpmsg,
2206 sizeof(MSG),
2207 1);
2208 RtlCopyMemory( &Msg,
2209 (PVOID)lpmsg,
2210 sizeof(MSG));
2211 }
2212 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2213 {
2214 BadChk = TRUE;
2215 }
2216 _SEH2_END;
2217 }
2218 else
2219 RETURN( FALSE);
2220
2221 if (BadChk) RETURN( FALSE);
2222
2223 if ( ISITHOOKED(WH_SYSMSGFILTER) &&
2224 co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
2225 {
2226 Ret = TRUE;
2227 }
2228 else
2229 {
2230 if ( ISITHOOKED(WH_MSGFILTER) )
2231 {
2232 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
2233 }
2234 }
2235
2236 _SEH2_TRY
2237 {
2238 ProbeForWrite((PVOID)lpmsg,
2239 sizeof(MSG),
2240 1);
2241 RtlCopyMemory((PVOID)lpmsg,
2242 &Msg,
2243 sizeof(MSG));
2244 }
2245 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2246 {
2247 BadChk = TRUE;
2248 }
2249 _SEH2_END;
2250 if (BadChk) RETURN( FALSE);
2251 RETURN( Ret)
2252
2253 CLEANUP:
2254 DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_);
2255 UserLeave();
2256 END_CLEANUP;
2257 }
2258
2259 LRESULT APIENTRY
2260 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
2261 {
2262 LRESULT Res = 0;
2263 BOOL Hit = FALSE;
2264 MSG SafeMsg;
2265
2266 UserEnterExclusive();
2267 _SEH2_TRY
2268 {
2269 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
2270 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
2271 }
2272 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2273 {
2274 SetLastNtError(_SEH2_GetExceptionCode());
2275 Hit = TRUE;
2276 }
2277 _SEH2_END;
2278
2279 if (!Hit) Res = IntDispatchMessage(&SafeMsg);
2280
2281 UserLeave();
2282 return Res;
2283 }
2284
2285
2286 BOOL APIENTRY
2287 NtUserTranslateMessage(LPMSG lpMsg,
2288 HKL dwhkl)
2289 {
2290 NTSTATUS Status;
2291 MSG SafeMsg;
2292 DECLARE_RETURN(BOOL);
2293
2294 DPRINT("Enter NtUserTranslateMessage\n");
2295 UserEnterExclusive();
2296
2297 Status = MmCopyFromCaller(&SafeMsg, lpMsg, sizeof(MSG));
2298 if(!NT_SUCCESS(Status))
2299 {
2300 SetLastNtError(Status);
2301 RETURN( FALSE);
2302 }
2303
2304 RETURN( IntTranslateKbdMessage(&SafeMsg, dwhkl));
2305
2306 CLEANUP:
2307 DPRINT("Leave NtUserTranslateMessage: ret=%i\n",_ret_);
2308 UserLeave();
2309 END_CLEANUP;
2310 }
2311
2312 BOOL APIENTRY
2313 NtUserMessageCall(
2314 HWND hWnd,
2315 UINT Msg,
2316 WPARAM wParam,
2317 LPARAM lParam,
2318 ULONG_PTR ResultInfo,
2319 DWORD dwType, // fnID?
2320 BOOL Ansi)
2321 {
2322 LRESULT lResult = 0;
2323 BOOL Ret = FALSE;
2324 BOOL BadChk = FALSE;
2325 PWINDOW_OBJECT Window = NULL;
2326 USER_REFERENCE_ENTRY Ref;
2327
2328 UserEnterExclusive();
2329
2330 /* Validate input */
2331 if (hWnd && (hWnd != INVALID_HANDLE_VALUE) && !(Window = UserGetWindowObject(hWnd)))
2332 {
2333 UserLeave();
2334 return FALSE;
2335 }
2336 switch(dwType)
2337 {
2338 case FNID_DEFWINDOWPROC:
2339 UserRefObjectCo(Window, &Ref);
2340 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2341 Ret = TRUE;
2342 UserDerefObjectCo(Window);
2343 break;
2344 case FNID_SENDNOTIFYMESSAGE:
2345 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
2346 break;
2347 case FNID_BROADCASTSYSTEMMESSAGE:
2348 {
2349 BROADCASTPARM parm;
2350 DWORD_PTR RetVal = 0;
2351
2352 if (ResultInfo)
2353 {
2354 _SEH2_TRY
2355 {
2356 ProbeForWrite((PVOID)ResultInfo,
2357 sizeof(BROADCASTPARM),
2358 1);
2359 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
2360 }
2361 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2362 {
2363 BadChk = TRUE;
2364 }
2365 _SEH2_END;
2366 if (BadChk) break;
2367 }
2368 else
2369 break;
2370
2371 if ( parm.recipients & BSM_ALLDESKTOPS ||
2372 parm.recipients == BSM_ALLCOMPONENTS )
2373 {
2374 }
2375 else if (parm.recipients & BSM_APPLICATIONS)
2376 {
2377 if (parm.flags & BSF_QUERY)
2378 {
2379 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2380 {
2381 co_IntSendMessageTimeout( HWND_BROADCAST,
2382 Msg,
2383 wParam,
2384 lParam,
2385 SMTO_ABORTIFHUNG,
2386 2000,
2387 &RetVal);
2388 }
2389 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2390 {
2391 co_IntSendMessageTimeout( HWND_BROADCAST,
2392 Msg,
2393 wParam,
2394 lParam,
2395 SMTO_NOTIMEOUTIFNOTHUNG,
2396 2000,
2397 &RetVal);
2398 }
2399 else
2400 {
2401 co_IntSendMessageTimeout( HWND_BROADCAST,
2402 Msg,
2403 wParam,
2404 lParam,
2405 SMTO_NORMAL,
2406 2000,
2407 &RetVal);
2408 }
2409 }
2410 else if (parm.flags & BSF_POSTMESSAGE)
2411 {
2412 Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
2413 }
2414 else if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
2415 {
2416 Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
2417 }
2418 }
2419 }
2420 break;
2421 case FNID_SENDMESSAGECALLBACK:
2422 break;
2423 // CallNextHook bypass.
2424 case FNID_CALLWNDPROC:
2425 case FNID_CALLWNDPROCRET:
2426 {
2427 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
2428 PHOOK NextObj, Hook = ClientInfo->phkCurrent;
2429
2430 if (!ClientInfo || !Hook) break;
2431
2432 UserReferenceObject(Hook);
2433
2434 if (Hook->Thread && (Hook->Thread != PsGetCurrentThread()))
2435 {
2436 UserDereferenceObject(Hook);
2437 break;
2438 }
2439
2440 NextObj = IntGetNextHook(Hook);
2441 ClientInfo->phkCurrent = NextObj;
2442
2443 if ( Hook->HookId == WH_CALLWNDPROC)
2444 {
2445 CWPSTRUCT CWP;
2446 CWP.hwnd = hWnd;
2447 CWP.message = Msg;
2448 CWP.wParam = wParam;
2449 CWP.lParam = lParam;
2450 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
2451
2452 lResult = co_IntCallHookProc( Hook->HookId,
2453 HC_ACTION,
2454 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2455 (LPARAM)&CWP,
2456 Hook->Proc,
2457 Hook->Ansi,
2458 &Hook->ModuleName);
2459 }
2460 else
2461 {
2462 CWPRETSTRUCT CWPR;
2463 CWPR.hwnd = hWnd;
2464 CWPR.message = Msg;
2465 CWPR.wParam = wParam;
2466 CWPR.lParam = lParam;
2467 CWPR.lResult = ClientInfo->dwHookData;
2468
2469 lResult = co_IntCallHookProc( Hook->HookId,
2470 HC_ACTION,
2471 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2472 (LPARAM)&CWPR,
2473 Hook->Proc,
2474 Hook->Ansi,
2475 &Hook->ModuleName);
2476 }
2477 UserDereferenceObject(Hook);
2478 lResult = (LRESULT) NextObj;
2479 }
2480 break;
2481 }
2482
2483 switch(dwType)
2484 {
2485 case FNID_DEFWINDOWPROC:
2486 case FNID_CALLWNDPROC:
2487 case FNID_CALLWNDPROCRET:
2488 if (ResultInfo)
2489 {
2490 _SEH2_TRY
2491 {
2492 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2493 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2494 }
2495 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2496 {
2497 BadChk = TRUE;
2498 }
2499 _SEH2_END;
2500 }
2501 break;
2502 default:
2503 break;
2504 }
2505
2506 UserLeave();
2507
2508 return BadChk ? FALSE : Ret;
2509 }
2510
2511 #define INFINITE 0xFFFFFFFF
2512 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2513
2514 DWORD
2515 APIENTRY
2516 NtUserWaitForInputIdle(
2517 IN HANDLE hProcess,
2518 IN DWORD dwMilliseconds,
2519 IN BOOL Unknown2)
2520 {
2521 PEPROCESS Process;
2522 PPROCESSINFO W32Process;
2523 NTSTATUS Status;
2524 HANDLE Handles[2];
2525 LARGE_INTEGER Timeout;
2526 ULONGLONG StartTime, Run, Elapsed = 0;
2527
2528 UserEnterExclusive();
2529
2530 Status = ObReferenceObjectByHandle(hProcess,
2531 PROCESS_QUERY_INFORMATION,
2532 PsProcessType,
2533 UserMode,
2534 (PVOID*)&Process,
2535 NULL);
2536
2537 if (!NT_SUCCESS(Status))
2538 {
2539 UserLeave();
2540 SetLastNtError(Status);
2541 return WAIT_FAILED;
2542 }
2543
2544 W32Process = (PPROCESSINFO)Process->Win32Process;
2545 if (!W32Process)
2546 {
2547 ObDereferenceObject(Process);
2548 UserLeave();
2549 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2550 return WAIT_FAILED;
2551 }
2552
2553 EngCreateEvent((PEVENT *)&W32Process->InputIdleEvent);
2554
2555 Handles[0] = Process;
2556 Handles[1] = W32Process->InputIdleEvent;
2557
2558 if (!Handles[1])
2559 {
2560 ObDereferenceObject(Process);
2561 UserLeave();
2562 return STATUS_SUCCESS; /* no event to wait on */
2563 }
2564
2565 StartTime = EngGetTickCount();
2566
2567 Run = dwMilliseconds;
2568
2569 DPRINT("WFII: waiting for %p\n", Handles[1] );
2570 do
2571 {
2572 Timeout.QuadPart = Run - Elapsed;
2573 UserLeave();
2574 Status = KeWaitForMultipleObjects( 2,
2575 Handles,
2576 WaitAny,
2577 UserRequest,
2578 UserMode,
2579 FALSE,
2580 dwMilliseconds == INFINITE ? NULL : &Timeout,
2581 NULL);
2582 UserEnterExclusive();
2583
2584 if (!NT_SUCCESS(Status))
2585 {
2586 SetLastNtError(Status);
2587 Status = WAIT_FAILED;
2588 goto WaitExit;
2589 }
2590
2591 switch (Status)
2592 {
2593 case STATUS_WAIT_0:
2594 Status = WAIT_FAILED;
2595 goto WaitExit;
2596
2597 case STATUS_WAIT_2:
2598 {
2599 USER_MESSAGE Msg;
2600 co_IntPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE );
2601 break;
2602 }
2603
2604 case STATUS_USER_APC:
2605 case STATUS_ALERTED:
2606 case STATUS_TIMEOUT:
2607 DPRINT1("WFII: timeout\n");
2608 Status = STATUS_TIMEOUT;
2609 goto WaitExit;
2610
2611 default:
2612 DPRINT1("WFII: finished\n");
2613 Status = STATUS_SUCCESS;
2614 goto WaitExit;
2615 }
2616
2617 if (dwMilliseconds != INFINITE)
2618 {
2619 Elapsed = EngGetTickCount() - StartTime;
2620
2621 if (Elapsed > Run)
2622 Status = STATUS_TIMEOUT;
2623 break;
2624 }
2625 }
2626 while (1);
2627
2628 WaitExit:
2629 if (W32Process->InputIdleEvent)
2630 {
2631 EngFreeMem((PVOID)W32Process->InputIdleEvent);
2632 W32Process->InputIdleEvent = NULL;
2633 }
2634 ObDereferenceObject(Process);
2635 UserLeave();
2636 return Status;
2637 }
2638
2639 /* EOF */