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