[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: subsystems/win32/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 BOOLEAN NTAPI PsGetProcessExitProcessCalled(PEPROCESS Process);
19
20 #define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE)
21
22 /* FUNCTIONS *****************************************************************/
23
24 NTSTATUS FASTCALL
25 IntInitMessageImpl(VOID)
26 {
27 return STATUS_SUCCESS;
28 }
29
30 NTSTATUS FASTCALL
31 IntCleanupMessageImpl(VOID)
32 {
33 return STATUS_SUCCESS;
34 }
35
36 #define MMS_SIZE_WPARAM -1
37 #define MMS_SIZE_WPARAMWCHAR -2
38 #define MMS_SIZE_LPARAMSZ -3
39 #define MMS_SIZE_SPECIAL -4
40 #define MMS_FLAG_READ 0x01
41 #define MMS_FLAG_WRITE 0x02
42 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
43 typedef struct tagMSGMEMORY
44 {
45 UINT Message;
46 UINT Size;
47 INT Flags;
48 }
49 MSGMEMORY, *PMSGMEMORY;
50
51 static MSGMEMORY MsgMemory[] =
52 {
53 { WM_CREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
54 { WM_DDE_ACK, sizeof(KMDDELPARAM), MMS_FLAG_READ },
55 { WM_DDE_EXECUTE, MMS_SIZE_WPARAM, MMS_FLAG_READ },
56 { WM_GETMINMAXINFO, sizeof(MINMAXINFO), MMS_FLAG_READWRITE },
57 { WM_GETTEXT, MMS_SIZE_WPARAMWCHAR, MMS_FLAG_WRITE },
58 { WM_NCCALCSIZE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
59 { WM_NCCREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
60 { WM_SETTEXT, MMS_SIZE_LPARAMSZ, MMS_FLAG_READ },
61 { WM_STYLECHANGED, sizeof(STYLESTRUCT), MMS_FLAG_READ },
62 { WM_STYLECHANGING, sizeof(STYLESTRUCT), MMS_FLAG_READWRITE },
63 { WM_COPYDATA, MMS_SIZE_SPECIAL, MMS_FLAG_READ },
64 { WM_COPYGLOBALDATA, MMS_SIZE_WPARAM, MMS_FLAG_READ },
65 { WM_WINDOWPOSCHANGED, sizeof(WINDOWPOS), MMS_FLAG_READ },
66 { WM_WINDOWPOSCHANGING, sizeof(WINDOWPOS), MMS_FLAG_READWRITE },
67 };
68
69 static PMSGMEMORY FASTCALL
70 FindMsgMemory(UINT Msg)
71 {
72 PMSGMEMORY MsgMemoryEntry;
73
74 /* See if this message type is present in the table */
75 for (MsgMemoryEntry = MsgMemory;
76 MsgMemoryEntry < MsgMemory + sizeof(MsgMemory) / sizeof(MSGMEMORY);
77 MsgMemoryEntry++)
78 {
79 if (Msg == MsgMemoryEntry->Message)
80 {
81 return MsgMemoryEntry;
82 }
83 }
84
85 return NULL;
86 }
87
88 static UINT FASTCALL
89 MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
90 {
91 CREATESTRUCTW *Cs;
92 PUNICODE_STRING WindowName;
93 PUNICODE_STRING ClassName;
94 UINT Size = 0;
95
96 _SEH2_TRY
97 {
98 if (MMS_SIZE_WPARAM == MsgMemoryEntry->Size)
99 {
100 Size = (UINT)wParam;
101 }
102 else if (MMS_SIZE_WPARAMWCHAR == MsgMemoryEntry->Size)
103 {
104 Size = (UINT) (wParam * sizeof(WCHAR));
105 }
106 else if (MMS_SIZE_LPARAMSZ == MsgMemoryEntry->Size)
107 {
108 Size = (UINT) ((wcslen((PWSTR) lParam) + 1) * sizeof(WCHAR));
109 }
110 else if (MMS_SIZE_SPECIAL == MsgMemoryEntry->Size)
111 {
112 switch(MsgMemoryEntry->Message)
113 {
114 case WM_CREATE:
115 case WM_NCCREATE:
116 Cs = (CREATESTRUCTW *) lParam;
117 WindowName = (PUNICODE_STRING) Cs->lpszName;
118 ClassName = (PUNICODE_STRING) Cs->lpszClass;
119 Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
120 if (IS_ATOM(ClassName->Buffer))
121 {
122 Size += sizeof(WCHAR) + sizeof(ATOM);
123 }
124 else
125 {
126 Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
127 }
128 break;
129
130 case WM_NCCALCSIZE:
131 Size = wParam ? sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS) : sizeof(RECT);
132 break;
133
134 case WM_COPYDATA:
135 Size = sizeof(COPYDATASTRUCT) + ((PCOPYDATASTRUCT)lParam)->cbData;
136 break;
137
138 default:
139 ASSERT(FALSE);
140 Size = 0;
141 break;
142 }
143 }
144 else
145 {
146 Size = MsgMemoryEntry->Size;
147 }
148 }
149 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
150 {
151 DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode());
152 Size = 0;
153 }
154 _SEH2_END;
155 return Size;
156 }
157
158 static NTSTATUS
159 PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolNeeded)
160 {
161 NCCALCSIZE_PARAMS *UnpackedNcCalcsize;
162 NCCALCSIZE_PARAMS *PackedNcCalcsize;
163 CREATESTRUCTW *UnpackedCs;
164 CREATESTRUCTW *PackedCs;
165 PLARGE_STRING WindowName;
166 PUNICODE_STRING ClassName;
167 POOL_TYPE PoolType;
168 UINT Size;
169 PCHAR CsData;
170
171 *lParamPacked = lParam;
172
173 if (NonPagedPoolNeeded)
174 PoolType = NonPagedPool;
175 else
176 PoolType = PagedPool;
177
178 if (WM_NCCALCSIZE == Msg && wParam)
179 {
180
181 UnpackedNcCalcsize = (NCCALCSIZE_PARAMS *) lParam;
182 PackedNcCalcsize = ExAllocatePoolWithTag(PoolType,
183 sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS),
184 TAG_MSG);
185
186 if (NULL == PackedNcCalcsize)
187 {
188 DPRINT1("Not enough memory to pack lParam\n");
189 return STATUS_NO_MEMORY;
190 }
191 RtlCopyMemory(PackedNcCalcsize, UnpackedNcCalcsize, sizeof(NCCALCSIZE_PARAMS));
192 PackedNcCalcsize->lppos = (PWINDOWPOS) (PackedNcCalcsize + 1);
193 RtlCopyMemory(PackedNcCalcsize->lppos, UnpackedNcCalcsize->lppos, sizeof(WINDOWPOS));
194 *lParamPacked = (LPARAM) PackedNcCalcsize;
195 }
196 else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
197 {
198 UnpackedCs = (CREATESTRUCTW *) lParam;
199 WindowName = (PLARGE_STRING) UnpackedCs->lpszName;
200 ClassName = (PUNICODE_STRING) UnpackedCs->lpszClass;
201 Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
202 if (IS_ATOM(ClassName->Buffer))
203 {
204 Size += sizeof(WCHAR) + sizeof(ATOM);
205 }
206 else
207 {
208 Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
209 }
210 PackedCs = ExAllocatePoolWithTag(PoolType, Size, TAG_MSG);
211 if (NULL == PackedCs)
212 {
213 DPRINT1("Not enough memory to pack lParam\n");
214 return STATUS_NO_MEMORY;
215 }
216 RtlCopyMemory(PackedCs, UnpackedCs, sizeof(CREATESTRUCTW));
217 CsData = (PCHAR) (PackedCs + 1);
218 PackedCs->lpszName = (LPCWSTR) (CsData - (PCHAR) PackedCs);
219 RtlCopyMemory(CsData, WindowName->Buffer, WindowName->Length);
220 CsData += WindowName->Length;
221 *((WCHAR *) CsData) = L'\0';
222 CsData += sizeof(WCHAR);
223 PackedCs->lpszClass = (LPCWSTR) (CsData - (PCHAR) PackedCs);
224 if (IS_ATOM(ClassName->Buffer))
225 {
226 *((WCHAR *) CsData) = L'A';
227 CsData += sizeof(WCHAR);
228 *((ATOM *) CsData) = (ATOM)(DWORD_PTR) ClassName->Buffer;
229 CsData += sizeof(ATOM);
230 }
231 else
232 {
233 *((WCHAR *) CsData) = L'S';
234 CsData += sizeof(WCHAR);
235 RtlCopyMemory(CsData, ClassName->Buffer, ClassName->Length);
236 CsData += ClassName->Length;
237 *((WCHAR *) CsData) = L'\0';
238 CsData += sizeof(WCHAR);
239 }
240 ASSERT(CsData == (PCHAR) PackedCs + Size);
241 *lParamPacked = (LPARAM) PackedCs;
242 }
243 else if (PoolType == NonPagedPool)
244 {
245 PMSGMEMORY MsgMemoryEntry;
246 PVOID PackedData;
247
248 MsgMemoryEntry = FindMsgMemory(Msg);
249
250 if ((!MsgMemoryEntry) || (MsgMemoryEntry->Size < 0))
251 {
252 /* Keep previous behavior */
253 return STATUS_SUCCESS;
254 }
255 PackedData = ExAllocatePoolWithTag(NonPagedPool, MsgMemorySize(MsgMemoryEntry, wParam, lParam), TAG_MSG);
256 RtlCopyMemory(PackedData, (PVOID)lParam, MsgMemorySize(MsgMemoryEntry, wParam, lParam));
257 *lParamPacked = (LPARAM)PackedData;
258 }
259
260 return STATUS_SUCCESS;
261 }
262
263 static NTSTATUS
264 UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolUsed)
265 {
266 NCCALCSIZE_PARAMS *UnpackedParams;
267 NCCALCSIZE_PARAMS *PackedParams;
268 PWINDOWPOS UnpackedWindowPos;
269
270 if (lParamPacked == lParam)
271 {
272 return STATUS_SUCCESS;
273 }
274
275 if (WM_NCCALCSIZE == Msg && wParam)
276 {
277 PackedParams = (NCCALCSIZE_PARAMS *) lParamPacked;
278 UnpackedParams = (NCCALCSIZE_PARAMS *) lParam;
279 UnpackedWindowPos = UnpackedParams->lppos;
280 RtlCopyMemory(UnpackedParams, PackedParams, sizeof(NCCALCSIZE_PARAMS));
281 UnpackedParams->lppos = UnpackedWindowPos;
282 RtlCopyMemory(UnpackedWindowPos, PackedParams + 1, sizeof(WINDOWPOS));
283 ExFreePool((PVOID) lParamPacked);
284
285 return STATUS_SUCCESS;
286 }
287 else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
288 {
289 ExFreePool((PVOID) lParamPacked);
290
291 return STATUS_SUCCESS;
292 }
293 else if (NonPagedPoolUsed)
294 {
295 PMSGMEMORY MsgMemoryEntry;
296 MsgMemoryEntry = FindMsgMemory(Msg);
297 if (MsgMemoryEntry->Size < 0)
298 {
299 /* Keep previous behavior */
300 return STATUS_INVALID_PARAMETER;
301 }
302
303 if (MsgMemory->Flags == MMS_FLAG_READWRITE)
304 {
305 //RtlCopyMemory((PVOID)lParam, (PVOID)lParamPacked, MsgMemory->Size);
306 }
307 ExFreePool((PVOID) lParamPacked);
308 return STATUS_SUCCESS;
309 }
310
311 ASSERT(FALSE);
312
313 return STATUS_INVALID_PARAMETER;
314 }
315
316 static NTSTATUS FASTCALL
317 CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
318 {
319 NTSTATUS Status;
320
321 PVOID KernelMem;
322 UINT Size;
323
324 *KernelModeMsg = *UserModeMsg;
325
326 /* See if this message type is present in the table */
327 if (NULL == MsgMemoryEntry)
328 {
329 /* Not present, no copying needed */
330 return STATUS_SUCCESS;
331 }
332
333 /* Determine required size */
334 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
335
336 if (0 != Size)
337 {
338 /* Allocate kernel mem */
339 KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
340 if (NULL == KernelMem)
341 {
342 DPRINT1("Not enough memory to copy message to kernel mem\n");
343 return STATUS_NO_MEMORY;
344 }
345 KernelModeMsg->lParam = (LPARAM) KernelMem;
346
347 /* Copy data if required */
348 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
349 {
350 Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
351 if (! NT_SUCCESS(Status))
352 {
353 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
354 ExFreePoolWithTag(KernelMem, TAG_MSG);
355 return Status;
356 }
357 }
358 else
359 {
360 /* Make sure we don't pass any secrets to usermode */
361 RtlZeroMemory(KernelMem, Size);
362 }
363 }
364 else
365 {
366 KernelModeMsg->lParam = 0;
367 }
368
369 return STATUS_SUCCESS;
370 }
371
372 static NTSTATUS FASTCALL
373 CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
374 {
375 NTSTATUS Status;
376 PMSGMEMORY MsgMemoryEntry;
377 UINT Size;
378
379 /* See if this message type is present in the table */
380 MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
381 if (NULL == MsgMemoryEntry)
382 {
383 /* Not present, no copying needed */
384 return STATUS_SUCCESS;
385 }
386
387 /* Determine required size */
388 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
389
390 if (0 != Size)
391 {
392 /* Copy data if required */
393 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
394 {
395 Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
396 if (! NT_SUCCESS(Status))
397 {
398 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
399 ExFreePool((PVOID) KernelModeMsg->lParam);
400 return Status;
401 }
402 }
403
404 ExFreePool((PVOID) KernelModeMsg->lParam);
405 }
406
407 return STATUS_SUCCESS;
408 }
409
410 //
411 // Wakeup any thread/process waiting on idle input.
412 //
413 VOID FASTCALL
414 IdlePing(VOID)
415 {
416 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
417 PUSER_MESSAGE_QUEUE ForegroundQueue;
418 PTHREADINFO pti, ptiForeground = NULL;
419
420 ForegroundQueue = IntGetFocusMessageQueue();
421
422 if (ForegroundQueue)
423 ptiForeground = ForegroundQueue->Thread->Tcb.Win32Thread;
424
425 pti = PsGetCurrentThreadWin32Thread();
426
427 if ( pti )
428 {
429 pti->pClientInfo->cSpins = 0; // Reset spins.
430
431 if ( pti->pDeskInfo && pti == ptiForeground )
432 {
433 if ( pti->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) ||
434 pti->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) )
435 {
436 co_HOOK_CallHooks(WH_FOREGROUNDIDLE,HC_ACTION,0,0);
437 }
438 }
439 }
440
441 DPRINT("IdlePing ppi 0x%x\n",ppi);
442 if ( ppi && ppi->InputIdleEvent )
443 {
444 DPRINT("InputIdleEvent\n");
445 KeSetEvent( ppi->InputIdleEvent, IO_NO_INCREMENT, FALSE);
446 }
447 }
448
449 VOID FASTCALL
450 IdlePong(VOID)
451 {
452 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
453
454 DPRINT("IdlePong ppi 0x%x\n",ppi);
455 if ( ppi && ppi->InputIdleEvent )
456 {
457 KeClearEvent(ppi->InputIdleEvent);
458 }
459 }
460
461 UINT FASTCALL
462 GetWakeMask(UINT first, UINT last )
463 {
464 UINT mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */
465
466 if (first || last)
467 {
468 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
469 if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
470 ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
471 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
472 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
473 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
474 }
475 else mask = QS_ALLINPUT;
476
477 return mask;
478 }
479
480 static VOID FASTCALL
481 IntCallWndProc( PWND Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
482 {
483 BOOL SameThread = FALSE;
484 CWPSTRUCT CWP;
485
486 if (Window->head.pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
487 SameThread = TRUE;
488
489 CWP.hwnd = hWnd;
490 CWP.message = Msg;
491 CWP.wParam = wParam;
492 CWP.lParam = lParam;
493 co_HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, SameThread, (LPARAM)&CWP );
494 }
495
496 static VOID FASTCALL
497 IntCallWndProcRet ( PWND Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *uResult)
498 {
499 BOOL SameThread = FALSE;
500 CWPRETSTRUCT CWPR;
501
502 if (Window->head.pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
503 SameThread = TRUE;
504
505 CWPR.hwnd = hWnd;
506 CWPR.message = Msg;
507 CWPR.wParam = wParam;
508 CWPR.lParam = lParam;
509 CWPR.lResult = *uResult;
510 co_HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, SameThread, (LPARAM)&CWPR );
511 }
512
513 LRESULT FASTCALL
514 IntDispatchMessage(PMSG pMsg)
515 {
516 LARGE_INTEGER TickCount;
517 LONG Time;
518 LRESULT retval = 0;
519 PTHREADINFO pti;
520 PWND Window = NULL;
521
522 if (pMsg->hwnd)
523 {
524 Window = UserGetWindowObject(pMsg->hwnd);
525 if (!Window) return 0;
526 }
527
528 pti = PsGetCurrentThreadWin32Thread();
529
530 if ( Window->head.pti != pti)
531 {
532 EngSetLastError( ERROR_MESSAGE_SYNC_ONLY );
533 return 0;
534 }
535
536 if (((pMsg->message == WM_SYSTIMER) ||
537 (pMsg->message == WM_TIMER)) &&
538 (pMsg->lParam) )
539 {
540 if (pMsg->message == WM_TIMER)
541 {
542 if (ValidateTimerCallback(pti,pMsg->lParam))
543 {
544 KeQueryTickCount(&TickCount);
545 Time = MsqCalculateMessageTime(&TickCount);
546 retval = co_IntCallWindowProc((WNDPROC)pMsg->lParam,
547 TRUE,
548 pMsg->hwnd,
549 WM_TIMER,
550 pMsg->wParam,
551 (LPARAM)Time,
552 0);
553 }
554 return retval;
555 }
556 else
557 {
558 PTIMER pTimer = FindSystemTimer(pMsg);
559 if (pTimer && pTimer->pfn)
560 {
561 KeQueryTickCount(&TickCount);
562 Time = MsqCalculateMessageTime(&TickCount);
563 pTimer->pfn(pMsg->hwnd, WM_SYSTIMER, (UINT)pMsg->wParam, Time);
564 }
565 return 0;
566 }
567 }
568 // Need a window!
569 if ( !Window ) return 0;
570
571 /* Since we are doing a callback on the same thread right away, there is
572 no need to copy the lparam to kernel mode and then back to usermode.
573 We just pretend it isn't a pointer */
574
575 retval = co_IntCallWindowProc( Window->lpfnWndProc,
576 !Window->Unicode,
577 pMsg->hwnd,
578 pMsg->message,
579 pMsg->wParam,
580 pMsg->lParam,
581 0);
582
583 if (pMsg->message == WM_PAINT)
584 {
585 /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
586 HRGN hrgn = IntSysCreateRectRgn( 0, 0, 0, 0 );
587 co_UserGetUpdateRgn( Window, hrgn, TRUE );
588 REGION_FreeRgnByHandle( hrgn );
589 }
590
591 return retval;
592 }
593
594 /*
595 * Internal version of PeekMessage() doing all the work
596 */
597 BOOL FASTCALL
598 co_IntPeekMessage( PMSG Msg,
599 PWND Window,
600 UINT MsgFilterMin,
601 UINT MsgFilterMax,
602 UINT RemoveMsg,
603 BOOL bGMSG )
604 {
605 PTHREADINFO pti;
606 PCLIENTINFO pci;
607 LARGE_INTEGER LargeTickCount;
608 PUSER_MESSAGE_QUEUE ThreadQueue;
609 BOOL RemoveMessages;
610 UINT ProcessMask;
611 BOOL Hit = FALSE;
612
613 pti = PsGetCurrentThreadWin32Thread();
614 ThreadQueue = pti->MessageQueue;
615 pci = pti->pClientInfo;
616
617 RemoveMessages = RemoveMsg & PM_REMOVE;
618 ProcessMask = HIWORD(RemoveMsg);
619
620 /* Hint, "If wMsgFilterMin and wMsgFilterMax are both zero, PeekMessage returns
621 all available messages (that is, no range filtering is performed)". */
622 if (!ProcessMask) ProcessMask = (QS_ALLPOSTMESSAGE|QS_ALLINPUT);
623
624 IdlePong();
625
626 do
627 {
628 KeQueryTickCount(&LargeTickCount);
629 ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
630 pti->pcti->tickLastMsgChecked = LargeTickCount.u.LowPart;
631
632 /* Dispatch sent messages here. */
633 while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
634 {
635 /* if some PM_QS* flags were specified, only handle sent messages from now on */
636 if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE; // wine does this; ProcessMask = QS_SENDMESSAGE;
637 }
638 if (Hit) return FALSE;
639
640 /* Clear changed bits so we can wait on them if we don't find a message */
641 if (ProcessMask & QS_POSTMESSAGE)
642 {
643 pti->pcti->fsChangeBits &= ~(QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER);
644 if (MsgFilterMin == 0 && MsgFilterMax == 0) // wine hack does this; ~0U)
645 {
646 pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
647 }
648 }
649
650 if (ProcessMask & QS_INPUT)
651 {
652 pti->pcti->fsChangeBits &= ~QS_INPUT;
653 }
654
655 /* Now check for normal messages. */
656 if ((ProcessMask & QS_POSTMESSAGE) &&
657 MsqPeekMessage( ThreadQueue,
658 RemoveMessages,
659 Window,
660 MsgFilterMin,
661 MsgFilterMax,
662 ProcessMask,
663 Msg ))
664 {
665 return TRUE;
666 }
667
668 /* Now look for a quit message. */
669 if (ThreadQueue->QuitPosted)
670 {
671 /* According to the PSDK, WM_QUIT messages are always returned, regardless
672 of the filter specified */
673 Msg->hwnd = NULL;
674 Msg->message = WM_QUIT;
675 Msg->wParam = ThreadQueue->QuitExitCode;
676 Msg->lParam = 0;
677 if (RemoveMessages)
678 {
679 ThreadQueue->QuitPosted = FALSE;
680 ClearMsgBitsMask(ThreadQueue, QS_POSTMESSAGE);
681 pti->pcti->fsWakeBits &= ~QS_ALLPOSTMESSAGE;
682 pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
683 }
684 return TRUE;
685 }
686
687 /* Check for hardware events. */
688 if ((ProcessMask & QS_MOUSE) &&
689 co_MsqPeekMouseMove( ThreadQueue,
690 RemoveMessages,
691 Window,
692 MsgFilterMin,
693 MsgFilterMax,
694 Msg ))
695 {
696 return TRUE;
697 }
698
699 if ((ProcessMask & QS_INPUT) &&
700 co_MsqPeekHardwareMessage( ThreadQueue,
701 RemoveMessages,
702 Window,
703 MsgFilterMin,
704 MsgFilterMax,
705 ProcessMask,
706 Msg))
707 {
708 return TRUE;
709 }
710
711 /* Check for sent messages again. */
712 while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
713 {
714 if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE;
715 }
716 if (Hit) return FALSE;
717
718 /* Check for paint messages. */
719 if ((ProcessMask & QS_PAINT) &&
720 pti->cPaintsReady &&
721 IntGetPaintMessage( Window,
722 MsgFilterMin,
723 MsgFilterMax,
724 pti,
725 Msg,
726 RemoveMessages))
727 {
728 return TRUE;
729 }
730
731 /* This is correct, check for the current threads timers waiting to be
732 posted to this threads message queue. If any we loop again.
733 */
734 if ((ProcessMask & QS_TIMER) &&
735 PostTimerMessages(Window))
736 {
737 continue;
738 }
739
740 return FALSE;
741 }
742 while (TRUE);
743
744 return TRUE;
745 }
746
747 static BOOL FASTCALL
748 co_IntWaitMessage( PWND Window,
749 UINT MsgFilterMin,
750 UINT MsgFilterMax )
751 {
752 PTHREADINFO pti;
753 PUSER_MESSAGE_QUEUE ThreadQueue;
754 NTSTATUS Status = STATUS_SUCCESS;
755 MSG Msg;
756
757 pti = PsGetCurrentThreadWin32Thread();
758 ThreadQueue = pti->MessageQueue;
759
760 do
761 {
762 if ( co_IntPeekMessage( &Msg, // Dont reenter!
763 Window,
764 MsgFilterMin,
765 MsgFilterMax,
766 MAKELONG( PM_NOREMOVE, GetWakeMask( MsgFilterMin, MsgFilterMax)),
767 TRUE ) ) // act like GetMessage.
768 {
769 return TRUE;
770 }
771
772 /* Nothing found. Wait for new messages. */
773 Status = co_MsqWaitForNewMessages( ThreadQueue,
774 Window,
775 MsgFilterMin,
776 MsgFilterMax);
777 }
778 while ( (STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) ||
779 STATUS_TIMEOUT == Status );
780
781 if (!NT_SUCCESS(Status))
782 {
783 SetLastNtError(Status);
784 DPRINT1("Exit co_IntWaitMessage on error!\n");
785 }
786
787 return FALSE;
788 }
789
790 BOOL FASTCALL
791 co_IntGetPeekMessage( PMSG pMsg,
792 HWND hWnd,
793 UINT MsgFilterMin,
794 UINT MsgFilterMax,
795 UINT RemoveMsg,
796 BOOL bGMSG )
797 {
798 PWND Window;
799 PTHREADINFO pti;
800 BOOL Present = FALSE;
801
802 if ( hWnd == HWND_TOPMOST || hWnd == HWND_BROADCAST )
803 hWnd = HWND_BOTTOM;
804
805 /* Validate input */
806 if (hWnd && hWnd != HWND_BOTTOM)
807 {
808 if (!(Window = UserGetWindowObject(hWnd)))
809 {
810 if (bGMSG)
811 return -1;
812 else
813 return FALSE;
814 }
815 }
816 else
817 {
818 Window = (PWND)hWnd;
819 }
820
821 if (MsgFilterMax < MsgFilterMin)
822 {
823 MsgFilterMin = 0;
824 MsgFilterMax = 0;
825 }
826
827 if (bGMSG)
828 {
829 RemoveMsg |= ((GetWakeMask( MsgFilterMin, MsgFilterMax ))<< 16);
830 }
831
832 pti = PsGetCurrentThreadWin32Thread();
833 pti->pClientInfo->cSpins++; // Bump up the spin count.
834
835 do
836 {
837 Present = co_IntPeekMessage( pMsg,
838 Window,
839 MsgFilterMin,
840 MsgFilterMax,
841 RemoveMsg,
842 bGMSG );
843 if (Present)
844 {
845 /* GetMessage or PostMessage must never get messages that contain pointers */
846 ASSERT(FindMsgMemory(pMsg->message) == NULL);
847
848 if (pMsg->message != WM_PAINT && pMsg->message != WM_QUIT)
849 {
850 pti->timeLast = pMsg->time;
851 pti->ptLast = pMsg->pt;
852 }
853
854 // The WH_GETMESSAGE hook enables an application to monitor messages about to
855 // be returned by the GetMessage or PeekMessage function.
856
857 co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)pMsg);
858
859 if ( bGMSG )
860 {
861 Present = (WM_QUIT != pMsg->message);
862 break;
863 }
864 }
865
866 if ( bGMSG )
867 {
868 if ( !co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax) )
869 {
870 Present = -1;
871 break;
872 }
873 }
874 else
875 {
876 if (!(RemoveMsg & PM_NOYIELD))
877 {
878 IdlePing();
879 // Yield this thread!
880 UserLeave();
881 ZwYieldExecution();
882 UserEnterExclusive();
883 // Fall through to exit.
884 IdlePong();
885 }
886 break;
887 }
888 }
889 while( bGMSG && !Present );
890
891 // Been spinning, time to swap vinyl...
892 if (pti->pClientInfo->cSpins >= 100)
893 {
894 // Clear the spin cycle to fix the mix.
895 pti->pClientInfo->cSpins = 0;
896 //if (!(pti->TIF_flags & TIF_SPINNING)) FIXME need to swap vinyl..
897 }
898 return Present;
899 }
900
901 BOOL FASTCALL
902 UserPostThreadMessage( DWORD idThread,
903 UINT Msg,
904 WPARAM wParam,
905 LPARAM lParam )
906 {
907 MSG Message;
908 PETHREAD peThread;
909 PTHREADINFO pThread;
910 LARGE_INTEGER LargeTickCount;
911 NTSTATUS Status;
912
913 if (FindMsgMemory(Msg) != 0)
914 {
915 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
916 return FALSE;
917 }
918
919 Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
920
921 if( Status == STATUS_SUCCESS )
922 {
923 pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
924 if( !pThread ||
925 !pThread->MessageQueue ||
926 (pThread->TIF_flags & TIF_INCLEANUP))
927 {
928 ObDereferenceObject( peThread );
929 return FALSE;
930 }
931
932 Message.hwnd = NULL;
933 Message.message = Msg;
934 Message.wParam = wParam;
935 Message.lParam = lParam;
936 Message.pt = gpsi->ptCursor;
937
938 KeQueryTickCount(&LargeTickCount);
939 Message.time = MsqCalculateMessageTime(&LargeTickCount);
940 MsqPostMessage(pThread->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
941 ObDereferenceObject( peThread );
942 return TRUE;
943 }
944 else
945 {
946 SetLastNtError( Status );
947 }
948 return FALSE;
949 }
950
951 BOOL FASTCALL
952 UserPostMessage( HWND Wnd,
953 UINT Msg,
954 WPARAM wParam,
955 LPARAM lParam )
956 {
957 PTHREADINFO pti;
958 MSG Message, KernelModeMsg;
959 LARGE_INTEGER LargeTickCount;
960 PMSGMEMORY MsgMemoryEntry;
961
962 Message.hwnd = Wnd;
963 Message.message = Msg;
964 Message.wParam = wParam;
965 Message.lParam = lParam;
966 Message.pt = gpsi->ptCursor;
967 KeQueryTickCount(&LargeTickCount);
968 Message.time = MsqCalculateMessageTime(&LargeTickCount);
969
970 MsgMemoryEntry = FindMsgMemory(Message.message);
971
972 if( Msg >= WM_DDE_FIRST && Msg <= WM_DDE_LAST )
973 {
974 NTSTATUS Status;
975
976 Status = CopyMsgToKernelMem(&KernelModeMsg, &Message, MsgMemoryEntry);
977 if (! NT_SUCCESS(Status))
978 {
979 EngSetLastError(ERROR_INVALID_PARAMETER);
980 return FALSE;
981 }
982 co_IntSendMessageNoWait(KernelModeMsg.hwnd,
983 KernelModeMsg.message,
984 KernelModeMsg.wParam,
985 KernelModeMsg.lParam);
986
987 if (MsgMemoryEntry && KernelModeMsg.lParam)
988 ExFreePool((PVOID) KernelModeMsg.lParam);
989
990 return TRUE;
991 }
992
993 if (MsgMemoryEntry)
994 {
995 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
996 return FALSE;
997 }
998
999 if (!Wnd)
1000 {
1001 return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
1002 Msg,
1003 wParam,
1004 lParam);
1005 }
1006 if (Wnd == HWND_BROADCAST)
1007 {
1008 HWND *List;
1009 PWND DesktopWindow;
1010 ULONG i;
1011
1012 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1013 List = IntWinListChildren(DesktopWindow);
1014
1015 if (List != NULL)
1016 {
1017 UserPostMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1018 for (i = 0; List[i]; i++)
1019 {
1020 UserPostMessage(List[i], Msg, wParam, lParam);
1021 }
1022 ExFreePoolWithTag(List,TAG_WINLIST);//ExFreePool(List);
1023 }
1024 }
1025 else
1026 {
1027 PWND Window;
1028
1029 Window = UserGetWindowObject(Wnd);
1030 if ( !Window )
1031 {
1032 return FALSE;
1033 }
1034
1035 pti = Window->head.pti;
1036 if ( pti->TIF_flags & TIF_INCLEANUP )
1037 {
1038 DPRINT1("Attempted to post message to window 0x%x when the thread is in cleanup!\n", Wnd);
1039 return FALSE;
1040 }
1041
1042 if ( Window->state & WNDS_DESTROYED )
1043 {
1044 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
1045 /* FIXME - last error code? */
1046 return FALSE;
1047 }
1048
1049 if (WM_QUIT == Msg)
1050 {
1051 MsqPostQuitMessage(Window->head.pti->MessageQueue, wParam);
1052 }
1053 else
1054 {
1055 MsqPostMessage(Window->head.pti->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1056 }
1057 }
1058 return TRUE;
1059 }
1060
1061
1062 LRESULT FASTCALL
1063 co_IntSendMessage( HWND hWnd,
1064 UINT Msg,
1065 WPARAM wParam,
1066 LPARAM lParam )
1067 {
1068 ULONG_PTR Result = 0;
1069 if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1070 {
1071 return (LRESULT)Result;
1072 }
1073 return 0;
1074 }
1075
1076 static LRESULT FASTCALL
1077 co_IntSendMessageTimeoutSingle( HWND hWnd,
1078 UINT Msg,
1079 WPARAM wParam,
1080 LPARAM lParam,
1081 UINT uFlags,
1082 UINT uTimeout,
1083 ULONG_PTR *uResult )
1084 {
1085 NTSTATUS Status;
1086 PWND Window = NULL;
1087 PMSGMEMORY MsgMemoryEntry;
1088 INT lParamBufferSize;
1089 LPARAM lParamPacked;
1090 PTHREADINFO Win32Thread;
1091 ULONG_PTR Result = 0;
1092 DECLARE_RETURN(LRESULT);
1093 USER_REFERENCE_ENTRY Ref;
1094
1095 if (!(Window = UserGetWindowObject(hWnd)))
1096 {
1097 RETURN( FALSE);
1098 }
1099
1100 UserRefObjectCo(Window, &Ref);
1101
1102 Win32Thread = PsGetCurrentThreadWin32Thread();
1103
1104 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1105
1106 if ( NULL != Win32Thread &&
1107 Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
1108 {
1109 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1110 {
1111 /* Never send messages to exiting threads */
1112 RETURN( FALSE);
1113 }
1114
1115 /* See if this message type is present in the table */
1116 MsgMemoryEntry = FindMsgMemory(Msg);
1117 if (NULL == MsgMemoryEntry)
1118 {
1119 lParamBufferSize = -1;
1120 }
1121 else
1122 {
1123 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1124 }
1125
1126 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, FALSE)))
1127 {
1128 DPRINT1("Failed to pack message parameters\n");
1129 RETURN( FALSE);
1130 }
1131
1132 ObReferenceObject(Win32Thread->pEThread);
1133 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1134 !Window->Unicode,
1135 hWnd,
1136 Msg,
1137 wParam,
1138 lParamPacked,
1139 lParamBufferSize );
1140 if(uResult)
1141 {
1142 *uResult = Result;
1143 }
1144
1145 ObDereferenceObject(Win32Thread->pEThread);
1146
1147 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1148
1149 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1150 {
1151 DPRINT1("Failed to unpack message parameters\n");
1152 RETURN( TRUE);
1153 }
1154
1155 RETURN( TRUE);
1156 }
1157
1158 if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->head.pti->MessageQueue))
1159 {
1160 /* FIXME - Set a LastError? */
1161 RETURN( FALSE);
1162 }
1163
1164 if (Window->state & WNDS_DESTROYED)
1165 {
1166 /* FIXME - last error? */
1167 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1168 RETURN( FALSE);
1169 }
1170
1171 do
1172 {
1173 Status = co_MsqSendMessage( Window->head.pti->MessageQueue,
1174 hWnd,
1175 Msg,
1176 wParam,
1177 lParam,
1178 uTimeout,
1179 (uFlags & SMTO_BLOCK),
1180 MSQ_NORMAL,
1181 uResult );
1182 }
1183 while ((STATUS_TIMEOUT == Status) &&
1184 (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
1185 !MsqIsHung(Window->head.pti->MessageQueue));
1186
1187 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1188
1189 if (STATUS_TIMEOUT == Status)
1190 {
1191 /*
1192 MSDN says:
1193 Microsoft Windows 2000: If GetLastError returns zero, then the function
1194 timed out.
1195 XP+ : If the function fails or times out, the return value is zero.
1196 To get extended error information, call GetLastError. If GetLastError
1197 returns ERROR_TIMEOUT, then the function timed out.
1198 */
1199 EngSetLastError(ERROR_TIMEOUT);
1200 RETURN( FALSE);
1201 }
1202 else if (! NT_SUCCESS(Status))
1203 {
1204 SetLastNtError(Status);
1205 RETURN( FALSE);
1206 }
1207
1208 RETURN( TRUE);
1209
1210 CLEANUP:
1211 if (Window) UserDerefObjectCo(Window);
1212 END_CLEANUP;
1213 }
1214
1215 LRESULT FASTCALL
1216 co_IntSendMessageTimeout( HWND hWnd,
1217 UINT Msg,
1218 WPARAM wParam,
1219 LPARAM lParam,
1220 UINT uFlags,
1221 UINT uTimeout,
1222 ULONG_PTR *uResult )
1223 {
1224 PWND DesktopWindow;
1225 HWND *Children;
1226 HWND *Child;
1227
1228 if (HWND_BROADCAST != hWnd)
1229 {
1230 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1231 }
1232
1233 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1234 if (NULL == DesktopWindow)
1235 {
1236 EngSetLastError(ERROR_INTERNAL_ERROR);
1237 return 0;
1238 }
1239
1240 /* Send message to the desktop window too! */
1241 co_IntSendMessageTimeoutSingle(DesktopWindow->head.h, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1242
1243 Children = IntWinListChildren(DesktopWindow);
1244 if (NULL == Children)
1245 {
1246 return 0;
1247 }
1248
1249 for (Child = Children; NULL != *Child; Child++)
1250 {
1251 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1252 }
1253
1254 ExFreePool(Children);
1255
1256 return (LRESULT) TRUE;
1257 }
1258
1259 LRESULT FASTCALL
1260 co_IntSendMessageNoWait(HWND hWnd,
1261 UINT Msg,
1262 WPARAM wParam,
1263 LPARAM lParam)
1264 {
1265 ULONG_PTR Result = 0;
1266 co_IntSendMessageWithCallBack(hWnd,
1267 Msg,
1268 wParam,
1269 lParam,
1270 NULL,
1271 0,
1272 &Result);
1273 return Result;
1274 }
1275
1276 LRESULT FASTCALL
1277 co_IntSendMessageWithCallBack( HWND hWnd,
1278 UINT Msg,
1279 WPARAM wParam,
1280 LPARAM lParam,
1281 SENDASYNCPROC CompletionCallback,
1282 ULONG_PTR CompletionCallbackContext,
1283 ULONG_PTR *uResult)
1284 {
1285 ULONG_PTR Result;
1286 PWND Window = NULL;
1287 PMSGMEMORY MsgMemoryEntry;
1288 INT lParamBufferSize;
1289 LPARAM lParamPacked;
1290 PTHREADINFO Win32Thread;
1291 DECLARE_RETURN(LRESULT);
1292 USER_REFERENCE_ENTRY Ref;
1293 PUSER_SENT_MESSAGE Message;
1294
1295 if (!(Window = UserGetWindowObject(hWnd)))
1296 {
1297 RETURN(FALSE);
1298 }
1299
1300 UserRefObjectCo(Window, &Ref);
1301
1302 if (Window->state & WNDS_DESTROYED)
1303 {
1304 /* FIXME - last error? */
1305 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1306 RETURN(FALSE);
1307 }
1308
1309 Win32Thread = PsGetCurrentThreadWin32Thread();
1310
1311 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1312
1313 if (Win32Thread == NULL)
1314 {
1315 ASSERT(FALSE);
1316 RETURN(FALSE);
1317 }
1318
1319 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1320 {
1321 /* Never send messages to exiting threads */
1322 RETURN(FALSE);
1323 }
1324
1325 /* See if this message type is present in the table */
1326 MsgMemoryEntry = FindMsgMemory(Msg);
1327 if (NULL == MsgMemoryEntry)
1328 {
1329 lParamBufferSize = -1;
1330 }
1331 else
1332 {
1333 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1334 }
1335
1336 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, Window->head.pti->MessageQueue != Win32Thread->MessageQueue)))
1337 {
1338 DPRINT1("Failed to pack message parameters\n");
1339 RETURN( FALSE);
1340 }
1341
1342 /* If this is not a callback and it can be sent now, then send it. */
1343 if ((Window->head.pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
1344 {
1345 ObReferenceObject(Win32Thread->pEThread);
1346 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1347 !Window->Unicode,
1348 hWnd,
1349 Msg,
1350 wParam,
1351 lParamPacked,
1352 lParamBufferSize );
1353 if(uResult)
1354 {
1355 *uResult = Result;
1356 }
1357 ObDereferenceObject(Win32Thread->pEThread);
1358 }
1359
1360 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1361
1362 if ((Window->head.pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
1363 {
1364 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1365 {
1366 DPRINT1("Failed to unpack message parameters\n");
1367 }
1368 RETURN(TRUE);
1369 }
1370
1371 if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
1372 {
1373 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1374 return STATUS_INSUFFICIENT_RESOURCES;
1375 }
1376
1377 Message->Msg.hwnd = hWnd;
1378 Message->Msg.message = Msg;
1379 Message->Msg.wParam = wParam;
1380 Message->Msg.lParam = lParamPacked;
1381 Message->CompletionEvent = NULL;
1382 Message->Result = 0;
1383 Message->lResult = 0;
1384 Message->QS_Flags = 0;
1385 Message->SenderQueue = NULL; // mjmartin, you are right! This is null.
1386 Message->CallBackSenderQueue = Win32Thread->MessageQueue;
1387
1388 IntReferenceMessageQueue(Window->head.pti->MessageQueue);
1389 Message->CompletionCallback = CompletionCallback;
1390 Message->CompletionCallbackContext = CompletionCallbackContext;
1391 Message->HookMessage = MSQ_NORMAL | MSQ_SENTNOWAIT;
1392 Message->HasPackedLParam = (lParamBufferSize > 0);
1393
1394 Message->QS_Flags = QS_SENDMESSAGE;
1395 MsqWakeQueue(Window->head.pti->MessageQueue, QS_SENDMESSAGE, FALSE);
1396
1397 InsertTailList(&Window->head.pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
1398 IntDereferenceMessageQueue(Window->head.pti->MessageQueue);
1399
1400 RETURN(TRUE);
1401
1402 CLEANUP:
1403 if (Window) UserDerefObjectCo(Window);
1404 END_CLEANUP;
1405 }
1406
1407 LRESULT FASTCALL
1408 co_IntDoSendMessage( HWND hWnd,
1409 UINT Msg,
1410 WPARAM wParam,
1411 LPARAM lParam,
1412 PDOSENDMESSAGE dsm)
1413 {
1414 PTHREADINFO pti;
1415 LRESULT Result = TRUE;
1416 NTSTATUS Status;
1417 PWND Window = NULL;
1418 MSG UserModeMsg;
1419 MSG KernelModeMsg;
1420 PMSGMEMORY MsgMemoryEntry;
1421
1422 if (HWND_BROADCAST != hWnd)
1423 {
1424 Window = UserGetWindowObject(hWnd);
1425 if ( !Window )
1426 {
1427 return 0;
1428 }
1429 }
1430
1431 /* Check for an exiting window. */
1432 if (Window && Window->state & WNDS_DESTROYED)
1433 {
1434 DPRINT1("co_IntDoSendMessage Window Exiting!\n");
1435 }
1436
1437 /* See if the current thread can handle the message */
1438 pti = PsGetCurrentThreadWin32Thread();
1439
1440 UserModeMsg.hwnd = hWnd;
1441 UserModeMsg.message = Msg;
1442 UserModeMsg.wParam = wParam;
1443 UserModeMsg.lParam = lParam;
1444 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1445
1446 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1447 if (! NT_SUCCESS(Status))
1448 {
1449 EngSetLastError(ERROR_INVALID_PARAMETER);
1450 return (dsm ? 0 : -1);
1451 }
1452
1453 if (!dsm)
1454 {
1455 Result = co_IntSendMessage( KernelModeMsg.hwnd,
1456 KernelModeMsg.message,
1457 KernelModeMsg.wParam,
1458 KernelModeMsg.lParam );
1459 }
1460 else
1461 {
1462 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1463 KernelModeMsg.message,
1464 KernelModeMsg.wParam,
1465 KernelModeMsg.lParam,
1466 dsm->uFlags,
1467 dsm->uTimeout,
1468 &dsm->Result );
1469 }
1470
1471 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1472 if (! NT_SUCCESS(Status))
1473 {
1474 EngSetLastError(ERROR_INVALID_PARAMETER);
1475 return(dsm ? 0 : -1);
1476 }
1477
1478 return (LRESULT)Result;
1479 }
1480
1481 BOOL FASTCALL
1482 UserSendNotifyMessage( HWND hWnd,
1483 UINT Msg,
1484 WPARAM wParam,
1485 LPARAM lParam )
1486 {
1487 BOOL Ret = TRUE;
1488
1489 if (FindMsgMemory(Msg) != 0)
1490 {
1491 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1492 return FALSE;
1493 }
1494
1495 // Basicly the same as IntPostOrSendMessage
1496 if (hWnd == HWND_BROADCAST) //Handle Broadcast
1497 {
1498 HWND *List;
1499 PWND DesktopWindow;
1500 ULONG i;
1501
1502 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1503 List = IntWinListChildren(DesktopWindow);
1504
1505 if (List != NULL)
1506 {
1507 UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1508 for (i = 0; List[i]; i++)
1509 {
1510 Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1511 if (!Ret)
1512 {
1513 DPRINT1("SendNotifyMessage: Failed in Broadcast!\n");
1514 break;
1515 }
1516 }
1517 ExFreePool(List);
1518 }
1519 }
1520 else
1521 {
1522 ULONG_PTR lResult = 0;
1523 Ret = co_IntSendMessageWithCallBack( hWnd,
1524 Msg,
1525 wParam,
1526 lParam,
1527 NULL,
1528 0,
1529 &lResult);
1530 }
1531 return Ret;
1532 }
1533
1534
1535 DWORD APIENTRY
1536 IntGetQueueStatus(DWORD Changes)
1537 {
1538 PTHREADINFO pti;
1539 PUSER_MESSAGE_QUEUE Queue;
1540 DWORD Result;
1541
1542 pti = PsGetCurrentThreadWin32Thread();
1543 Queue = pti->MessageQueue;
1544 // wine:
1545 Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
1546
1547 /* High word, types of messages currently in the queue.
1548 Low word, types of messages that have been added to the queue and that
1549 are still in the queue
1550 */
1551 Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes);
1552
1553 pti->pcti->fsChangeBits &= ~Changes;
1554
1555 return Result;
1556 }
1557
1558 BOOL APIENTRY
1559 IntInitMessagePumpHook()
1560 {
1561 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1562
1563 if (pti->pcti)
1564 {
1565 pti->pcti->dwcPumpHook++;
1566 return TRUE;
1567 }
1568 return FALSE;
1569 }
1570
1571 BOOL APIENTRY
1572 IntUninitMessagePumpHook()
1573 {
1574 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1575
1576 if (pti->pcti)
1577 {
1578 if (pti->pcti->dwcPumpHook <= 0)
1579 {
1580 return FALSE;
1581 }
1582 pti->pcti->dwcPumpHook--;
1583 return TRUE;
1584 }
1585 return FALSE;
1586 }
1587
1588 /** Functions ******************************************************************/
1589
1590 BOOL APIENTRY
1591 NtUserPostMessage(HWND hWnd,
1592 UINT Msg,
1593 WPARAM wParam,
1594 LPARAM lParam)
1595 {
1596 BOOL ret;
1597
1598 UserEnterExclusive();
1599
1600 ret = UserPostMessage(hWnd, Msg, wParam, lParam);
1601
1602 UserLeave();
1603
1604 return ret;
1605 }
1606
1607 BOOL APIENTRY
1608 NtUserPostThreadMessage(DWORD idThread,
1609 UINT Msg,
1610 WPARAM wParam,
1611 LPARAM lParam)
1612 {
1613 BOOL ret;
1614
1615 UserEnterExclusive();
1616
1617 ret = UserPostThreadMessage( idThread, Msg, wParam, lParam);
1618
1619 UserLeave();
1620
1621 return ret;
1622 }
1623
1624 BOOL APIENTRY
1625 NtUserWaitMessage(VOID)
1626 {
1627 BOOL ret;
1628
1629 UserEnterExclusive();
1630 DPRINT("NtUserWaitMessage Enter\n");
1631 ret = co_IntWaitMessage(NULL, 0, 0);
1632 DPRINT("NtUserWaitMessage Leave\n");
1633 UserLeave();
1634
1635 return ret;
1636 }
1637
1638 BOOL APIENTRY
1639 NtUserGetMessage(PMSG pMsg,
1640 HWND hWnd,
1641 UINT MsgFilterMin,
1642 UINT MsgFilterMax )
1643 {
1644 MSG Msg;
1645 BOOL Ret;
1646
1647 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
1648 {
1649 EngSetLastError(ERROR_INVALID_PARAMETER);
1650 return FALSE;
1651 }
1652
1653 UserEnterExclusive();
1654
1655 RtlZeroMemory(&Msg, sizeof(MSG));
1656
1657 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
1658
1659 UserLeave();
1660
1661 if (Ret)
1662 {
1663 _SEH2_TRY
1664 {
1665 ProbeForWrite(pMsg, sizeof(MSG), 1);
1666 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1667 }
1668 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1669 {
1670 SetLastNtError(_SEH2_GetExceptionCode());
1671 Ret = FALSE;
1672 }
1673 _SEH2_END;
1674 }
1675
1676 return Ret;
1677 }
1678
1679 BOOL APIENTRY
1680 NtUserPeekMessage( PMSG pMsg,
1681 HWND hWnd,
1682 UINT MsgFilterMin,
1683 UINT MsgFilterMax,
1684 UINT RemoveMsg)
1685 {
1686 MSG Msg;
1687 BOOL Ret;
1688
1689 if ( RemoveMsg & PM_BADMSGFLAGS )
1690 {
1691 EngSetLastError(ERROR_INVALID_FLAGS);
1692 return FALSE;
1693 }
1694
1695 UserEnterExclusive();
1696
1697 RtlZeroMemory(&Msg, sizeof(MSG));
1698
1699 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
1700
1701 UserLeave();
1702
1703 if (Ret)
1704 {
1705 _SEH2_TRY
1706 {
1707 ProbeForWrite(pMsg, sizeof(MSG), 1);
1708 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1709 }
1710 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1711 {
1712 SetLastNtError(_SEH2_GetExceptionCode());
1713 Ret = FALSE;
1714 }
1715 _SEH2_END;
1716 }
1717
1718 return Ret;
1719 }
1720
1721 BOOL APIENTRY
1722 NtUserCallMsgFilter( LPMSG lpmsg, INT code)
1723 {
1724 BOOL Ret = FALSE;
1725 MSG Msg;
1726
1727 _SEH2_TRY
1728 {
1729 ProbeForRead(lpmsg, sizeof(MSG), 1);
1730 RtlCopyMemory( &Msg, lpmsg, sizeof(MSG));
1731 }
1732 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1733 {
1734 _SEH2_YIELD(return FALSE);
1735 }
1736 _SEH2_END;
1737
1738 UserEnterExclusive();
1739
1740 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
1741 {
1742 Ret = TRUE;
1743 }
1744 else
1745 {
1746 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
1747 }
1748
1749 UserLeave();
1750
1751 _SEH2_TRY
1752 {
1753 ProbeForWrite(lpmsg, sizeof(MSG), 1);
1754 RtlCopyMemory(lpmsg, &Msg, sizeof(MSG));
1755 }
1756 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1757 {
1758 Ret = FALSE;
1759 }
1760 _SEH2_END;
1761
1762 return Ret;
1763 }
1764
1765 LRESULT APIENTRY
1766 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
1767 {
1768 LRESULT Res = 0;
1769 MSG SafeMsg;
1770
1771 _SEH2_TRY
1772 {
1773 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
1774 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
1775 }
1776 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1777 {
1778 SetLastNtError(_SEH2_GetExceptionCode());
1779 _SEH2_YIELD(return FALSE);
1780 }
1781 _SEH2_END;
1782
1783 UserEnterExclusive();
1784
1785 Res = IntDispatchMessage(&SafeMsg);
1786
1787 UserLeave();
1788 return Res;
1789 }
1790
1791
1792 BOOL APIENTRY
1793 NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
1794 {
1795 MSG SafeMsg;
1796 BOOL Ret;
1797
1798 _SEH2_TRY
1799 {
1800 ProbeForRead(lpMsg, sizeof(MSG), 1);
1801 RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG));
1802 }
1803 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1804 {
1805 SetLastNtError(_SEH2_GetExceptionCode());
1806 _SEH2_YIELD(return FALSE);
1807 }
1808 _SEH2_END;
1809
1810 UserEnterExclusive();
1811
1812 Ret = IntTranslateKbdMessage(&SafeMsg, flags);
1813
1814 UserLeave();
1815
1816 return Ret;
1817 }
1818
1819 BOOL APIENTRY
1820 NtUserMessageCall( HWND hWnd,
1821 UINT Msg,
1822 WPARAM wParam,
1823 LPARAM lParam,
1824 ULONG_PTR ResultInfo,
1825 DWORD dwType, // fnID?
1826 BOOL Ansi)
1827 {
1828 LRESULT lResult = 0;
1829 BOOL Ret = FALSE;
1830 PWND Window = NULL;
1831 USER_REFERENCE_ENTRY Ref;
1832
1833 UserEnterExclusive();
1834
1835 /* Validate input */
1836 if (hWnd && (hWnd != INVALID_HANDLE_VALUE))
1837 {
1838 Window = UserGetWindowObject(hWnd);
1839 if (!Window)
1840 {
1841 UserLeave();
1842 return FALSE;
1843 }
1844 }
1845
1846 switch(dwType)
1847 {
1848 case FNID_DEFWINDOWPROC:
1849 if (Window) UserRefObjectCo(Window, &Ref);
1850 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
1851 Ret = TRUE;
1852 if (Window) UserDerefObjectCo(Window);
1853 break;
1854 case FNID_SENDNOTIFYMESSAGE:
1855 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
1856 break;
1857 case FNID_BROADCASTSYSTEMMESSAGE:
1858 {
1859 BROADCASTPARM parm;
1860 DWORD_PTR RetVal = 0;
1861
1862 if (ResultInfo)
1863 {
1864 _SEH2_TRY
1865 {
1866 ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1);
1867 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
1868 }
1869 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1870 {
1871 Ret = FALSE;
1872 _SEH2_YIELD(break);
1873 }
1874 _SEH2_END;
1875 }
1876 else
1877 break;
1878
1879 if ( parm.recipients & BSM_ALLDESKTOPS ||
1880 parm.recipients == BSM_ALLCOMPONENTS )
1881 {
1882 }
1883 else if (parm.recipients & BSM_APPLICATIONS)
1884 {
1885 if (parm.flags & BSF_QUERY)
1886 {
1887 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
1888 {
1889 co_IntSendMessageTimeout( HWND_BROADCAST,
1890 Msg,
1891 wParam,
1892 lParam,
1893 SMTO_ABORTIFHUNG,
1894 2000,
1895 &RetVal);
1896 }
1897 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
1898 {
1899 co_IntSendMessageTimeout( HWND_BROADCAST,
1900 Msg,
1901 wParam,
1902 lParam,
1903 SMTO_NOTIMEOUTIFNOTHUNG,
1904 2000,
1905 &RetVal);
1906 }
1907 else
1908 {
1909 co_IntSendMessageTimeout( HWND_BROADCAST,
1910 Msg,
1911 wParam,
1912 lParam,
1913 SMTO_NORMAL,
1914 2000,
1915 &RetVal);
1916 }
1917 Ret = RetVal;
1918 }
1919 else if (parm.flags & BSF_POSTMESSAGE)
1920 {
1921 Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
1922 }
1923 else //Everything else,,,, if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
1924 {
1925 Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
1926 }
1927 }
1928 }
1929 break;
1930 case FNID_SENDMESSAGECALLBACK:
1931 {
1932 CALL_BACK_INFO CallBackInfo;
1933 ULONG_PTR uResult;
1934
1935 _SEH2_TRY
1936 {
1937 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
1938 RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO));
1939 }
1940 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1941 {
1942 Ret = FALSE;
1943 _SEH2_YIELD(break);
1944 }
1945 _SEH2_END;
1946
1947 if (!co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
1948 CallBackInfo.CallBack, CallBackInfo.Context, &uResult))
1949 {
1950 DPRINT1("Callback failure!\n");
1951 }
1952 }
1953 break;
1954 case FNID_SENDMESSAGE:
1955 {
1956 Ret = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
1957
1958 if (ResultInfo)
1959 {
1960 _SEH2_TRY
1961 {
1962 ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
1963 RtlCopyMemory((PVOID)ResultInfo, &Ret, sizeof(ULONG_PTR));
1964 }
1965 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1966 {
1967 Ret = FALSE;
1968 _SEH2_YIELD(break);
1969 }
1970 _SEH2_END;
1971 }
1972 break;
1973 }
1974 case FNID_SENDMESSAGETIMEOUT:
1975 {
1976 DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo;
1977 if (ResultInfo)
1978 {
1979 _SEH2_TRY
1980 {
1981 ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1);
1982 RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE));
1983 }
1984 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1985 {
1986 Ret = FALSE;
1987 _SEH2_YIELD(break);
1988 }
1989 _SEH2_END;
1990 }
1991
1992 Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, &dsm );
1993
1994 if (pdsm)
1995 {
1996 _SEH2_TRY
1997 {
1998 ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1);
1999 RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE));
2000 }
2001 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2002 {
2003 Ret = FALSE;
2004 _SEH2_YIELD(break);
2005 }
2006 _SEH2_END;
2007 }
2008 break;
2009 }
2010 // CallNextHook bypass.
2011 case FNID_CALLWNDPROC:
2012 case FNID_CALLWNDPROCRET:
2013 {
2014 PTHREADINFO pti;
2015 PCLIENTINFO ClientInfo;
2016 PHOOK NextObj, Hook;
2017
2018 pti = GetW32ThreadInfo();
2019
2020 Hook = pti->sphkCurrent;
2021
2022 if (!Hook) break;
2023
2024 NextObj = Hook->phkNext;
2025 ClientInfo = pti->pClientInfo;
2026 _SEH2_TRY
2027 {
2028 ClientInfo->phkCurrent = NextObj;
2029 }
2030 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2031 {
2032 ClientInfo = NULL;
2033 }
2034 _SEH2_END;
2035
2036 if (!ClientInfo || !NextObj) break;
2037
2038 NextObj->phkNext = IntGetNextHook(NextObj);
2039
2040 if ( Hook->HookId == WH_CALLWNDPROC)
2041 {
2042 CWPSTRUCT CWP;
2043 CWP.hwnd = hWnd;
2044 CWP.message = Msg;
2045 CWP.wParam = wParam;
2046 CWP.lParam = lParam;
2047 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
2048
2049 lResult = co_IntCallHookProc( Hook->HookId,
2050 HC_ACTION,
2051 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2052 (LPARAM)&CWP,
2053 Hook->Proc,
2054 Hook->Ansi,
2055 &Hook->ModuleName);
2056 }
2057 else
2058 {
2059 CWPRETSTRUCT CWPR;
2060 CWPR.hwnd = hWnd;
2061 CWPR.message = Msg;
2062 CWPR.wParam = wParam;
2063 CWPR.lParam = lParam;
2064 CWPR.lResult = ClientInfo->dwHookData;
2065
2066 lResult = co_IntCallHookProc( Hook->HookId,
2067 HC_ACTION,
2068 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2069 (LPARAM)&CWPR,
2070 Hook->Proc,
2071 Hook->Ansi,
2072 &Hook->ModuleName);
2073 }
2074 }
2075 break;
2076 }
2077
2078 switch(dwType)
2079 {
2080 case FNID_DEFWINDOWPROC:
2081 case FNID_CALLWNDPROC:
2082 case FNID_CALLWNDPROCRET:
2083 if (ResultInfo)
2084 {
2085 _SEH2_TRY
2086 {
2087 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2088 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2089 }
2090 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2091 {
2092 Ret = FALSE;
2093 }
2094 _SEH2_END;
2095 }
2096 break;
2097 default:
2098 break;
2099 }
2100
2101 UserLeave();
2102
2103 return Ret;
2104 }
2105
2106 #define INFINITE 0xFFFFFFFF
2107 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2108
2109 DWORD
2110 APIENTRY
2111 NtUserWaitForInputIdle( IN HANDLE hProcess,
2112 IN DWORD dwMilliseconds,
2113 IN BOOL Unknown2)
2114 {
2115 PEPROCESS Process;
2116 PPROCESSINFO W32Process;
2117 PTHREADINFO pti;
2118 NTSTATUS Status;
2119 HANDLE Handles[3];
2120 LARGE_INTEGER Timeout;
2121
2122 UserEnterExclusive();
2123
2124 Status = ObReferenceObjectByHandle(hProcess,
2125 PROCESS_QUERY_INFORMATION,
2126 PsProcessType,
2127 UserMode,
2128 (PVOID*)&Process,
2129 NULL);
2130
2131 if (!NT_SUCCESS(Status))
2132 {
2133 UserLeave();
2134 SetLastNtError(Status);
2135 return WAIT_FAILED;
2136 }
2137
2138 pti = PsGetCurrentThreadWin32Thread();
2139
2140 W32Process = (PPROCESSINFO)Process->Win32Process;
2141
2142 if ( PsGetProcessExitProcessCalled(Process) ||
2143 !W32Process ||
2144 pti->ppi == W32Process)
2145 {
2146 ObDereferenceObject(Process);
2147 UserLeave();
2148 EngSetLastError(ERROR_INVALID_PARAMETER);
2149 return WAIT_FAILED;
2150 }
2151
2152 Handles[0] = Process;
2153 Handles[1] = W32Process->InputIdleEvent;
2154 Handles[2] = pti->MessageQueue->NewMessages; // pEventQueueServer; IntMsqSetWakeMask returns hEventQueueClient
2155
2156 if (!Handles[1])
2157 {
2158 ObDereferenceObject(Process);
2159 UserLeave();
2160 return STATUS_SUCCESS; /* no event to wait on */
2161 }
2162
2163 if (dwMilliseconds != INFINITE)
2164 Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
2165
2166 W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE;
2167 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2168 {
2169 pti->TIF_flags |= TIF_WAITFORINPUTIDLE;
2170 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2171 }
2172
2173 DPRINT("WFII: ppi 0x%x\n",W32Process);
2174 DPRINT("WFII: waiting for %p\n", Handles[1] );
2175 do
2176 {
2177 UserLeave();
2178 Status = KeWaitForMultipleObjects( 3,
2179 Handles,
2180 WaitAny,
2181 UserRequest,
2182 UserMode,
2183 FALSE,
2184 dwMilliseconds == INFINITE ? NULL : &Timeout,
2185 NULL);
2186 UserEnterExclusive();
2187
2188 if (!NT_SUCCESS(Status))
2189 {
2190 SetLastNtError(Status);
2191 Status = WAIT_FAILED;
2192 goto WaitExit;
2193 }
2194
2195 switch (Status)
2196 {
2197 case STATUS_WAIT_0:
2198 goto WaitExit;
2199
2200 case STATUS_WAIT_2:
2201 {
2202 MSG Msg;
2203 co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE);
2204 DPRINT1("WFII: WAIT 2\n");
2205 }
2206 break;
2207
2208 case STATUS_TIMEOUT:
2209 DPRINT1("WFII: timeout\n");
2210 case WAIT_FAILED:
2211 goto WaitExit;
2212
2213 default:
2214 DPRINT1("WFII: finished\n");
2215 Status = STATUS_SUCCESS;
2216 goto WaitExit;
2217 }
2218 }
2219 while (TRUE);
2220
2221 WaitExit:
2222 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2223 {
2224 pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE;
2225 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2226 }
2227 W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE;
2228 ObDereferenceObject(Process);
2229 UserLeave();
2230 return Status;
2231 }
2232
2233 /* EOF */