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