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