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