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