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