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