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