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