[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(),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 = NULL; //Win32Thread->MessageQueue;
1650
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 IntDereferenceMessageQueue(Window->pti->MessageQueue);
1659
1660 RETURN(TRUE);
1661
1662 CLEANUP:
1663 if (Window) UserDerefObjectCo(Window);
1664 END_CLEANUP;
1665 }
1666
1667 /* This function posts a message if the destination's message queue belongs to
1668 another thread, otherwise it sends the message. It does not support broadcast
1669 messages! */
1670 LRESULT FASTCALL
1671 co_IntPostOrSendMessage( HWND hWnd,
1672 UINT Msg,
1673 WPARAM wParam,
1674 LPARAM lParam )
1675 {
1676 ULONG_PTR Result;
1677 PTHREADINFO pti;
1678 PWINDOW_OBJECT Window;
1679
1680 if ( hWnd == HWND_BROADCAST )
1681 {
1682 return 0;
1683 }
1684
1685 if(!(Window = UserGetWindowObject(hWnd)))
1686 {
1687 return 0;
1688 }
1689
1690 pti = PsGetCurrentThreadWin32Thread();
1691
1692 if ( Window->pti->MessageQueue != pti->MessageQueue &&
1693 FindMsgMemory(Msg) == 0 )
1694 {
1695 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1696 }
1697 else
1698 {
1699 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
1700 {
1701 Result = 0;
1702 }
1703 }
1704
1705 return (LRESULT)Result;
1706 }
1707
1708 LRESULT FASTCALL
1709 co_IntDoSendMessage( HWND hWnd,
1710 UINT Msg,
1711 WPARAM wParam,
1712 LPARAM lParam,
1713 PDOSENDMESSAGE dsm,
1714 PNTUSERSENDMESSAGEINFO UnsafeInfo )
1715 {
1716 PTHREADINFO pti;
1717 LRESULT Result = TRUE;
1718 NTSTATUS Status;
1719 PWINDOW_OBJECT Window = NULL;
1720 NTUSERSENDMESSAGEINFO Info;
1721 MSG UserModeMsg;
1722 MSG KernelModeMsg;
1723 PMSGMEMORY MsgMemoryEntry;
1724
1725 RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));
1726
1727 /* FIXME: Call hooks. */
1728 if (HWND_BROADCAST != hWnd)
1729 {
1730 Window = UserGetWindowObject(hWnd);
1731 if ( !Window || !Window->Wnd )
1732 {
1733 /* Tell usermode to not touch this one */
1734 Info.HandledByKernel = TRUE;
1735 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1736 return 0;
1737 }
1738 }
1739
1740 /* Check for an exiting window. */
1741 if (Window && Window->state & WINDOWSTATUS_DESTROYING)
1742 {
1743 DPRINT1("co_IntDoSendMessage Window Exiting!\n");
1744 }
1745
1746 /* See if the current thread can handle the message */
1747 pti = PsGetCurrentThreadWin32Thread();
1748
1749 // This is checked in user mode!!!!!!!
1750 if ( HWND_BROADCAST != hWnd &&
1751 NULL != pti &&
1752 Window->pti->MessageQueue == pti->MessageQueue &&
1753 !ISITHOOKED(WH_CALLWNDPROC) &&
1754 !ISITHOOKED(WH_CALLWNDPROCRET) &&
1755 ( Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST ) )
1756 {
1757 /* Gather the information usermode needs to call the window proc directly */
1758 Info.HandledByKernel = FALSE;
1759
1760 Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi),
1761 sizeof(BOOL));
1762 if (! NT_SUCCESS(Status))
1763 {
1764 Info.Ansi = ! Window->Wnd->Unicode;
1765 }
1766
1767 Info.Ansi = !Window->Wnd->Unicode;
1768 Info.Proc = Window->Wnd->lpfnWndProc;
1769 }
1770 else
1771 {
1772 /* Must be handled by other thread */
1773 // if (HWND_BROADCAST != hWnd)
1774 // {
1775 // UserDereferenceObject(Window);
1776 // }
1777 Info.HandledByKernel = TRUE;
1778 UserModeMsg.hwnd = hWnd;
1779 UserModeMsg.message = Msg;
1780 UserModeMsg.wParam = wParam;
1781 UserModeMsg.lParam = lParam;
1782 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1783
1784 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1785 if (! NT_SUCCESS(Status))
1786 {
1787 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1788 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1789 return (dsm ? 0 : -1);
1790 }
1791
1792 if(!dsm)
1793 {
1794 Result = co_IntSendMessage( KernelModeMsg.hwnd,
1795 KernelModeMsg.message,
1796 KernelModeMsg.wParam,
1797 KernelModeMsg.lParam );
1798 }
1799 else
1800 {
1801 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1802 KernelModeMsg.message,
1803 KernelModeMsg.wParam,
1804 KernelModeMsg.lParam,
1805 dsm->uFlags,
1806 dsm->uTimeout,
1807 &dsm->Result );
1808 }
1809
1810 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1811 if (! NT_SUCCESS(Status))
1812 {
1813 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1814 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1815 return(dsm ? 0 : -1);
1816 }
1817 }
1818
1819 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1820 if (! NT_SUCCESS(Status))
1821 {
1822 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1823 }
1824
1825 return (LRESULT)Result;
1826 }
1827
1828
1829 BOOL FASTCALL
1830 UserSendNotifyMessage( HWND hWnd,
1831 UINT Msg,
1832 WPARAM wParam,
1833 LPARAM lParam )
1834 {
1835 BOOL Result = TRUE;
1836
1837 if (FindMsgMemory(Msg) != 0)
1838 {
1839 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
1840 return FALSE;
1841 }
1842
1843 // Basicly the same as IntPostOrSendMessage
1844 if (hWnd == HWND_BROADCAST) //Handle Broadcast
1845 {
1846 HWND *List;
1847 PWINDOW_OBJECT DesktopWindow;
1848 ULONG i;
1849
1850 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1851 List = IntWinListChildren(DesktopWindow);
1852
1853 if (List != NULL)
1854 {
1855 for (i = 0; List[i]; i++)
1856 {
1857 UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1858 }
1859 ExFreePool(List);
1860 }
1861 }
1862 else
1863 {
1864 ULONG_PTR PResult;
1865 PTHREADINFO pti;
1866 PWINDOW_OBJECT Window;
1867 MSG Message;
1868
1869 if ( !(Window = UserGetWindowObject(hWnd)) ) return FALSE;
1870
1871 pti = PsGetCurrentThreadWin32Thread();
1872
1873 if (Window->pti->MessageQueue != pti->MessageQueue)
1874 { // Send message w/o waiting for it.
1875 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1876 }
1877 else
1878 { // Handle message and callback.
1879 Message.hwnd = hWnd;
1880 Message.message = Msg;
1881 Message.wParam = wParam;
1882 Message.lParam = lParam;
1883
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 */