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