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