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