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