e78ce5aeca2edfb2ea5636a84f336b763ee6ffe1
[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) && (CompletionCallback == NULL))
1629 {
1630 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1631 {
1632 DPRINT1("Failed to unpack message parameters\n");
1633 }
1634 RETURN(TRUE);
1635 }
1636
1637 if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
1638 {
1639 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1640 return STATUS_INSUFFICIENT_RESOURCES;
1641 }
1642
1643 Message->Msg.hwnd = hWnd;
1644 Message->Msg.message = Msg;
1645 Message->Msg.wParam = wParam;
1646 Message->Msg.lParam = lParamPacked;
1647 Message->CompletionEvent = NULL;
1648 Message->Result = 0;
1649 Message->SenderQueue = Win32Thread->MessageQueue;
1650 IntReferenceMessageQueue(Message->SenderQueue);
1651 IntReferenceMessageQueue(Window->pti->MessageQueue);
1652 Message->CompletionCallback = CompletionCallback;
1653 Message->CompletionCallbackContext = CompletionCallbackContext;
1654 Message->HookMessage = MSQ_NORMAL | MSQ_SENTNOWAIT;
1655 Message->HasPackedLParam = (lParamBufferSize > 0);
1656
1657 InsertTailList(&Window->pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
1658 InsertTailList(&Win32Thread->MessageQueue->DispatchingMessagesHead, &Message->DispatchingListEntry);
1659 IntDereferenceMessageQueue(Window->pti->MessageQueue);
1660 IntDereferenceMessageQueue(Message->SenderQueue);
1661
1662 RETURN(TRUE);
1663
1664 CLEANUP:
1665 if (Window) UserDerefObjectCo(Window);
1666 END_CLEANUP;
1667 }
1668
1669 /* This function posts a message if the destination's message queue belongs to
1670 another thread, otherwise it sends the message. It does not support broadcast
1671 messages! */
1672 LRESULT FASTCALL
1673 co_IntPostOrSendMessage( HWND hWnd,
1674 UINT Msg,
1675 WPARAM wParam,
1676 LPARAM lParam )
1677 {
1678 ULONG_PTR Result;
1679 PTHREADINFO pti;
1680 PWINDOW_OBJECT Window;
1681
1682 if ( hWnd == HWND_BROADCAST )
1683 {
1684 return 0;
1685 }
1686
1687 if(!(Window = UserGetWindowObject(hWnd)))
1688 {
1689 return 0;
1690 }
1691
1692 pti = PsGetCurrentThreadWin32Thread();
1693
1694 if ( Window->pti->MessageQueue != pti->MessageQueue &&
1695 FindMsgMemory(Msg) == 0 )
1696 {
1697 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1698 }
1699 else
1700 {
1701 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
1702 {
1703 Result = 0;
1704 }
1705 }
1706
1707 return (LRESULT)Result;
1708 }
1709
1710 LRESULT FASTCALL
1711 co_IntDoSendMessage( HWND hWnd,
1712 UINT Msg,
1713 WPARAM wParam,
1714 LPARAM lParam,
1715 PDOSENDMESSAGE dsm,
1716 PNTUSERSENDMESSAGEINFO UnsafeInfo )
1717 {
1718 PTHREADINFO pti;
1719 LRESULT Result = TRUE;
1720 NTSTATUS Status;
1721 PWINDOW_OBJECT Window = NULL;
1722 NTUSERSENDMESSAGEINFO Info;
1723 MSG UserModeMsg;
1724 MSG KernelModeMsg;
1725 PMSGMEMORY MsgMemoryEntry;
1726
1727 RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));
1728
1729 /* FIXME: Call hooks. */
1730 if (HWND_BROADCAST != hWnd)
1731 {
1732 Window = UserGetWindowObject(hWnd);
1733 if ( !Window || !Window->Wnd )
1734 {
1735 /* Tell usermode to not touch this one */
1736 Info.HandledByKernel = TRUE;
1737 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1738 return 0;
1739 }
1740 }
1741
1742 /* Check for an exiting window. */
1743 if (Window && Window->state & WINDOWSTATUS_DESTROYING)
1744 {
1745 DPRINT1("co_IntDoSendMessage Window Exiting!\n");
1746 }
1747
1748 /* See if the current thread can handle the message */
1749 pti = PsGetCurrentThreadWin32Thread();
1750
1751 // This is checked in user mode!!!!!!!
1752 if ( HWND_BROADCAST != hWnd &&
1753 NULL != pti &&
1754 Window->pti->MessageQueue == pti->MessageQueue &&
1755 !ISITHOOKED(WH_CALLWNDPROC) &&
1756 !ISITHOOKED(WH_CALLWNDPROCRET) &&
1757 ( Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST ) )
1758 {
1759 /* Gather the information usermode needs to call the window proc directly */
1760 Info.HandledByKernel = FALSE;
1761
1762 Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi),
1763 sizeof(BOOL));
1764 if (! NT_SUCCESS(Status))
1765 {
1766 Info.Ansi = ! Window->Wnd->Unicode;
1767 }
1768
1769 Info.Ansi = !Window->Wnd->Unicode;
1770 Info.Proc = Window->Wnd->lpfnWndProc;
1771 }
1772 else
1773 {
1774 /* Must be handled by other thread */
1775 // if (HWND_BROADCAST != hWnd)
1776 // {
1777 // UserDereferenceObject(Window);
1778 // }
1779 Info.HandledByKernel = TRUE;
1780 UserModeMsg.hwnd = hWnd;
1781 UserModeMsg.message = Msg;
1782 UserModeMsg.wParam = wParam;
1783 UserModeMsg.lParam = lParam;
1784 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1785
1786 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1787 if (! NT_SUCCESS(Status))
1788 {
1789 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1790 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1791 return (dsm ? 0 : -1);
1792 }
1793
1794 if(!dsm)
1795 {
1796 Result = co_IntSendMessage( KernelModeMsg.hwnd,
1797 KernelModeMsg.message,
1798 KernelModeMsg.wParam,
1799 KernelModeMsg.lParam );
1800 }
1801 else
1802 {
1803 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1804 KernelModeMsg.message,
1805 KernelModeMsg.wParam,
1806 KernelModeMsg.lParam,
1807 dsm->uFlags,
1808 dsm->uTimeout,
1809 &dsm->Result );
1810 }
1811
1812 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1813 if (! NT_SUCCESS(Status))
1814 {
1815 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1816 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1817 return(dsm ? 0 : -1);
1818 }
1819 }
1820
1821 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1822 if (! NT_SUCCESS(Status))
1823 {
1824 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1825 }
1826
1827 return (LRESULT)Result;
1828 }
1829
1830
1831 BOOL FASTCALL
1832 UserSendNotifyMessage( HWND hWnd,
1833 UINT Msg,
1834 WPARAM wParam,
1835 LPARAM lParam )
1836 {
1837 BOOL Result = TRUE;
1838
1839 if (FindMsgMemory(Msg) != 0)
1840 {
1841 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
1842 return FALSE;
1843 }
1844
1845 // Basicly the same as IntPostOrSendMessage
1846 if (hWnd == HWND_BROADCAST) //Handle Broadcast
1847 {
1848 HWND *List;
1849 PWINDOW_OBJECT DesktopWindow;
1850 ULONG i;
1851
1852 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1853 List = IntWinListChildren(DesktopWindow);
1854
1855 if (List != NULL)
1856 {
1857 for (i = 0; List[i]; i++)
1858 {
1859 UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1860 }
1861 ExFreePool(List);
1862 }
1863 }
1864 else
1865 {
1866 ULONG_PTR PResult;
1867 PTHREADINFO pti;
1868 PWINDOW_OBJECT Window;
1869 MSG Message;
1870
1871 if ( !(Window = UserGetWindowObject(hWnd)) ) return FALSE;
1872
1873 pti = PsGetCurrentThreadWin32Thread();
1874
1875 if (Window->pti->MessageQueue != pti->MessageQueue)
1876 { // Send message w/o waiting for it.
1877 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1878 }
1879 else
1880 { // Handle message and callback.
1881 Message.hwnd = hWnd;
1882 Message.message = Msg;
1883 Message.wParam = wParam;
1884 Message.lParam = lParam;
1885
1886 Result = co_IntSendMessageTimeoutSingle( hWnd,
1887 Msg,
1888 wParam,
1889 lParam,
1890 SMTO_NORMAL,
1891 0,
1892 &PResult );
1893 }
1894 }
1895 return Result;
1896 }
1897
1898
1899 DWORD APIENTRY
1900 IntGetQueueStatus(BOOL ClearChanges)
1901 {
1902 PTHREADINFO pti;
1903 PUSER_MESSAGE_QUEUE Queue;
1904 DWORD Result;
1905 DECLARE_RETURN(DWORD);
1906
1907 DPRINT("Enter IntGetQueueStatus\n");
1908
1909 pti = PsGetCurrentThreadWin32Thread();
1910 Queue = pti->MessageQueue;
1911
1912 Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
1913 if (ClearChanges)
1914 {
1915 Queue->ChangedBits = 0;
1916 }
1917
1918 RETURN(Result);
1919
1920 CLEANUP:
1921 DPRINT("Leave IntGetQueueStatus, ret=%i\n",_ret_);
1922 END_CLEANUP;
1923 }
1924
1925 BOOL APIENTRY
1926 IntInitMessagePumpHook()
1927 {
1928 if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti)
1929 {
1930 ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook++;
1931 return TRUE;
1932 }
1933 return FALSE;
1934 }
1935
1936 BOOL APIENTRY
1937 IntUninitMessagePumpHook()
1938 {
1939 if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti)
1940 {
1941 if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook <= 0)
1942 {
1943 return FALSE;
1944 }
1945 ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook--;
1946 return TRUE;
1947 }
1948 return FALSE;
1949 }
1950
1951 /** Functions ******************************************************************/
1952
1953 BOOL APIENTRY
1954 NtUserPostMessage(HWND hWnd,
1955 UINT Msg,
1956 WPARAM wParam,
1957 LPARAM lParam)
1958 {
1959 DECLARE_RETURN(BOOL);
1960
1961 DPRINT("Enter NtUserPostMessage\n");
1962 UserEnterExclusive();
1963
1964 RETURN( UserPostMessage(hWnd, Msg, wParam, lParam));
1965
1966 CLEANUP:
1967 DPRINT("Leave NtUserPostMessage, ret=%i\n",_ret_);
1968 UserLeave();
1969 END_CLEANUP;
1970 }
1971
1972 BOOL APIENTRY
1973 NtUserPostThreadMessage(DWORD idThread,
1974 UINT Msg,
1975 WPARAM wParam,
1976 LPARAM lParam)
1977 {
1978 DECLARE_RETURN(BOOL);
1979
1980 DPRINT("Enter NtUserPostThreadMessage\n");
1981 UserEnterExclusive();
1982
1983 RETURN( UserPostThreadMessage( idThread,
1984 Msg,
1985 wParam,
1986 lParam));
1987
1988 CLEANUP:
1989 DPRINT("Leave NtUserPostThreadMessage, ret=%i\n",_ret_);
1990 UserLeave();
1991 END_CLEANUP;
1992 }
1993
1994 DWORD APIENTRY
1995 NtUserQuerySendMessage(DWORD Unknown0)
1996 {
1997 UNIMPLEMENTED;
1998
1999 return 0;
2000 }
2001
2002
2003 ////////// API on the way out!
2004 LRESULT APIENTRY
2005 NtUserSendMessageTimeout( HWND hWnd,
2006 UINT Msg,
2007 WPARAM wParam,
2008 LPARAM lParam,
2009 UINT uFlags,
2010 UINT uTimeout,
2011 ULONG_PTR *uResult,
2012 PNTUSERSENDMESSAGEINFO UnsafeInfo )
2013 {
2014 DOSENDMESSAGE dsm;
2015 LRESULT Result;
2016 DECLARE_RETURN(BOOL);
2017
2018 DPRINT("Enter NtUserSendMessageTimeout\n");
2019 UserEnterExclusive();
2020
2021 dsm.uFlags = uFlags;
2022 dsm.uTimeout = uTimeout;
2023 Result = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
2024 if(uResult != NULL && Result != 0)
2025 {
2026 NTSTATUS Status;
2027
2028 Status = MmCopyToCaller(uResult, &dsm.Result, sizeof(ULONG_PTR));
2029 if(!NT_SUCCESS(Status))
2030 {
2031 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2032 RETURN( FALSE);
2033 }
2034 }
2035 RETURN( Result);
2036
2037 CLEANUP:
2038 DPRINT("Leave NtUserSendMessageTimeout, ret=%i\n",_ret_);
2039 UserLeave();
2040 END_CLEANUP;
2041 }
2042
2043 LRESULT APIENTRY
2044 NtUserSendMessage( HWND Wnd,
2045 UINT Msg,
2046 WPARAM wParam,
2047 LPARAM lParam,
2048 PNTUSERSENDMESSAGEINFO UnsafeInfo )
2049 {
2050 DECLARE_RETURN(BOOL);
2051
2052 DPRINT("Enter NtUserSendMessage\n");
2053 UserEnterExclusive();
2054
2055 RETURN(co_IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo));
2056
2057 CLEANUP:
2058 DPRINT("Leave NtUserSendMessage, ret=%i\n",_ret_);
2059 UserLeave();
2060 END_CLEANUP;
2061 }
2062 //////////
2063
2064 BOOL APIENTRY
2065 NtUserWaitMessage(VOID)
2066 {
2067 DECLARE_RETURN(BOOL);
2068
2069 DPRINT("EnterNtUserWaitMessage\n");
2070 UserEnterExclusive();
2071
2072 RETURN(co_IntWaitMessage(NULL, 0, 0));
2073
2074 CLEANUP:
2075 DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_);
2076 UserLeave();
2077 END_CLEANUP;
2078 }
2079
2080
2081 BOOL APIENTRY
2082 NtUserGetMessage( PNTUSERGETMESSAGEINFO UnsafeInfo,
2083 HWND hWnd,
2084 UINT MsgFilterMin,
2085 UINT MsgFilterMax )
2086 /*
2087 * FUNCTION: Get a message from the calling thread's message queue.
2088 * ARGUMENTS:
2089 * UnsafeMsg - Pointer to the structure which receives the returned message.
2090 * Wnd - Window whose messages are to be retrieved.
2091 * MsgFilterMin - Integer value of the lowest message value to be
2092 * retrieved.
2093 * MsgFilterMax - Integer value of the highest message value to be
2094 * retrieved.
2095 */
2096 {
2097 BOOL GotMessage;
2098 NTUSERGETMESSAGEINFO Info;
2099 NTSTATUS Status;
2100 /* FIXME: if initialization is removed, gcc complains that this may be used before initialization. Please review */
2101 PWINDOW_OBJECT Window = NULL;
2102 PMSGMEMORY MsgMemoryEntry;
2103 PVOID UserMem;
2104 UINT Size;
2105 USER_MESSAGE Msg;
2106 DECLARE_RETURN(BOOL);
2107 // USER_REFERENCE_ENTRY Ref;
2108
2109 DPRINT("Enter NtUserGetMessage\n");
2110 UserEnterExclusive();
2111
2112 /* Validate input */
2113 if (hWnd && !(Window = UserGetWindowObject(hWnd)))
2114 {
2115 RETURN(-1);
2116 }
2117
2118 // if (Window) UserRefObjectCo(Window, &Ref);
2119
2120 if (MsgFilterMax < MsgFilterMin)
2121 {
2122 MsgFilterMin = 0;
2123 MsgFilterMax = 0;
2124 }
2125
2126 do
2127 {
2128 GotMessage = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, PM_REMOVE);
2129 if (GotMessage)
2130 {
2131 Info.Msg = Msg.Msg;
2132 /* See if this message type is present in the table */
2133 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
2134 if (NULL == MsgMemoryEntry)
2135 {
2136 /* Not present, no copying needed */
2137 Info.LParamSize = 0;
2138 }
2139 else
2140 {
2141 /* Determine required size */
2142 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
2143 Info.Msg.lParam);
2144 /* Allocate required amount of user-mode memory */
2145 Info.LParamSize = Size;
2146 UserMem = NULL;
2147 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
2148 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
2149
2150 if (! NT_SUCCESS(Status))
2151 {
2152 SetLastNtError(Status);
2153 RETURN( (BOOL) -1);
2154 }
2155 /* Transfer lParam data to user-mode mem */
2156 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
2157 if (! NT_SUCCESS(Status))
2158 {
2159 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
2160 &Info.LParamSize, MEM_DECOMMIT);
2161 SetLastNtError(Status);
2162 RETURN( (BOOL) -1);
2163 }
2164 Info.Msg.lParam = (LPARAM) UserMem;
2165 }
2166 if (Msg.FreeLParam && 0 != Msg.Msg.lParam)
2167 {
2168 ExFreePool((void *) Msg.Msg.lParam);
2169 }
2170 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
2171 if (! NT_SUCCESS(Status))
2172 {
2173 SetLastNtError(Status);
2174 RETURN( (BOOL) -1);
2175 }
2176 }
2177 else if (! co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax))
2178 {
2179 RETURN( (BOOL) -1);
2180 }
2181 }
2182 while (! GotMessage);
2183
2184 RETURN( WM_QUIT != Info.Msg.message);
2185
2186 CLEANUP:
2187 // if (Window) UserDerefObjectCo(Window);
2188
2189 DPRINT("Leave NtUserGetMessage\n");
2190 UserLeave();
2191 END_CLEANUP;
2192 }
2193
2194
2195 BOOL
2196 APIENTRY
2197 NtUserGetMessageX(
2198 PMSG pMsg,
2199 HWND hWnd,
2200 UINT MsgFilterMin,
2201 UINT MsgFilterMax)
2202 {
2203 MSG Msg;
2204 BOOL Ret = FALSE;
2205 DECLARE_RETURN(BOOL);
2206
2207 DPRINT("Enter NtUserGetMessage\n");
2208 UserEnterExclusive();
2209
2210 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
2211 {
2212 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2213 RETURN( Ret);
2214 }
2215
2216 RtlZeroMemory(&Msg, sizeof(MSG));
2217
2218 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
2219
2220 if (Ret)
2221 {
2222 _SEH2_TRY
2223 {
2224 ProbeForWrite(pMsg, sizeof(MSG), 1);
2225 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
2226 }
2227 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2228 {
2229 SetLastNtError(_SEH2_GetExceptionCode());
2230 Ret = FALSE;
2231 }
2232 _SEH2_END;
2233 }
2234 RETURN( Ret);
2235
2236 CLEANUP:
2237 DPRINT("Leave NtUserGetMessage\n");
2238 UserLeave();
2239 END_CLEANUP;
2240 }
2241
2242 BOOL APIENTRY
2243 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
2244 HWND hWnd,
2245 UINT MsgFilterMin,
2246 UINT MsgFilterMax,
2247 UINT RemoveMsg)
2248 {
2249 NTSTATUS Status;
2250 BOOL Present;
2251 NTUSERGETMESSAGEINFO Info;
2252 PWINDOW_OBJECT Window;
2253 PMSGMEMORY MsgMemoryEntry;
2254 PVOID UserMem;
2255 UINT Size;
2256 USER_MESSAGE Msg;
2257 DECLARE_RETURN(BOOL);
2258
2259 DPRINT("Enter NtUserPeekMessage\n");
2260 UserEnterExclusive();
2261
2262 if (hWnd == (HWND)-1 || hWnd == (HWND)0x0000FFFF || hWnd == (HWND)0xFFFFFFFF)
2263 hWnd = (HWND)1;
2264
2265 /* Validate input */
2266 if (hWnd && hWnd != (HWND)1)
2267 {
2268 if (!(Window = UserGetWindowObject(hWnd)))
2269 {
2270 RETURN(-1);
2271 }
2272 }
2273 else
2274 {
2275 Window = (PWINDOW_OBJECT)hWnd;
2276 }
2277
2278 if (MsgFilterMax < MsgFilterMin)
2279 {
2280 MsgFilterMin = 0;
2281 MsgFilterMax = 0;
2282 }
2283
2284 Present = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, RemoveMsg);
2285 if (Present)
2286 {
2287
2288 Info.Msg = Msg.Msg;
2289 /* See if this message type is present in the table */
2290 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
2291 if (NULL == MsgMemoryEntry)
2292 {
2293 /* Not present, no copying needed */
2294 Info.LParamSize = 0;
2295 }
2296 else
2297 {
2298 /* Determine required size */
2299 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
2300 Info.Msg.lParam);
2301 /* Allocate required amount of user-mode memory */
2302 Info.LParamSize = Size;
2303 UserMem = NULL;
2304 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
2305 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
2306 if (! NT_SUCCESS(Status))
2307 {
2308 SetLastNtError(Status);
2309 RETURN( (BOOL) -1);
2310 }
2311 /* Transfer lParam data to user-mode mem */
2312 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
2313 if (! NT_SUCCESS(Status))
2314 {
2315 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
2316 &Info.LParamSize, MEM_RELEASE);
2317 SetLastNtError(Status);
2318 RETURN( (BOOL) -1);
2319 }
2320 Info.Msg.lParam = (LPARAM) UserMem;
2321 }
2322 if (RemoveMsg && Msg.FreeLParam && 0 != Msg.Msg.lParam)
2323 {
2324 ExFreePool((void *) Msg.Msg.lParam);
2325 }
2326 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
2327 if (! NT_SUCCESS(Status))
2328 {
2329 SetLastNtError(Status);
2330 RETURN( (BOOL) -1);
2331 }
2332 }
2333
2334 RETURN( Present);
2335
2336 CLEANUP:
2337 DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_);
2338 UserLeave();
2339 END_CLEANUP;
2340 }
2341
2342 BOOL
2343 APIENTRY
2344 NtUserPeekMessageX(
2345 PMSG pMsg,
2346 HWND hWnd,
2347 UINT MsgFilterMin,
2348 UINT MsgFilterMax,
2349 UINT RemoveMsg)
2350 {
2351 MSG Msg;
2352 BOOL Ret = FALSE;
2353 DECLARE_RETURN(BOOL);
2354
2355 DPRINT("Enter NtUserPeekMessage\n");
2356 UserEnterExclusive();
2357
2358 if ( RemoveMsg & PM_BADMSGFLAGS )
2359 {
2360 SetLastWin32Error(ERROR_INVALID_FLAGS);
2361 RETURN( Ret);
2362 }
2363
2364 RtlZeroMemory(&Msg, sizeof(MSG));
2365
2366 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
2367
2368 if (Ret)
2369 {
2370 _SEH2_TRY
2371 {
2372 ProbeForWrite(pMsg, sizeof(MSG), 1);
2373 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
2374 }
2375 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2376 {
2377 SetLastNtError(_SEH2_GetExceptionCode());
2378 Ret = FALSE;
2379 }
2380 _SEH2_END;
2381 }
2382 RETURN( Ret);
2383
2384 CLEANUP:
2385 DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_);
2386 UserLeave();
2387 END_CLEANUP;
2388 }
2389
2390 BOOL
2391 APIENTRY
2392 NtUserCallMsgFilter(
2393 LPMSG lpmsg,
2394 INT code)
2395 {
2396 BOOL BadChk = FALSE, Ret = FALSE;
2397 MSG Msg;
2398 DECLARE_RETURN(BOOL);
2399
2400 DPRINT("Enter NtUserCallMsgFilter\n");
2401 UserEnterExclusive();
2402 if (lpmsg)
2403 {
2404 _SEH2_TRY
2405 {
2406 ProbeForRead((PVOID)lpmsg,
2407 sizeof(MSG),
2408 1);
2409 RtlCopyMemory( &Msg,
2410 (PVOID)lpmsg,
2411 sizeof(MSG));
2412 }
2413 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2414 {
2415 BadChk = TRUE;
2416 }
2417 _SEH2_END;
2418 }
2419 else
2420 RETURN( FALSE);
2421
2422 if (BadChk) RETURN( FALSE);
2423
2424 if ( ISITHOOKED(WH_SYSMSGFILTER) &&
2425 co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
2426 {
2427 Ret = TRUE;
2428 }
2429 else
2430 {
2431 if ( ISITHOOKED(WH_MSGFILTER) )
2432 {
2433 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
2434 }
2435 }
2436
2437 _SEH2_TRY
2438 {
2439 ProbeForWrite((PVOID)lpmsg,
2440 sizeof(MSG),
2441 1);
2442 RtlCopyMemory((PVOID)lpmsg,
2443 &Msg,
2444 sizeof(MSG));
2445 }
2446 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2447 {
2448 BadChk = TRUE;
2449 }
2450 _SEH2_END;
2451 if (BadChk) RETURN( FALSE);
2452 RETURN( Ret)
2453
2454 CLEANUP:
2455 DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_);
2456 UserLeave();
2457 END_CLEANUP;
2458 }
2459
2460 LRESULT APIENTRY
2461 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
2462 {
2463 LRESULT Res = 0;
2464 BOOL Hit = FALSE;
2465 MSG SafeMsg;
2466
2467 UserEnterExclusive();
2468 _SEH2_TRY
2469 {
2470 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
2471 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
2472 }
2473 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2474 {
2475 SetLastNtError(_SEH2_GetExceptionCode());
2476 Hit = TRUE;
2477 }
2478 _SEH2_END;
2479
2480 if (!Hit) Res = IntDispatchMessage(&SafeMsg);
2481
2482 UserLeave();
2483 return Res;
2484 }
2485
2486
2487 BOOL APIENTRY
2488 NtUserTranslateMessage(LPMSG lpMsg,
2489 UINT flags)
2490 {
2491 NTSTATUS Status;
2492 MSG SafeMsg;
2493 DECLARE_RETURN(BOOL);
2494
2495 DPRINT("Enter NtUserTranslateMessage\n");
2496 UserEnterExclusive();
2497
2498 Status = MmCopyFromCaller(&SafeMsg, lpMsg, sizeof(MSG));
2499 if(!NT_SUCCESS(Status))
2500 {
2501 SetLastNtError(Status);
2502 RETURN( FALSE);
2503 }
2504
2505 RETURN( IntTranslateKbdMessage(&SafeMsg, flags));
2506
2507 CLEANUP:
2508 DPRINT("Leave NtUserTranslateMessage: ret=%i\n",_ret_);
2509 UserLeave();
2510 END_CLEANUP;
2511 }
2512
2513 BOOL APIENTRY
2514 NtUserMessageCall(
2515 HWND hWnd,
2516 UINT Msg,
2517 WPARAM wParam,
2518 LPARAM lParam,
2519 ULONG_PTR ResultInfo,
2520 DWORD dwType, // fnID?
2521 BOOL Ansi)
2522 {
2523 LRESULT lResult = 0;
2524 BOOL Ret = FALSE;
2525 BOOL BadChk = FALSE;
2526 PWINDOW_OBJECT Window = NULL;
2527 USER_REFERENCE_ENTRY Ref;
2528
2529 UserEnterExclusive();
2530
2531 /* Validate input */
2532 if (hWnd && (hWnd != INVALID_HANDLE_VALUE) && !(Window = UserGetWindowObject(hWnd)))
2533 {
2534 UserLeave();
2535 return FALSE;
2536 }
2537 switch(dwType)
2538 {
2539 case FNID_DEFWINDOWPROC:
2540 UserRefObjectCo(Window, &Ref);
2541 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2542 Ret = TRUE;
2543 UserDerefObjectCo(Window);
2544 break;
2545 case FNID_SENDNOTIFYMESSAGE:
2546 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
2547 break;
2548 case FNID_BROADCASTSYSTEMMESSAGE:
2549 {
2550 BROADCASTPARM parm;
2551 DWORD_PTR RetVal = 0;
2552
2553 if (ResultInfo)
2554 {
2555 _SEH2_TRY
2556 {
2557 ProbeForWrite((PVOID)ResultInfo,
2558 sizeof(BROADCASTPARM),
2559 1);
2560 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
2561 }
2562 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2563 {
2564 BadChk = TRUE;
2565 }
2566 _SEH2_END;
2567 if (BadChk) break;
2568 }
2569 else
2570 break;
2571
2572 if ( parm.recipients & BSM_ALLDESKTOPS ||
2573 parm.recipients == BSM_ALLCOMPONENTS )
2574 {
2575 }
2576 else if (parm.recipients & BSM_APPLICATIONS)
2577 {
2578 if (parm.flags & BSF_QUERY)
2579 {
2580 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2581 {
2582 co_IntSendMessageTimeout( HWND_BROADCAST,
2583 Msg,
2584 wParam,
2585 lParam,
2586 SMTO_ABORTIFHUNG,
2587 2000,
2588 &RetVal);
2589 }
2590 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2591 {
2592 co_IntSendMessageTimeout( HWND_BROADCAST,
2593 Msg,
2594 wParam,
2595 lParam,
2596 SMTO_NOTIMEOUTIFNOTHUNG,
2597 2000,
2598 &RetVal);
2599 }
2600 else
2601 {
2602 co_IntSendMessageTimeout( HWND_BROADCAST,
2603 Msg,
2604 wParam,
2605 lParam,
2606 SMTO_NORMAL,
2607 2000,
2608 &RetVal);
2609 }
2610 }
2611 else if (parm.flags & BSF_POSTMESSAGE)
2612 {
2613 Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
2614 }
2615 else if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
2616 {
2617 Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
2618 }
2619 }
2620 }
2621 break;
2622 case FNID_SENDMESSAGECALLBACK:
2623 {
2624 PCALL_BACK_INFO CallBackInfo = (PCALL_BACK_INFO)ResultInfo;
2625
2626 if (!CallBackInfo)
2627 break;
2628
2629 if (!co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
2630 CallBackInfo->CallBack, CallBackInfo->Context, NULL))
2631 {
2632 DPRINT1("Callback failure!\n");
2633 }
2634 }
2635 break;
2636 // CallNextHook bypass.
2637 case FNID_CALLWNDPROC:
2638 case FNID_CALLWNDPROCRET:
2639 {
2640 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
2641 PHOOK NextObj, Hook = ClientInfo->phkCurrent;
2642
2643 if (!ClientInfo || !Hook) break;
2644
2645 UserReferenceObject(Hook);
2646
2647 if (Hook->Thread && (Hook->Thread != PsGetCurrentThread()))
2648 {
2649 UserDereferenceObject(Hook);
2650 break;
2651 }
2652
2653 NextObj = IntGetNextHook(Hook);
2654 ClientInfo->phkCurrent = NextObj;
2655
2656 if ( Hook->HookId == WH_CALLWNDPROC)
2657 {
2658 CWPSTRUCT CWP;
2659 CWP.hwnd = hWnd;
2660 CWP.message = Msg;
2661 CWP.wParam = wParam;
2662 CWP.lParam = lParam;
2663 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
2664
2665 lResult = co_IntCallHookProc( Hook->HookId,
2666 HC_ACTION,
2667 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2668 (LPARAM)&CWP,
2669 Hook->Proc,
2670 Hook->Ansi,
2671 &Hook->ModuleName);
2672 }
2673 else
2674 {
2675 CWPRETSTRUCT CWPR;
2676 CWPR.hwnd = hWnd;
2677 CWPR.message = Msg;
2678 CWPR.wParam = wParam;
2679 CWPR.lParam = lParam;
2680 CWPR.lResult = ClientInfo->dwHookData;
2681
2682 lResult = co_IntCallHookProc( Hook->HookId,
2683 HC_ACTION,
2684 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2685 (LPARAM)&CWPR,
2686 Hook->Proc,
2687 Hook->Ansi,
2688 &Hook->ModuleName);
2689 }
2690 UserDereferenceObject(Hook);
2691 lResult = (LRESULT) NextObj;
2692 }
2693 break;
2694 }
2695
2696 switch(dwType)
2697 {
2698 case FNID_DEFWINDOWPROC:
2699 case FNID_CALLWNDPROC:
2700 case FNID_CALLWNDPROCRET:
2701 if (ResultInfo)
2702 {
2703 _SEH2_TRY
2704 {
2705 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2706 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2707 }
2708 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2709 {
2710 BadChk = TRUE;
2711 }
2712 _SEH2_END;
2713 }
2714 break;
2715 default:
2716 break;
2717 }
2718
2719 UserLeave();
2720
2721 return BadChk ? FALSE : Ret;
2722 }
2723
2724 #define INFINITE 0xFFFFFFFF
2725 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2726
2727 DWORD
2728 APIENTRY
2729 NtUserWaitForInputIdle(
2730 IN HANDLE hProcess,
2731 IN DWORD dwMilliseconds,
2732 IN BOOL Unknown2)
2733 {
2734 PEPROCESS Process;
2735 PPROCESSINFO W32Process;
2736 NTSTATUS Status;
2737 HANDLE Handles[2];
2738 LARGE_INTEGER Timeout;
2739 ULONGLONG StartTime, Run, Elapsed = 0;
2740
2741 UserEnterExclusive();
2742
2743 Status = ObReferenceObjectByHandle(hProcess,
2744 PROCESS_QUERY_INFORMATION,
2745 PsProcessType,
2746 UserMode,
2747 (PVOID*)&Process,
2748 NULL);
2749
2750 if (!NT_SUCCESS(Status))
2751 {
2752 UserLeave();
2753 SetLastNtError(Status);
2754 return WAIT_FAILED;
2755 }
2756
2757 W32Process = (PPROCESSINFO)Process->Win32Process;
2758 if (!W32Process)
2759 {
2760 ObDereferenceObject(Process);
2761 UserLeave();
2762 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2763 return WAIT_FAILED;
2764 }
2765
2766 EngCreateEvent((PEVENT *)&W32Process->InputIdleEvent);
2767
2768 Handles[0] = Process;
2769 Handles[1] = W32Process->InputIdleEvent;
2770
2771 if (!Handles[1])
2772 {
2773 ObDereferenceObject(Process);
2774 UserLeave();
2775 return STATUS_SUCCESS; /* no event to wait on */
2776 }
2777
2778 StartTime = EngGetTickCount();
2779
2780 Run = dwMilliseconds;
2781
2782 DPRINT("WFII: waiting for %p\n", Handles[1] );
2783 do
2784 {
2785 Timeout.QuadPart = Run - Elapsed;
2786 UserLeave();
2787 Status = KeWaitForMultipleObjects( 2,
2788 Handles,
2789 WaitAny,
2790 UserRequest,
2791 UserMode,
2792 FALSE,
2793 dwMilliseconds == INFINITE ? NULL : &Timeout,
2794 NULL);
2795 UserEnterExclusive();
2796
2797 if (!NT_SUCCESS(Status))
2798 {
2799 SetLastNtError(Status);
2800 Status = WAIT_FAILED;
2801 goto WaitExit;
2802 }
2803
2804 switch (Status)
2805 {
2806 case STATUS_WAIT_0:
2807 Status = WAIT_FAILED;
2808 goto WaitExit;
2809
2810 case STATUS_WAIT_2:
2811 {
2812 USER_MESSAGE Msg;
2813 co_IntPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE );
2814 break;
2815 }
2816
2817 case STATUS_USER_APC:
2818 case STATUS_ALERTED:
2819 case STATUS_TIMEOUT:
2820 DPRINT1("WFII: timeout\n");
2821 Status = STATUS_TIMEOUT;
2822 goto WaitExit;
2823
2824 default:
2825 DPRINT1("WFII: finished\n");
2826 Status = STATUS_SUCCESS;
2827 goto WaitExit;
2828 }
2829
2830 if (dwMilliseconds != INFINITE)
2831 {
2832 Elapsed = EngGetTickCount() - StartTime;
2833
2834 if (Elapsed > Run)
2835 Status = STATUS_TIMEOUT;
2836 break;
2837 }
2838 }
2839 while (1);
2840
2841 WaitExit:
2842 if (W32Process->InputIdleEvent)
2843 {
2844 EngFreeMem((PVOID)W32Process->InputIdleEvent);
2845 W32Process->InputIdleEvent = NULL;
2846 }
2847 ObDereferenceObject(Process);
2848 UserLeave();
2849 return Status;
2850 }
2851
2852 /* EOF */