[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 (MsqPeekMessage( ThreadQueue,
936 RemoveMessages,
937 Window,
938 MsgFilterMin,
939 MsgFilterMax,
940 Msg ))
941 {
942 return TRUE;
943 }
944
945 /* Check for hardware events. */
946 if(co_MsqPeekHardwareMessage( ThreadQueue,
947 RemoveMessages,
948 Window,
949 MsgFilterMin,
950 MsgFilterMax,
951 Msg))
952 {
953
954 if(!ProcessHardwareMessage(Msg, RemoveMessages))
955 continue;
956
957 return TRUE;
958 }
959
960 /* Check for sent messages again. */
961 while (co_MsqDispatchOneSentMessage(ThreadQueue))
962 ;
963
964 /* Check for paint messages. */
965 if( IntGetPaintMessage( Window,
966 MsgFilterMin,
967 MsgFilterMax,
968 pti,
969 Msg,
970 RemoveMessages))
971 {
972 return TRUE;
973 }
974
975 if (PostTimerMessages(Window))
976 {
977 continue;
978 }
979
980 return FALSE;
981 }
982 while (TRUE);
983
984 return TRUE;
985 }
986
987 static NTSTATUS FASTCALL
988 CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
989 {
990 NTSTATUS Status;
991
992 PVOID KernelMem;
993 UINT Size;
994
995 *KernelModeMsg = *UserModeMsg;
996
997 /* See if this message type is present in the table */
998 if (NULL == MsgMemoryEntry)
999 {
1000 /* Not present, no copying needed */
1001 return STATUS_SUCCESS;
1002 }
1003
1004 /* Determine required size */
1005 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
1006
1007 if (0 != Size)
1008 {
1009 /* Allocate kernel mem */
1010 KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
1011 if (NULL == KernelMem)
1012 {
1013 DPRINT1("Not enough memory to copy message to kernel mem\n");
1014 return STATUS_NO_MEMORY;
1015 }
1016 KernelModeMsg->lParam = (LPARAM) KernelMem;
1017
1018 /* Copy data if required */
1019 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
1020 {
1021 Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
1022 if (! NT_SUCCESS(Status))
1023 {
1024 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
1025 ExFreePoolWithTag(KernelMem, TAG_MSG);
1026 return Status;
1027 }
1028 }
1029 else
1030 {
1031 /* Make sure we don't pass any secrets to usermode */
1032 RtlZeroMemory(KernelMem, Size);
1033 }
1034 }
1035 else
1036 {
1037 KernelModeMsg->lParam = 0;
1038 }
1039
1040 return STATUS_SUCCESS;
1041 }
1042
1043 static NTSTATUS FASTCALL
1044 CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
1045 {
1046 NTSTATUS Status;
1047 PMSGMEMORY MsgMemoryEntry;
1048 UINT Size;
1049
1050 /* See if this message type is present in the table */
1051 MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
1052 if (NULL == MsgMemoryEntry)
1053 {
1054 /* Not present, no copying needed */
1055 return STATUS_SUCCESS;
1056 }
1057
1058 /* Determine required size */
1059 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
1060
1061 if (0 != Size)
1062 {
1063 /* Copy data if required */
1064 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
1065 {
1066 Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
1067 if (! NT_SUCCESS(Status))
1068 {
1069 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1070 ExFreePool((PVOID) KernelModeMsg->lParam);
1071 return Status;
1072 }
1073 }
1074
1075 ExFreePool((PVOID) KernelModeMsg->lParam);
1076 }
1077
1078 return STATUS_SUCCESS;
1079 }
1080
1081 static BOOL FASTCALL
1082 co_IntWaitMessage( PWND Window,
1083 UINT MsgFilterMin,
1084 UINT MsgFilterMax )
1085 {
1086 PTHREADINFO pti;
1087 PUSER_MESSAGE_QUEUE ThreadQueue;
1088 NTSTATUS Status = STATUS_SUCCESS;
1089 MSG Msg;
1090
1091 pti = PsGetCurrentThreadWin32Thread();
1092 ThreadQueue = pti->MessageQueue;
1093
1094 do
1095 {
1096 if ( co_IntPeekMessage( &Msg,
1097 Window,
1098 MsgFilterMin,
1099 MsgFilterMax,
1100 PM_NOREMOVE))
1101 {
1102 return TRUE;
1103 }
1104
1105 /* Nothing found. Wait for new messages. */
1106 Status = co_MsqWaitForNewMessages( ThreadQueue,
1107 Window,
1108 MsgFilterMin,
1109 MsgFilterMax);
1110 }
1111 while ( (STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) ||
1112 STATUS_TIMEOUT == Status );
1113
1114 if (!NT_SUCCESS(Status))
1115 {
1116 SetLastNtError(Status);
1117 DPRINT1("Exit co_IntWaitMessage on error!\n");
1118 }
1119
1120 return FALSE;
1121 }
1122
1123 BOOL FASTCALL
1124 co_IntGetPeekMessage( PMSG pMsg,
1125 HWND hWnd,
1126 UINT MsgFilterMin,
1127 UINT MsgFilterMax,
1128 UINT RemoveMsg,
1129 BOOL bGMSG )
1130 {
1131 PWND Window;
1132 BOOL Present = FALSE;
1133
1134 if ( hWnd == HWND_TOPMOST || hWnd == HWND_BROADCAST )
1135 hWnd = HWND_BOTTOM;
1136
1137 /* Validate input */
1138 if (hWnd && hWnd != HWND_BOTTOM)
1139 {
1140 if (!(Window = UserGetWindowObject(hWnd)))
1141 {
1142 if (bGMSG)
1143 return -1;
1144 else
1145 return FALSE;
1146 }
1147 }
1148 else
1149 {
1150 Window = (PWND)hWnd;
1151 }
1152
1153 if (MsgFilterMax < MsgFilterMin)
1154 {
1155 MsgFilterMin = 0;
1156 MsgFilterMax = 0;
1157 }
1158
1159 do
1160 {
1161 Present = co_IntPeekMessage( pMsg,
1162 Window,
1163 MsgFilterMin,
1164 MsgFilterMax,
1165 RemoveMsg );
1166 if (Present)
1167 {
1168 // The WH_GETMESSAGE hook enables an application to monitor messages about to
1169 // be returned by the GetMessage or PeekMessage function.
1170
1171 co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)pMsg);
1172
1173 if ( bGMSG )
1174 return (WM_QUIT != pMsg->message);
1175 }
1176
1177 if ( bGMSG )
1178 {
1179 if ( !co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax) )
1180 return -1;
1181 }
1182 else
1183 {
1184 if (!(RemoveMsg & PM_NOYIELD))
1185 {
1186 IdlePing();
1187 // Yield this thread!
1188 UserLeave();
1189 ZwYieldExecution();
1190 UserEnterExclusive();
1191 // Fall through to exit.
1192 IdlePong();
1193 }
1194 break;
1195 }
1196 }
1197 while( bGMSG && !Present );
1198
1199 return Present;
1200 }
1201
1202 BOOL FASTCALL
1203 UserPostThreadMessage( DWORD idThread,
1204 UINT Msg,
1205 WPARAM wParam,
1206 LPARAM lParam )
1207 {
1208 MSG Message;
1209 PETHREAD peThread;
1210 PTHREADINFO pThread;
1211 LARGE_INTEGER LargeTickCount;
1212 NTSTATUS Status;
1213
1214 DPRINT1("UserPostThreadMessage wParam 0x%x lParam 0x%x\n", wParam,lParam);
1215
1216 if (FindMsgMemory(Msg) != 0)
1217 {
1218 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
1219 return FALSE;
1220 }
1221
1222 Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
1223
1224 if( Status == STATUS_SUCCESS )
1225 {
1226 pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
1227 if( !pThread ||
1228 !pThread->MessageQueue ||
1229 (pThread->TIF_flags & TIF_INCLEANUP))
1230 {
1231 ObDereferenceObject( peThread );
1232 return FALSE;
1233 }
1234
1235 Message.hwnd = NULL;
1236 Message.message = Msg;
1237 Message.wParam = wParam;
1238 Message.lParam = lParam;
1239 Message.pt = gpsi->ptCursor;
1240
1241 KeQueryTickCount(&LargeTickCount);
1242 pThread->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
1243 MsqPostMessage(pThread->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1244 ObDereferenceObject( peThread );
1245 return TRUE;
1246 }
1247 else
1248 {
1249 SetLastNtError( Status );
1250 }
1251 return FALSE;
1252 }
1253
1254 BOOL FASTCALL
1255 UserPostMessage( HWND Wnd,
1256 UINT Msg,
1257 WPARAM wParam,
1258 LPARAM lParam )
1259 {
1260 PTHREADINFO pti;
1261 MSG Message;
1262 LARGE_INTEGER LargeTickCount;
1263
1264 if (FindMsgMemory(Msg) != 0)
1265 {
1266 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
1267 return FALSE;
1268 }
1269
1270 if (!Wnd)
1271 {
1272 return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
1273 Msg,
1274 wParam,
1275 lParam);
1276 }
1277 if (Wnd == HWND_BROADCAST)
1278 {
1279 HWND *List;
1280 PWND DesktopWindow;
1281 ULONG i;
1282
1283 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1284 List = IntWinListChildren(DesktopWindow);
1285
1286 if (List != NULL)
1287 {
1288 UserPostMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1289 for (i = 0; List[i]; i++)
1290 {
1291 UserPostMessage(List[i], Msg, wParam, lParam);
1292 }
1293 ExFreePool(List);
1294 }
1295 }
1296 else
1297 {
1298 PWND Window;
1299
1300 Window = UserGetWindowObject(Wnd);
1301 if ( !Window )
1302 {
1303 return FALSE;
1304 }
1305
1306 pti = Window->head.pti;
1307 if ( pti->TIF_flags & TIF_INCLEANUP )
1308 {
1309 DPRINT1("Attempted to post message to window 0x%x when the thread is in cleanup!\n", Wnd);
1310 return FALSE;
1311 }
1312
1313 if ( Window->state & WNDS_DESTROYED )
1314 {
1315 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
1316 /* FIXME - last error code? */
1317 return FALSE;
1318 }
1319
1320 if (WM_QUIT == Msg)
1321 {
1322 MsqPostQuitMessage(Window->head.pti->MessageQueue, wParam);
1323 }
1324 else
1325 {
1326 Message.hwnd = Wnd;
1327 Message.message = Msg;
1328 Message.wParam = wParam;
1329 Message.lParam = lParam;
1330 Message.pt = gpsi->ptCursor;
1331 KeQueryTickCount(&LargeTickCount);
1332 pti->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
1333 MsqPostMessage(Window->head.pti->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1334 }
1335 }
1336 return TRUE;
1337 }
1338
1339
1340 LRESULT FASTCALL
1341 co_IntSendMessage( HWND hWnd,
1342 UINT Msg,
1343 WPARAM wParam,
1344 LPARAM lParam )
1345 {
1346 ULONG_PTR Result = 0;
1347 if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1348 {
1349 return (LRESULT)Result;
1350 }
1351 return 0;
1352 }
1353
1354 static LRESULT FASTCALL
1355 co_IntSendMessageTimeoutSingle( HWND hWnd,
1356 UINT Msg,
1357 WPARAM wParam,
1358 LPARAM lParam,
1359 UINT uFlags,
1360 UINT uTimeout,
1361 ULONG_PTR *uResult )
1362 {
1363 NTSTATUS Status;
1364 PWND Window = NULL;
1365 PMSGMEMORY MsgMemoryEntry;
1366 INT lParamBufferSize;
1367 LPARAM lParamPacked;
1368 PTHREADINFO Win32Thread;
1369 ULONG_PTR Result = 0;
1370 DECLARE_RETURN(LRESULT);
1371 USER_REFERENCE_ENTRY Ref;
1372
1373 if (!(Window = UserGetWindowObject(hWnd)))
1374 {
1375 RETURN( FALSE);
1376 }
1377
1378 UserRefObjectCo(Window, &Ref);
1379
1380 Win32Thread = PsGetCurrentThreadWin32Thread();
1381
1382 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1383
1384 if ( NULL != Win32Thread &&
1385 Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
1386 {
1387 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1388 {
1389 /* Never send messages to exiting threads */
1390 RETURN( FALSE);
1391 }
1392
1393 /* See if this message type is present in the table */
1394 MsgMemoryEntry = FindMsgMemory(Msg);
1395 if (NULL == MsgMemoryEntry)
1396 {
1397 lParamBufferSize = -1;
1398 }
1399 else
1400 {
1401 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1402 }
1403
1404 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, FALSE)))
1405 {
1406 DPRINT1("Failed to pack message parameters\n");
1407 RETURN( FALSE);
1408 }
1409
1410 ObReferenceObject(Win32Thread->pEThread);
1411 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1412 !Window->Unicode,
1413 hWnd,
1414 Msg,
1415 wParam,
1416 lParamPacked,
1417 lParamBufferSize );
1418 if(uResult)
1419 {
1420 *uResult = Result;
1421 }
1422
1423 ObDereferenceObject(Win32Thread->pEThread);
1424
1425 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1426
1427 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1428 {
1429 DPRINT1("Failed to unpack message parameters\n");
1430 RETURN( TRUE);
1431 }
1432
1433 RETURN( TRUE);
1434 }
1435
1436 if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->head.pti->MessageQueue))
1437 {
1438 /* FIXME - Set a LastError? */
1439 RETURN( FALSE);
1440 }
1441
1442 if (Window->state & WNDS_DESTROYED)
1443 {
1444 /* FIXME - last error? */
1445 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1446 RETURN( FALSE);
1447 }
1448
1449 do
1450 {
1451 Status = co_MsqSendMessage( Window->head.pti->MessageQueue,
1452 hWnd,
1453 Msg,
1454 wParam,
1455 lParam,
1456 uTimeout,
1457 (uFlags & SMTO_BLOCK),
1458 MSQ_NORMAL,
1459 uResult );
1460 }
1461 while ((STATUS_TIMEOUT == Status) &&
1462 (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
1463 !MsqIsHung(Window->head.pti->MessageQueue));
1464
1465 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1466
1467 if (STATUS_TIMEOUT == Status)
1468 {
1469 /*
1470 MSDN says:
1471 Microsoft Windows 2000: If GetLastError returns zero, then the function
1472 timed out.
1473 XP+ : If the function fails or times out, the return value is zero.
1474 To get extended error information, call GetLastError. If GetLastError
1475 returns ERROR_TIMEOUT, then the function timed out.
1476 */
1477 SetLastWin32Error(ERROR_TIMEOUT);
1478 RETURN( FALSE);
1479 }
1480 else if (! NT_SUCCESS(Status))
1481 {
1482 SetLastNtError(Status);
1483 RETURN( FALSE);
1484 }
1485
1486 RETURN( TRUE);
1487
1488 CLEANUP:
1489 if (Window) UserDerefObjectCo(Window);
1490 END_CLEANUP;
1491 }
1492
1493 LRESULT FASTCALL
1494 co_IntSendMessageTimeout( HWND hWnd,
1495 UINT Msg,
1496 WPARAM wParam,
1497 LPARAM lParam,
1498 UINT uFlags,
1499 UINT uTimeout,
1500 ULONG_PTR *uResult )
1501 {
1502 PWND DesktopWindow;
1503 HWND *Children;
1504 HWND *Child;
1505
1506 if (HWND_BROADCAST != hWnd)
1507 {
1508 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1509 }
1510
1511 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1512 if (NULL == DesktopWindow)
1513 {
1514 SetLastWin32Error(ERROR_INTERNAL_ERROR);
1515 return 0;
1516 }
1517
1518 /* Send message to the desktop window too! */
1519 co_IntSendMessageTimeoutSingle(DesktopWindow->head.h, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1520
1521 Children = IntWinListChildren(DesktopWindow);
1522 if (NULL == Children)
1523 {
1524 return 0;
1525 }
1526
1527 for (Child = Children; NULL != *Child; Child++)
1528 {
1529 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1530 }
1531
1532 ExFreePool(Children);
1533
1534 return (LRESULT) TRUE;
1535 }
1536
1537 LRESULT FASTCALL
1538 co_IntSendMessageNoWait(HWND hWnd,
1539 UINT Msg,
1540 WPARAM wParam,
1541 LPARAM lParam)
1542 {
1543 ULONG_PTR Result = 0;
1544 co_IntSendMessageWithCallBack(hWnd,
1545 Msg,
1546 wParam,
1547 lParam,
1548 NULL,
1549 0,
1550 &Result);
1551 return Result;
1552 }
1553
1554 LRESULT FASTCALL
1555 co_IntSendMessageWithCallBack( HWND hWnd,
1556 UINT Msg,
1557 WPARAM wParam,
1558 LPARAM lParam,
1559 SENDASYNCPROC CompletionCallback,
1560 ULONG_PTR CompletionCallbackContext,
1561 ULONG_PTR *uResult)
1562 {
1563 ULONG_PTR Result;
1564 PWND Window = NULL;
1565 PMSGMEMORY MsgMemoryEntry;
1566 INT lParamBufferSize;
1567 LPARAM lParamPacked;
1568 PTHREADINFO Win32Thread;
1569 DECLARE_RETURN(LRESULT);
1570 USER_REFERENCE_ENTRY Ref;
1571 PUSER_SENT_MESSAGE Message;
1572
1573 if (!(Window = UserGetWindowObject(hWnd)))
1574 {
1575 RETURN(FALSE);
1576 }
1577
1578 UserRefObjectCo(Window, &Ref);
1579
1580 if (Window->state & WNDS_DESTROYED)
1581 {
1582 /* FIXME - last error? */
1583 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1584 RETURN(FALSE);
1585 }
1586
1587 Win32Thread = PsGetCurrentThreadWin32Thread();
1588
1589 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1590
1591 if (Win32Thread == NULL)
1592 {
1593 ASSERT(FALSE);
1594 RETURN(FALSE);
1595 }
1596
1597 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1598 {
1599 /* Never send messages to exiting threads */
1600 RETURN(FALSE);
1601 }
1602
1603 /* See if this message type is present in the table */
1604 MsgMemoryEntry = FindMsgMemory(Msg);
1605 if (NULL == MsgMemoryEntry)
1606 {
1607 lParamBufferSize = -1;
1608 }
1609 else
1610 {
1611 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1612 }
1613
1614 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, Window->head.pti->MessageQueue != Win32Thread->MessageQueue)))
1615 {
1616 DPRINT1("Failed to pack message parameters\n");
1617 RETURN( FALSE);
1618 }
1619
1620 /* If this is not a callback and it can be sent now, then send it. */
1621 if ((Window->head.pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
1622 {
1623 ObReferenceObject(Win32Thread->pEThread);
1624 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1625 !Window->Unicode,
1626 hWnd,
1627 Msg,
1628 wParam,
1629 lParamPacked,
1630 lParamBufferSize );
1631 if(uResult)
1632 {
1633 *uResult = Result;
1634 }
1635 ObDereferenceObject(Win32Thread->pEThread);
1636 }
1637
1638 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1639
1640 if ((Window->head.pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
1641 {
1642 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1643 {
1644 DPRINT1("Failed to unpack message parameters\n");
1645 }
1646 RETURN(TRUE);
1647 }
1648
1649 if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
1650 {
1651 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1652 return STATUS_INSUFFICIENT_RESOURCES;
1653 }
1654
1655 Message->Msg.hwnd = hWnd;
1656 Message->Msg.message = Msg;
1657 Message->Msg.wParam = wParam;
1658 Message->Msg.lParam = lParamPacked;
1659 Message->CompletionEvent = NULL;
1660 Message->Result = 0;
1661 Message->SenderQueue = NULL; //Win32Thread->MessageQueue;
1662
1663 IntReferenceMessageQueue(Window->head.pti->MessageQueue);
1664 Message->CompletionCallback = CompletionCallback;
1665 Message->CompletionCallbackContext = CompletionCallbackContext;
1666 Message->HookMessage = MSQ_NORMAL | MSQ_SENTNOWAIT;
1667 Message->HasPackedLParam = (lParamBufferSize > 0);
1668
1669 InsertTailList(&Window->head.pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
1670 IntDereferenceMessageQueue(Window->head.pti->MessageQueue);
1671
1672 RETURN(TRUE);
1673
1674 CLEANUP:
1675 if (Window) UserDerefObjectCo(Window);
1676 END_CLEANUP;
1677 }
1678
1679 /* This function posts a message if the destination's message queue belongs to
1680 another thread, otherwise it sends the message. It does not support broadcast
1681 messages! */
1682 LRESULT FASTCALL
1683 co_IntPostOrSendMessage( HWND hWnd,
1684 UINT Msg,
1685 WPARAM wParam,
1686 LPARAM lParam )
1687 {
1688 ULONG_PTR Result;
1689 PTHREADINFO pti;
1690 PWND Window;
1691
1692 if ( hWnd == HWND_BROADCAST )
1693 {
1694 return 0;
1695 }
1696
1697 if(!(Window = UserGetWindowObject(hWnd)))
1698 {
1699 return 0;
1700 }
1701
1702 pti = PsGetCurrentThreadWin32Thread();
1703
1704 if ( Window->head.pti->MessageQueue != pti->MessageQueue &&
1705 FindMsgMemory(Msg) == 0 )
1706 {
1707 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1708 }
1709 else
1710 {
1711 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
1712 {
1713 Result = 0;
1714 }
1715 }
1716
1717 return (LRESULT)Result;
1718 }
1719
1720 LRESULT FASTCALL
1721 co_IntDoSendMessage( HWND hWnd,
1722 UINT Msg,
1723 WPARAM wParam,
1724 LPARAM lParam,
1725 PDOSENDMESSAGE dsm,
1726 PNTUSERSENDMESSAGEINFO UnsafeInfo )
1727 {
1728 PTHREADINFO pti;
1729 LRESULT Result = TRUE;
1730 NTSTATUS Status;
1731 PWND Window = NULL;
1732 NTUSERSENDMESSAGEINFO Info;
1733 MSG UserModeMsg;
1734 MSG KernelModeMsg;
1735 PMSGMEMORY MsgMemoryEntry;
1736
1737 RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));
1738
1739 /* FIXME: Call hooks. */
1740 if (HWND_BROADCAST != hWnd)
1741 {
1742 Window = UserGetWindowObject(hWnd);
1743 if ( !Window )
1744 {
1745 /* Tell usermode to not touch this one */
1746 Info.HandledByKernel = TRUE;
1747 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1748 return 0;
1749 }
1750 }
1751
1752 /* Check for an exiting window. */
1753 if (Window && Window->state & WNDS_DESTROYED)
1754 {
1755 DPRINT1("co_IntDoSendMessage Window Exiting!\n");
1756 }
1757
1758 /* See if the current thread can handle the message */
1759 pti = PsGetCurrentThreadWin32Thread();
1760
1761 // This is checked in user mode!!!!!!!
1762 if ( HWND_BROADCAST != hWnd &&
1763 NULL != pti &&
1764 Window->head.pti->MessageQueue == pti->MessageQueue &&
1765 !ISITHOOKED(WH_CALLWNDPROC) &&
1766 !ISITHOOKED(WH_CALLWNDPROCRET) &&
1767 ( Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST ) )
1768 {
1769 /* Gather the information usermode needs to call the window proc directly */
1770 Info.HandledByKernel = FALSE;
1771
1772 Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi), sizeof(BOOL));
1773 if (! NT_SUCCESS(Status))
1774 {
1775 Info.Ansi = ! Window->Unicode;
1776 }
1777
1778 Info.Ansi = !Window->Unicode;
1779 Info.Proc = Window->lpfnWndProc;
1780 }
1781 else
1782 {
1783 /* Must be handled by other thread */
1784 // if (HWND_BROADCAST != hWnd)
1785 // {
1786 // UserDereferenceObject(Window);
1787 // }
1788 Info.HandledByKernel = TRUE;
1789 UserModeMsg.hwnd = hWnd;
1790 UserModeMsg.message = Msg;
1791 UserModeMsg.wParam = wParam;
1792 UserModeMsg.lParam = lParam;
1793 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1794
1795 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1796 if (! NT_SUCCESS(Status))
1797 {
1798 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1799 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1800 return (dsm ? 0 : -1);
1801 }
1802
1803 if(!dsm)
1804 {
1805 Result = co_IntSendMessage( KernelModeMsg.hwnd,
1806 KernelModeMsg.message,
1807 KernelModeMsg.wParam,
1808 KernelModeMsg.lParam );
1809 }
1810 else
1811 {
1812 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1813 KernelModeMsg.message,
1814 KernelModeMsg.wParam,
1815 KernelModeMsg.lParam,
1816 dsm->uFlags,
1817 dsm->uTimeout,
1818 &dsm->Result );
1819 }
1820
1821 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1822 if (! NT_SUCCESS(Status))
1823 {
1824 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1825 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1826 return(dsm ? 0 : -1);
1827 }
1828 }
1829
1830 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1831 if (! NT_SUCCESS(Status))
1832 {
1833 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1834 }
1835
1836 return (LRESULT)Result;
1837 }
1838
1839
1840 BOOL FASTCALL
1841 UserSendNotifyMessage( HWND hWnd,
1842 UINT Msg,
1843 WPARAM wParam,
1844 LPARAM lParam )
1845 {
1846 BOOL Result = TRUE;
1847
1848 if (FindMsgMemory(Msg) != 0)
1849 {
1850 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
1851 return FALSE;
1852 }
1853
1854 // Basicly the same as IntPostOrSendMessage
1855 if (hWnd == HWND_BROADCAST) //Handle Broadcast
1856 {
1857 HWND *List;
1858 PWND DesktopWindow;
1859 ULONG i;
1860
1861 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1862 List = IntWinListChildren(DesktopWindow);
1863
1864 if (List != NULL)
1865 {
1866 UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1867 for (i = 0; List[i]; i++)
1868 {
1869 UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1870 }
1871 ExFreePool(List);
1872 }
1873 }
1874 else
1875 {
1876 ULONG_PTR PResult;
1877 PTHREADINFO pti;
1878 PWND Window;
1879
1880 if ( !(Window = UserGetWindowObject(hWnd)) ) return FALSE;
1881
1882 pti = PsGetCurrentThreadWin32Thread();
1883
1884 if (Window->head.pti->MessageQueue != pti->MessageQueue)
1885 { // Send message w/o waiting for it.
1886 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1887 }
1888 else
1889 { // Handle message and callback.
1890 Result = co_IntSendMessageTimeoutSingle( hWnd,
1891 Msg,
1892 wParam,
1893 lParam,
1894 SMTO_NORMAL,
1895 0,
1896 &PResult );
1897 }
1898 }
1899 return Result;
1900 }
1901
1902
1903 DWORD APIENTRY
1904 IntGetQueueStatus(DWORD Changes)
1905 {
1906 PTHREADINFO pti;
1907 PUSER_MESSAGE_QUEUE Queue;
1908 DWORD Result;
1909
1910 pti = PsGetCurrentThreadWin32Thread();
1911 Queue = pti->MessageQueue;
1912 // wine:
1913 Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
1914
1915 Result = MAKELONG(Queue->ChangedBits & Changes, Queue->QueueBits & Changes);
1916
1917 if (pti->pcti)
1918 {
1919 pti->pcti->fsChangeBits = Queue->ChangedBits;
1920 pti->pcti->fsChangeBits &= ~Changes;
1921 }
1922
1923 Queue->ChangedBits &= ~Changes;
1924
1925 return Result;
1926 }
1927
1928 BOOL APIENTRY
1929 IntInitMessagePumpHook()
1930 {
1931 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1932
1933 if (pti->pcti)
1934 {
1935 pti->pcti->dwcPumpHook++;
1936 return TRUE;
1937 }
1938 return FALSE;
1939 }
1940
1941 BOOL APIENTRY
1942 IntUninitMessagePumpHook()
1943 {
1944 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1945
1946 if (pti->pcti)
1947 {
1948 if (pti->pcti->dwcPumpHook <= 0)
1949 {
1950 return FALSE;
1951 }
1952 pti->pcti->dwcPumpHook--;
1953 return TRUE;
1954 }
1955 return FALSE;
1956 }
1957
1958 /** Functions ******************************************************************/
1959
1960 BOOL APIENTRY
1961 NtUserPostMessage(HWND hWnd,
1962 UINT Msg,
1963 WPARAM wParam,
1964 LPARAM lParam)
1965 {
1966 BOOL ret;
1967
1968 UserEnterExclusive();
1969
1970 ret = UserPostMessage(hWnd, Msg, wParam, lParam);
1971
1972 UserLeave();
1973
1974 return ret;
1975 }
1976
1977 BOOL APIENTRY
1978 NtUserPostThreadMessage(DWORD idThread,
1979 UINT Msg,
1980 WPARAM wParam,
1981 LPARAM lParam)
1982 {
1983 BOOL ret;
1984
1985 UserEnterExclusive();
1986
1987 ret = UserPostThreadMessage( idThread, Msg, wParam, lParam);
1988
1989 UserLeave();
1990
1991 return ret;
1992 }
1993
1994 DWORD APIENTRY
1995 NtUserQuerySendMessage(DWORD Unknown0)
1996 {
1997 UNIMPLEMENTED;
1998
1999 return 0;
2000 }
2001
2002
2003 ////////// API on the way out!
2004 LRESULT APIENTRY
2005 NtUserSendMessageTimeout( HWND hWnd,
2006 UINT Msg,
2007 WPARAM wParam,
2008 LPARAM lParam,
2009 UINT uFlags,
2010 UINT uTimeout,
2011 ULONG_PTR *uResult,
2012 PNTUSERSENDMESSAGEINFO UnsafeInfo )
2013 {
2014 DOSENDMESSAGE dsm;
2015 LRESULT Result;
2016
2017 DPRINT("Enter NtUserSendMessageTimeout\n");
2018
2019 dsm.uFlags = uFlags;
2020 dsm.uTimeout = uTimeout;
2021
2022 UserEnterExclusive();
2023
2024 Result = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
2025
2026 UserLeave();
2027
2028 if(uResult != NULL && Result != 0)
2029 {
2030 _SEH2_TRY
2031 {
2032 ProbeForWrite(uResult, sizeof(ULONG_PTR), 1);
2033 RtlCopyMemory(uResult, &dsm.Result, sizeof(ULONG_PTR));
2034 }
2035 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2036 {
2037 SetLastWin32Error(ERROR_INVALID_PARAMETER);;
2038 Result = FALSE;
2039 }
2040 _SEH2_END;
2041 }
2042
2043 return Result;
2044 }
2045
2046 LRESULT APIENTRY
2047 NtUserSendMessage( HWND Wnd,
2048 UINT Msg,
2049 WPARAM wParam,
2050 LPARAM lParam,
2051 PNTUSERSENDMESSAGEINFO UnsafeInfo )
2052 {
2053 BOOL ret;
2054
2055 UserEnterExclusive();
2056
2057 ret = co_IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo);
2058
2059 UserLeave();
2060
2061 return ret;
2062 }
2063 //////////
2064
2065 BOOL APIENTRY
2066 NtUserWaitMessage(VOID)
2067 {
2068 BOOL ret;
2069
2070 UserEnterExclusive();
2071
2072 ret = co_IntWaitMessage(NULL, 0, 0);
2073
2074 UserLeave();
2075
2076 return ret;
2077 }
2078
2079
2080 BOOL APIENTRY
2081 NtUserGetMessage( PNTUSERGETMESSAGEINFO UnsafeInfo,
2082 HWND hWnd,
2083 UINT MsgFilterMin,
2084 UINT MsgFilterMax )
2085 /*
2086 * FUNCTION: Get a message from the calling thread's message queue.
2087 * ARGUMENTS:
2088 * UnsafeMsg - Pointer to the structure which receives the returned message.
2089 * Wnd - Window whose messages are to be retrieved.
2090 * MsgFilterMin - Integer value of the lowest message value to be
2091 * retrieved.
2092 * MsgFilterMax - Integer value of the highest message value to be
2093 * retrieved.
2094 */
2095 {
2096 NTUSERGETMESSAGEINFO Info;
2097 NTSTATUS Status;
2098 PMSGMEMORY MsgMemoryEntry;
2099 PVOID UserMem;
2100 ULONG Size;
2101 MSG Msg;
2102 BOOL GotMessage;
2103
2104 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
2105 {
2106 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2107 return FALSE;
2108 }
2109
2110 UserEnterExclusive();
2111
2112 RtlZeroMemory(&Msg, sizeof(MSG));
2113
2114 GotMessage = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
2115
2116 UserLeave();
2117
2118 Info.Msg = Msg;
2119 /* See if this message type is present in the table */
2120 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
2121
2122 _SEH2_TRY
2123 {
2124 ProbeForWrite(UnsafeInfo, sizeof(NTUSERGETMESSAGEINFO), 1);
2125 RtlCopyMemory(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
2126
2127 if (NULL == MsgMemoryEntry)
2128 {
2129 /* Not present, no copying needed */
2130 UnsafeInfo->LParamSize = 0;
2131 }
2132 else
2133 {
2134 /* Determine required size */
2135 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam, Info.Msg.lParam);
2136
2137 /* Allocate required amount of user-mode memory */
2138 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
2139 &UserMem,
2140 0,
2141 &Size,
2142 MEM_COMMIT,
2143 PAGE_READWRITE);
2144 if (! NT_SUCCESS(Status))
2145 {
2146 SetLastNtError(Status);
2147 _SEH2_YIELD(return (BOOL) -1);
2148 }
2149
2150 /* Transfer lParam data to user-mode mem */
2151 ProbeForWrite(UserMem, Size, 1);
2152 RtlCopyMemory(UserMem, (PVOID)Info.Msg.lParam, Size);
2153
2154 UnsafeInfo->LParamSize = Size;
2155 UnsafeInfo->Msg.lParam = (LPARAM) UserMem;
2156 }
2157 }
2158 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2159 {
2160 SetLastNtError(_SEH2_GetExceptionCode());
2161
2162 if(UserMem != NULL)
2163 {
2164 ZwFreeVirtualMemory(NtCurrentProcess(), &UserMem, &Size, MEM_RELEASE);
2165 }
2166
2167 _SEH2_YIELD(return (BOOL) -1);
2168 }
2169 _SEH2_END;
2170
2171 return GotMessage;
2172 }
2173
2174
2175 BOOL APIENTRY
2176 NtUserGetMessageX(PMSG pMsg,
2177 HWND hWnd,
2178 UINT MsgFilterMin,
2179 UINT MsgFilterMax)
2180 {
2181 MSG Msg;
2182 BOOL Ret;
2183
2184 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
2185 {
2186 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2187 return FALSE;
2188 }
2189
2190 UserEnterExclusive();
2191
2192 RtlZeroMemory(&Msg, sizeof(MSG));
2193
2194 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
2195
2196 UserLeave();
2197
2198 if (Ret)
2199 {
2200 _SEH2_TRY
2201 {
2202 ProbeForWrite(pMsg, sizeof(MSG), 1);
2203 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
2204 }
2205 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2206 {
2207 SetLastNtError(_SEH2_GetExceptionCode());
2208 Ret = FALSE;
2209 }
2210 _SEH2_END;
2211 }
2212
2213 return Ret;
2214 }
2215
2216 BOOL APIENTRY
2217 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
2218 HWND hWnd,
2219 UINT MsgFilterMin,
2220 UINT MsgFilterMax,
2221 UINT RemoveMsg)
2222 {
2223 NTSTATUS Status;
2224 NTUSERGETMESSAGEINFO Info;
2225 PMSGMEMORY MsgMemoryEntry;
2226 PVOID UserMem = NULL;
2227 ULONG Size;
2228 MSG Msg;
2229 BOOL Ret;
2230
2231 if ( RemoveMsg & PM_BADMSGFLAGS )
2232 {
2233 SetLastWin32Error(ERROR_INVALID_FLAGS);
2234 return FALSE;
2235 }
2236
2237 UserEnterExclusive();
2238
2239 RtlZeroMemory(&Msg, sizeof(MSG));
2240
2241 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
2242
2243 UserLeave();
2244
2245 if (Ret)
2246 {
2247 Info.Msg = Msg;
2248 /* See if this message type is present in the table */
2249 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
2250
2251 _SEH2_TRY
2252 {
2253 ProbeForWrite(UnsafeInfo, sizeof(NTUSERGETMESSAGEINFO), 1);
2254 RtlCopyMemory(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
2255
2256 if (NULL == MsgMemoryEntry)
2257 {
2258 /* Not present, no copying needed */
2259 UnsafeInfo->LParamSize = 0;
2260 }
2261 else
2262 {
2263 /* Determine required size */
2264 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam, Info.Msg.lParam);
2265
2266 /* Allocate required amount of user-mode memory */
2267 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
2268 &UserMem,
2269 0,
2270 &Size,
2271 MEM_COMMIT,
2272 PAGE_READWRITE);
2273 if (! NT_SUCCESS(Status))
2274 {
2275 SetLastNtError(Status);
2276 _SEH2_YIELD(return (BOOL) -1);
2277 }
2278
2279 /* Transfer lParam data to user-mode mem */
2280 ProbeForWrite(UserMem, Size, 1);
2281 RtlCopyMemory(UserMem, (PVOID)Info.Msg.lParam, Size);
2282
2283 UnsafeInfo->LParamSize = Size;
2284 UnsafeInfo->Msg.lParam = (LPARAM) UserMem;
2285 }
2286 }
2287 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2288 {
2289 SetLastNtError(_SEH2_GetExceptionCode());
2290 Ret = (BOOL) -1;
2291
2292 if(UserMem != NULL)
2293 {
2294 ZwFreeVirtualMemory(NtCurrentProcess(), &UserMem, &Size, MEM_RELEASE);
2295 }
2296 }
2297 _SEH2_END;
2298 }
2299
2300 return Ret;
2301 }
2302
2303 BOOL APIENTRY
2304 NtUserPeekMessageX( PMSG pMsg,
2305 HWND hWnd,
2306 UINT MsgFilterMin,
2307 UINT MsgFilterMax,
2308 UINT RemoveMsg)
2309 {
2310 MSG Msg;
2311 BOOL Ret;
2312
2313 if ( RemoveMsg & PM_BADMSGFLAGS )
2314 {
2315 SetLastWin32Error(ERROR_INVALID_FLAGS);
2316 return FALSE;
2317 }
2318
2319 UserEnterExclusive();
2320
2321 RtlZeroMemory(&Msg, sizeof(MSG));
2322
2323 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
2324
2325 UserLeave();
2326
2327 if (Ret)
2328 {
2329 _SEH2_TRY
2330 {
2331 ProbeForWrite(pMsg, sizeof(MSG), 1);
2332 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
2333 }
2334 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2335 {
2336 SetLastNtError(_SEH2_GetExceptionCode());
2337 Ret = FALSE;
2338 }
2339 _SEH2_END;
2340 }
2341
2342 return Ret;
2343 }
2344
2345 BOOL APIENTRY
2346 NtUserCallMsgFilter( LPMSG lpmsg, INT code)
2347 {
2348 BOOL Ret = FALSE;
2349 MSG Msg;
2350
2351 _SEH2_TRY
2352 {
2353 ProbeForRead(lpmsg, sizeof(MSG), 1);
2354 RtlCopyMemory( &Msg, lpmsg, sizeof(MSG));
2355 }
2356 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2357 {
2358 _SEH2_YIELD(return FALSE);
2359 }
2360 _SEH2_END;
2361
2362 UserEnterExclusive();
2363
2364 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
2365 {
2366 Ret = TRUE;
2367 }
2368 else
2369 {
2370 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
2371 }
2372
2373 UserLeave();
2374
2375 _SEH2_TRY
2376 {
2377 ProbeForWrite(lpmsg, sizeof(MSG), 1);
2378 RtlCopyMemory(lpmsg, &Msg, sizeof(MSG));
2379 }
2380 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2381 {
2382 Ret = FALSE;
2383 }
2384 _SEH2_END;
2385
2386 return Ret;
2387 }
2388
2389 LRESULT APIENTRY
2390 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
2391 {
2392 LRESULT Res = 0;
2393 MSG SafeMsg;
2394
2395 _SEH2_TRY
2396 {
2397 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
2398 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
2399 }
2400 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2401 {
2402 SetLastNtError(_SEH2_GetExceptionCode());
2403 _SEH2_YIELD(return FALSE);
2404 }
2405 _SEH2_END;
2406
2407 UserEnterExclusive();
2408
2409 Res = IntDispatchMessage(&SafeMsg);
2410
2411 UserLeave();
2412 return Res;
2413 }
2414
2415
2416 BOOL APIENTRY
2417 NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
2418 {
2419 MSG SafeMsg;
2420 BOOL Ret;
2421
2422 _SEH2_TRY
2423 {
2424 ProbeForRead(lpMsg, sizeof(MSG), 1);
2425 RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG));
2426 }
2427 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2428 {
2429 SetLastNtError(_SEH2_GetExceptionCode());
2430 _SEH2_YIELD(return FALSE);
2431 }
2432 _SEH2_END;
2433
2434 UserEnterExclusive();
2435
2436 Ret = IntTranslateKbdMessage(&SafeMsg, flags);
2437
2438 UserLeave();
2439
2440 return Ret;
2441 }
2442
2443 BOOL APIENTRY
2444 NtUserMessageCall( HWND hWnd,
2445 UINT Msg,
2446 WPARAM wParam,
2447 LPARAM lParam,
2448 ULONG_PTR ResultInfo,
2449 DWORD dwType, // fnID?
2450 BOOL Ansi)
2451 {
2452 LRESULT lResult = 0;
2453 BOOL Ret = FALSE;
2454 PWND Window = NULL;
2455 USER_REFERENCE_ENTRY Ref;
2456
2457 UserEnterExclusive();
2458
2459 /* Validate input */
2460 if (hWnd && (hWnd != INVALID_HANDLE_VALUE))
2461 {
2462 Window = UserGetWindowObject(hWnd);
2463 if (!Window)
2464 {
2465 UserLeave();
2466 return FALSE;
2467 }
2468 }
2469
2470 switch(dwType)
2471 {
2472 case FNID_DEFWINDOWPROC:
2473 if (Window) UserRefObjectCo(Window, &Ref);
2474 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2475 Ret = TRUE;
2476 if (Window) UserDerefObjectCo(Window);
2477 break;
2478 case FNID_SENDNOTIFYMESSAGE:
2479 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
2480 break;
2481 case FNID_BROADCASTSYSTEMMESSAGE:
2482 {
2483 BROADCASTPARM parm;
2484 DWORD_PTR RetVal = 0;
2485
2486 if (ResultInfo)
2487 {
2488 _SEH2_TRY
2489 {
2490 ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1);
2491 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
2492 }
2493 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2494 {
2495 Ret = FALSE;
2496 _SEH2_YIELD(break);
2497 }
2498 _SEH2_END;
2499 }
2500 else
2501 break;
2502
2503 if ( parm.recipients & BSM_ALLDESKTOPS ||
2504 parm.recipients == BSM_ALLCOMPONENTS )
2505 {
2506 }
2507 else if (parm.recipients & BSM_APPLICATIONS)
2508 {
2509 if (parm.flags & BSF_QUERY)
2510 {
2511 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2512 {
2513 co_IntSendMessageTimeout( HWND_BROADCAST,
2514 Msg,
2515 wParam,
2516 lParam,
2517 SMTO_ABORTIFHUNG,
2518 2000,
2519 &RetVal);
2520 }
2521 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2522 {
2523 co_IntSendMessageTimeout( HWND_BROADCAST,
2524 Msg,
2525 wParam,
2526 lParam,
2527 SMTO_NOTIMEOUTIFNOTHUNG,
2528 2000,
2529 &RetVal);
2530 }
2531 else
2532 {
2533 co_IntSendMessageTimeout( HWND_BROADCAST,
2534 Msg,
2535 wParam,
2536 lParam,
2537 SMTO_NORMAL,
2538 2000,
2539 &RetVal);
2540 }
2541 Ret = RetVal;
2542 }
2543 else if (parm.flags & BSF_POSTMESSAGE)
2544 {
2545 Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
2546 }
2547 else //Everything else,,,, if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
2548 {
2549 Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
2550 }
2551 }
2552 }
2553 break;
2554 case FNID_SENDMESSAGECALLBACK:
2555 {
2556 PCALL_BACK_INFO CallBackInfo = (PCALL_BACK_INFO)ResultInfo;
2557 ULONG_PTR uResult;
2558
2559 if (!CallBackInfo)
2560 break;
2561
2562 if (!co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
2563 CallBackInfo->CallBack, CallBackInfo->Context, &uResult))
2564 {
2565 DPRINT1("Callback failure!\n");
2566 }
2567 }
2568 break;
2569 // CallNextHook bypass.
2570 case FNID_CALLWNDPROC:
2571 case FNID_CALLWNDPROCRET:
2572 {
2573 PTHREADINFO pti;
2574 PCLIENTINFO ClientInfo;
2575 PHOOK NextObj, Hook;
2576
2577 pti = GetW32ThreadInfo();
2578
2579 Hook = pti->sphkCurrent;
2580
2581 if (!Hook) break;
2582
2583 NextObj = Hook->phkNext;
2584 ClientInfo = pti->pClientInfo;
2585 _SEH2_TRY
2586 {
2587 ClientInfo->phkCurrent = NextObj;
2588 }
2589 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2590 {
2591 ClientInfo = NULL;
2592 }
2593 _SEH2_END;
2594
2595 if (!ClientInfo || !NextObj) break;
2596
2597 NextObj->phkNext = IntGetNextHook(NextObj);
2598
2599 if ( Hook->HookId == WH_CALLWNDPROC)
2600 {
2601 CWPSTRUCT CWP;
2602 CWP.hwnd = hWnd;
2603 CWP.message = Msg;
2604 CWP.wParam = wParam;
2605 CWP.lParam = lParam;
2606 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
2607
2608 lResult = co_IntCallHookProc( Hook->HookId,
2609 HC_ACTION,
2610 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2611 (LPARAM)&CWP,
2612 Hook->Proc,
2613 Hook->Ansi,
2614 &Hook->ModuleName);
2615 }
2616 else
2617 {
2618 CWPRETSTRUCT CWPR;
2619 CWPR.hwnd = hWnd;
2620 CWPR.message = Msg;
2621 CWPR.wParam = wParam;
2622 CWPR.lParam = lParam;
2623 CWPR.lResult = ClientInfo->dwHookData;
2624
2625 lResult = co_IntCallHookProc( Hook->HookId,
2626 HC_ACTION,
2627 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2628 (LPARAM)&CWPR,
2629 Hook->Proc,
2630 Hook->Ansi,
2631 &Hook->ModuleName);
2632 }
2633 }
2634 break;
2635 }
2636
2637 switch(dwType)
2638 {
2639 case FNID_DEFWINDOWPROC:
2640 case FNID_CALLWNDPROC:
2641 case FNID_CALLWNDPROCRET:
2642 if (ResultInfo)
2643 {
2644 _SEH2_TRY
2645 {
2646 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2647 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2648 }
2649 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2650 {
2651 Ret = FALSE;
2652 }
2653 _SEH2_END;
2654 }
2655 break;
2656 default:
2657 break;
2658 }
2659
2660 UserLeave();
2661
2662 return Ret;
2663 }
2664
2665 #define INFINITE 0xFFFFFFFF
2666 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2667
2668 DWORD
2669 APIENTRY
2670 NtUserWaitForInputIdle( IN HANDLE hProcess,
2671 IN DWORD dwMilliseconds,
2672 IN BOOL Unknown2)
2673 {
2674 PEPROCESS Process;
2675 PPROCESSINFO W32Process;
2676 PTHREADINFO pti;
2677 NTSTATUS Status;
2678 HANDLE Handles[3];
2679 LARGE_INTEGER Timeout;
2680
2681 UserEnterExclusive();
2682
2683 Status = ObReferenceObjectByHandle(hProcess,
2684 PROCESS_QUERY_INFORMATION,
2685 PsProcessType,
2686 UserMode,
2687 (PVOID*)&Process,
2688 NULL);
2689
2690 if (!NT_SUCCESS(Status))
2691 {
2692 UserLeave();
2693 SetLastNtError(Status);
2694 return WAIT_FAILED;
2695 }
2696
2697 pti = PsGetCurrentThreadWin32Thread();
2698
2699 W32Process = (PPROCESSINFO)Process->Win32Process;
2700
2701 if ( PsGetProcessExitProcessCalled(Process) ||
2702 !W32Process ||
2703 pti->ppi == W32Process)
2704 {
2705 ObDereferenceObject(Process);
2706 UserLeave();
2707 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2708 return WAIT_FAILED;
2709 }
2710
2711 Handles[0] = Process;
2712 Handles[1] = W32Process->InputIdleEvent;
2713 Handles[2] = pti->MessageQueue->NewMessages; // pEventQueueServer; IntMsqSetWakeMask returns hEventQueueClient
2714
2715 if (!Handles[1])
2716 {
2717 ObDereferenceObject(Process);
2718 UserLeave();
2719 return STATUS_SUCCESS; /* no event to wait on */
2720 }
2721
2722 if (dwMilliseconds != INFINITE)
2723 Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
2724
2725 DPRINT("WFII: ppi 0x%x\n",W32Process);
2726 DPRINT("WFII: waiting for %p\n", Handles[1] );
2727 do
2728 {
2729 UserLeave();
2730 Status = KeWaitForMultipleObjects( 3,
2731 Handles,
2732 WaitAny,
2733 UserRequest,
2734 UserMode,
2735 FALSE,
2736 dwMilliseconds == INFINITE ? NULL : &Timeout,
2737 NULL);
2738 UserEnterExclusive();
2739
2740 if (!NT_SUCCESS(Status))
2741 {
2742 SetLastNtError(Status);
2743 Status = WAIT_FAILED;
2744 goto WaitExit;
2745 }
2746
2747 switch (Status)
2748 {
2749 case STATUS_WAIT_0:
2750 goto WaitExit;
2751
2752 case STATUS_WAIT_2:
2753 {
2754 MSG Msg;
2755 co_IntPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE );
2756 DPRINT1("WFII: WAIT 2\n");
2757 }
2758 break;
2759
2760 case STATUS_TIMEOUT:
2761 DPRINT1("WFII: timeout\n");
2762 case WAIT_FAILED:
2763 goto WaitExit;
2764
2765 default:
2766 DPRINT1("WFII: finished\n");
2767 Status = STATUS_SUCCESS;
2768 goto WaitExit;
2769 }
2770 }
2771 while (TRUE);
2772
2773 WaitExit:
2774 ObDereferenceObject(Process);
2775 UserLeave();
2776 return Status;
2777 }
2778
2779 /* EOF */