2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
5 * FILE: subsystems/win32/win32k/ntuser/message.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * 06-06-2001 CSH Created
11 /* INCLUDES ******************************************************************/
18 BOOLEAN NTAPI
PsGetProcessExitProcessCalled(PEPROCESS Process
);
20 #define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE)
28 DOSENDMESSAGE
, *PDOSENDMESSAGE
;
30 /* FUNCTIONS *****************************************************************/
33 IntInitMessageImpl(VOID
)
35 return STATUS_SUCCESS
;
39 IntCleanupMessageImpl(VOID
)
41 return STATUS_SUCCESS
;
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
57 MSGMEMORY
, *PMSGMEMORY
;
59 static MSGMEMORY MsgMemory
[] =
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
},
76 static PMSGMEMORY FASTCALL
77 FindMsgMemory(UINT Msg
)
79 PMSGMEMORY MsgMemoryEntry
;
81 /* See if this message type is present in the table */
82 for (MsgMemoryEntry
= MsgMemory
;
83 MsgMemoryEntry
< MsgMemory
+ sizeof(MsgMemory
) / sizeof(MSGMEMORY
);
86 if (Msg
== MsgMemoryEntry
->Message
)
88 return MsgMemoryEntry
;
96 MsgMemorySize(PMSGMEMORY MsgMemoryEntry
, WPARAM wParam
, LPARAM lParam
)
99 PUNICODE_STRING WindowName
;
100 PUNICODE_STRING ClassName
;
105 if (MMS_SIZE_WPARAM
== MsgMemoryEntry
->Size
)
109 else if (MMS_SIZE_WPARAMWCHAR
== MsgMemoryEntry
->Size
)
111 Size
= (UINT
) (wParam
* sizeof(WCHAR
));
113 else if (MMS_SIZE_LPARAMSZ
== MsgMemoryEntry
->Size
)
115 Size
= (UINT
) ((wcslen((PWSTR
) lParam
) + 1) * sizeof(WCHAR
));
117 else if (MMS_SIZE_SPECIAL
== MsgMemoryEntry
->Size
)
119 switch(MsgMemoryEntry
->Message
)
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
))
129 Size
+= sizeof(WCHAR
) + sizeof(ATOM
);
133 Size
+= sizeof(WCHAR
) + ClassName
->Length
+ sizeof(WCHAR
);
138 Size
= wParam
? sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
) : sizeof(RECT
);
142 Size
= sizeof(COPYDATASTRUCT
) + ((PCOPYDATASTRUCT
)lParam
)->cbData
;
145 case WM_COPYGLOBALDATA
:
157 Size
= MsgMemoryEntry
->Size
;
160 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
162 DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode());
170 PackParam(LPARAM
*lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, BOOL NonPagedPoolNeeded
)
172 NCCALCSIZE_PARAMS
*UnpackedNcCalcsize
;
173 NCCALCSIZE_PARAMS
*PackedNcCalcsize
;
174 CREATESTRUCTW
*UnpackedCs
;
175 CREATESTRUCTW
*PackedCs
;
176 PLARGE_STRING WindowName
;
177 PUNICODE_STRING ClassName
;
182 *lParamPacked
= lParam
;
184 if (NonPagedPoolNeeded
)
185 PoolType
= NonPagedPool
;
187 PoolType
= PagedPool
;
189 if (WM_NCCALCSIZE
== Msg
&& wParam
)
192 UnpackedNcCalcsize
= (NCCALCSIZE_PARAMS
*) lParam
;
193 PackedNcCalcsize
= ExAllocatePoolWithTag(PoolType
,
194 sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
),
197 if (NULL
== PackedNcCalcsize
)
199 DPRINT1("Not enough memory to pack lParam\n");
200 return STATUS_NO_MEMORY
;
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
;
207 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
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
))
215 Size
+= sizeof(WCHAR
) + sizeof(ATOM
);
219 Size
+= sizeof(WCHAR
) + ClassName
->Length
+ sizeof(WCHAR
);
221 PackedCs
= ExAllocatePoolWithTag(PoolType
, Size
, TAG_MSG
);
222 if (NULL
== PackedCs
)
224 DPRINT1("Not enough memory to pack lParam\n");
225 return STATUS_NO_MEMORY
;
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
))
237 *((WCHAR
*) CsData
) = L
'A';
238 CsData
+= sizeof(WCHAR
);
239 *((ATOM
*) CsData
) = (ATOM
)(DWORD_PTR
) ClassName
->Buffer
;
240 CsData
+= sizeof(ATOM
);
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
);
251 ASSERT(CsData
== (PCHAR
) PackedCs
+ Size
);
252 *lParamPacked
= (LPARAM
) PackedCs
;
255 else if (PoolType
== NonPagedPool
)
257 PMSGMEMORY MsgMemoryEntry
;
260 MsgMemoryEntry
= FindMsgMemory(Msg
);
262 if ((!MsgMemoryEntry
) || (MsgMemoryEntry
->Size
< 0))
264 /* Keep previous behavior */
265 return STATUS_SUCCESS
;
267 PackedData
= ExAllocatePoolWithTag(NonPagedPool
, MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
), TAG_MSG
);
268 RtlCopyMemory(PackedData
, (PVOID
)lParam
, MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
));
269 *lParamPacked
= (LPARAM
)PackedData
;
272 return STATUS_SUCCESS
;
276 UnpackParam(LPARAM lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, BOOL NonPagedPoolUsed
)
278 NCCALCSIZE_PARAMS
*UnpackedParams
;
279 NCCALCSIZE_PARAMS
*PackedParams
;
280 PWINDOWPOS UnpackedWindowPos
;
282 if (lParamPacked
== lParam
)
284 return STATUS_SUCCESS
;
287 if (WM_NCCALCSIZE
== Msg
&& wParam
)
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
);
297 return STATUS_SUCCESS
;
299 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
301 ExFreePool((PVOID
) lParamPacked
);
303 return STATUS_SUCCESS
;
305 else if (NonPagedPoolUsed
)
307 PMSGMEMORY MsgMemoryEntry
;
308 MsgMemoryEntry
= FindMsgMemory(Msg
);
309 if (MsgMemoryEntry
->Size
< 0)
311 /* Keep previous behavior */
312 return STATUS_INVALID_PARAMETER
;
315 if (MsgMemory
->Flags
== MMS_FLAG_READWRITE
)
317 //RtlCopyMemory((PVOID)lParam, (PVOID)lParamPacked, MsgMemory->Size);
319 ExFreePool((PVOID
) lParamPacked
);
320 return STATUS_SUCCESS
;
325 return STATUS_INVALID_PARAMETER
;
329 // Wakeup any thread/process waiting on idle input.
334 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
335 PUSER_MESSAGE_QUEUE ForegroundQueue
;
336 PTHREADINFO pti
, ptiForeground
= NULL
;
338 ForegroundQueue
= IntGetFocusMessageQueue();
341 ptiForeground
= ForegroundQueue
->Thread
->Tcb
.Win32Thread
;
343 pti
= PsGetCurrentThreadWin32Thread();
347 pti
->pClientInfo
->cSpins
= 0; // Reset spins.
349 if ( pti
->pDeskInfo
&& pti
== ptiForeground
)
351 if ( pti
->fsHooks
& HOOKID_TO_FLAG(WH_FOREGROUNDIDLE
) ||
352 pti
->pDeskInfo
->fsHooks
& HOOKID_TO_FLAG(WH_FOREGROUNDIDLE
) )
354 co_HOOK_CallHooks(WH_FOREGROUNDIDLE
,HC_ACTION
,0,0);
359 DPRINT("IdlePing ppi 0x%x\n",ppi
);
360 if ( ppi
&& ppi
->InputIdleEvent
)
362 DPRINT("InputIdleEvent\n");
363 KeSetEvent( ppi
->InputIdleEvent
, IO_NO_INCREMENT
, FALSE
);
370 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
372 DPRINT("IdlePong ppi 0x%x\n",ppi
);
373 if ( ppi
&& ppi
->InputIdleEvent
)
375 KeClearEvent(ppi
->InputIdleEvent
);
380 GetWakeMask(UINT first
, UINT last
)
382 UINT mask
= QS_POSTMESSAGE
| QS_SENDMESSAGE
; /* Always selected */
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
;
393 else mask
= QS_ALLINPUT
;
399 IntCallWndProc( PWND Window
, HWND hWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
401 BOOL SameThread
= FALSE
;
404 if (Window
->head
.pti
== ((PTHREADINFO
)PsGetCurrentThreadWin32Thread()))
411 co_HOOK_CallHooks( WH_CALLWNDPROC
, HC_ACTION
, SameThread
, (LPARAM
)&CWP
);
415 IntCallWndProcRet ( PWND Window
, HWND hWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*uResult
)
417 BOOL SameThread
= FALSE
;
420 if (Window
->head
.pti
== ((PTHREADINFO
)PsGetCurrentThreadWin32Thread()))
425 CWPR
.wParam
= wParam
;
426 CWPR
.lParam
= lParam
;
427 CWPR
.lResult
= *uResult
;
428 co_HOOK_CallHooks( WH_CALLWNDPROCRET
, HC_ACTION
, SameThread
, (LPARAM
)&CWPR
);
432 IntDispatchMessage(PMSG pMsg
)
434 LARGE_INTEGER TickCount
;
437 PMSGMEMORY MsgMemoryEntry
;
438 INT lParamBufferSize
;
445 Window
= UserGetWindowObject(pMsg
->hwnd
);
446 if (!Window
) return 0;
449 pti
= PsGetCurrentThreadWin32Thread();
451 if ( Window
->head
.pti
!= pti
)
453 SetLastWin32Error( ERROR_MESSAGE_SYNC_ONLY
);
457 if (((pMsg
->message
== WM_SYSTIMER
) ||
458 (pMsg
->message
== WM_TIMER
)) &&
461 if (pMsg
->message
== WM_TIMER
)
463 ObReferenceObject(pti
->pEThread
);
464 if (ValidateTimerCallback(pti
,pMsg
->lParam
))
466 KeQueryTickCount(&TickCount
);
467 Time
= MsqCalculateMessageTime(&TickCount
);
468 retval
= co_IntCallWindowProc((WNDPROC
)pMsg
->lParam
,
476 ObDereferenceObject(pti
->pEThread
);
481 PTIMER pTimer
= FindSystemTimer(pMsg
);
482 if (pTimer
&& pTimer
->pfn
)
484 KeQueryTickCount(&TickCount
);
485 Time
= MsqCalculateMessageTime(&TickCount
);
486 pTimer
->pfn(pMsg
->hwnd
, WM_SYSTIMER
, (UINT
)pMsg
->wParam
, Time
);
492 if ( !Window
) return 0;
494 /* See if this message type is present in the table */
495 MsgMemoryEntry
= FindMsgMemory(pMsg
->message
);
496 if ( !MsgMemoryEntry
)
498 lParamBufferSize
= -1;
502 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, pMsg
->wParam
, pMsg
->lParam
);
505 if (! NT_SUCCESS(PackParam(&lParamPacked
, pMsg
->message
, pMsg
->wParam
, pMsg
->lParam
, FALSE
)))
507 DPRINT1("Failed to pack message parameters\n");
510 ObReferenceObject(pti
->pEThread
);
511 retval
= co_IntCallWindowProc( Window
->lpfnWndProc
,
519 if (! NT_SUCCESS(UnpackParam(lParamPacked
, pMsg
->message
, pMsg
->wParam
, pMsg
->lParam
, FALSE
)))
521 DPRINT1("Failed to unpack message parameters\n");
524 if (pMsg
->message
== WM_PAINT
)
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
);
531 ObDereferenceObject(pti
->pEThread
);
536 * Internal version of PeekMessage() doing all the work
539 co_IntPeekMessage( PMSG Msg
,
548 LARGE_INTEGER LargeTickCount
;
549 PUSER_MESSAGE_QUEUE ThreadQueue
;
554 pti
= PsGetCurrentThreadWin32Thread();
555 ThreadQueue
= pti
->MessageQueue
;
556 pci
= pti
->pClientInfo
;
558 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
559 ProcessMask
= HIWORD(RemoveMsg
);
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
);
569 KeQueryTickCount(&LargeTickCount
);
570 ThreadQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
571 pti
->pcti
->tickLastMsgChecked
= LargeTickCount
.u
.LowPart
;
573 /* Dispatch sent messages here. */
574 while ( co_MsqDispatchOneSentMessage(ThreadQueue
) )
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;
579 if (Hit
) return FALSE
;
581 /* Clear changed bits so we can wait on them if we don't find a message */
582 if (ProcessMask
& QS_POSTMESSAGE
)
584 pti
->pcti
->fsChangeBits
&= ~(QS_POSTMESSAGE
| QS_HOTKEY
| QS_TIMER
);
585 if (MsgFilterMin
== 0 && MsgFilterMax
== 0) // wine hack does this; ~0U)
587 pti
->pcti
->fsChangeBits
&= ~QS_ALLPOSTMESSAGE
;
591 if (ProcessMask
& QS_INPUT
)
593 pti
->pcti
->fsChangeBits
&= ~QS_INPUT
;
596 /* Now check for normal messages. */
597 if ((ProcessMask
& QS_POSTMESSAGE
) &&
598 MsqPeekMessage( ThreadQueue
,
609 /* Now look for a quit message. */
610 if (ThreadQueue
->QuitPosted
)
612 /* According to the PSDK, WM_QUIT messages are always returned, regardless
613 of the filter specified */
615 Msg
->message
= WM_QUIT
;
616 Msg
->wParam
= ThreadQueue
->QuitExitCode
;
620 ThreadQueue
->QuitPosted
= FALSE
;
621 ClearMsgBitsMask(ThreadQueue
, QS_POSTMESSAGE
);
622 pti
->pcti
->fsWakeBits
&= ~QS_ALLPOSTMESSAGE
;
623 pti
->pcti
->fsChangeBits
&= ~QS_ALLPOSTMESSAGE
;
628 /* Check for hardware events. */
629 if ((ProcessMask
& QS_MOUSE
) &&
630 co_MsqPeekMouseMove( ThreadQueue
,
640 if ((ProcessMask
& QS_INPUT
) &&
641 co_MsqPeekHardwareMessage( ThreadQueue
,
652 /* Check for sent messages again. */
653 while ( co_MsqDispatchOneSentMessage(ThreadQueue
) )
655 if (HIWORD(RemoveMsg
) && !bGMSG
) Hit
= TRUE
;
657 if (Hit
) return FALSE
;
659 /* Check for paint messages. */
660 if ((ProcessMask
& QS_PAINT
) &&
662 IntGetPaintMessage( Window
,
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.
675 if ((ProcessMask
& QS_TIMER
) &&
676 PostTimerMessages(Window
))
688 static NTSTATUS FASTCALL
689 CopyMsgToKernelMem(MSG
*KernelModeMsg
, MSG
*UserModeMsg
, PMSGMEMORY MsgMemoryEntry
)
696 *KernelModeMsg
= *UserModeMsg
;
698 /* See if this message type is present in the table */
699 if (NULL
== MsgMemoryEntry
)
701 /* Not present, no copying needed */
702 return STATUS_SUCCESS
;
705 /* Determine required size */
706 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
710 /* Allocate kernel mem */
711 KernelMem
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
712 if (NULL
== KernelMem
)
714 DPRINT1("Not enough memory to copy message to kernel mem\n");
715 return STATUS_NO_MEMORY
;
717 KernelModeMsg
->lParam
= (LPARAM
) KernelMem
;
719 /* Copy data if required */
720 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_READ
))
722 Status
= MmCopyFromCaller(KernelMem
, (PVOID
) UserModeMsg
->lParam
, Size
);
723 if (! NT_SUCCESS(Status
))
725 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
726 ExFreePoolWithTag(KernelMem
, TAG_MSG
);
732 /* Make sure we don't pass any secrets to usermode */
733 RtlZeroMemory(KernelMem
, Size
);
738 KernelModeMsg
->lParam
= 0;
741 return STATUS_SUCCESS
;
744 static NTSTATUS FASTCALL
745 CopyMsgToUserMem(MSG
*UserModeMsg
, MSG
*KernelModeMsg
)
748 PMSGMEMORY MsgMemoryEntry
;
751 /* See if this message type is present in the table */
752 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
753 if (NULL
== MsgMemoryEntry
)
755 /* Not present, no copying needed */
756 return STATUS_SUCCESS
;
759 /* Determine required size */
760 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
764 /* Copy data if required */
765 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_WRITE
))
767 Status
= MmCopyToCaller((PVOID
) UserModeMsg
->lParam
, (PVOID
) KernelModeMsg
->lParam
, Size
);
768 if (! NT_SUCCESS(Status
))
770 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
771 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
776 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
779 return STATUS_SUCCESS
;
783 co_IntWaitMessage( PWND Window
,
788 PUSER_MESSAGE_QUEUE ThreadQueue
;
789 NTSTATUS Status
= STATUS_SUCCESS
;
792 pti
= PsGetCurrentThreadWin32Thread();
793 ThreadQueue
= pti
->MessageQueue
;
797 if ( co_IntPeekMessage( &Msg
, // Dont reenter!
801 MAKELONG( PM_NOREMOVE
, GetWakeMask( MsgFilterMin
, MsgFilterMax
)),
802 TRUE
) ) // act like GetMessage.
807 /* Nothing found. Wait for new messages. */
808 Status
= co_MsqWaitForNewMessages( ThreadQueue
,
813 while ( (STATUS_WAIT_0
<= Status
&& Status
<= STATUS_WAIT_63
) ||
814 STATUS_TIMEOUT
== Status
);
816 if (!NT_SUCCESS(Status
))
818 SetLastNtError(Status
);
819 DPRINT1("Exit co_IntWaitMessage on error!\n");
826 co_IntGetPeekMessage( PMSG pMsg
,
835 BOOL Present
= FALSE
;
837 if ( hWnd
== HWND_TOPMOST
|| hWnd
== HWND_BROADCAST
)
841 if (hWnd
&& hWnd
!= HWND_BOTTOM
)
843 if (!(Window
= UserGetWindowObject(hWnd
)))
856 if (MsgFilterMax
< MsgFilterMin
)
864 RemoveMsg
|= ((GetWakeMask( MsgFilterMin
, MsgFilterMax
))<< 16);
869 Present
= co_IntPeekMessage( pMsg
,
877 // The WH_GETMESSAGE hook enables an application to monitor messages about to
878 // be returned by the GetMessage or PeekMessage function.
880 co_HOOK_CallHooks( WH_GETMESSAGE
, HC_ACTION
, RemoveMsg
& PM_REMOVE
, (LPARAM
)pMsg
);
884 Present
= (WM_QUIT
!= pMsg
->message
);
891 if ( !co_IntWaitMessage(Window
, MsgFilterMin
, MsgFilterMax
) )
899 if (!(RemoveMsg
& PM_NOYIELD
))
902 // Yield this thread!
905 UserEnterExclusive();
906 // Fall through to exit.
912 while( bGMSG
&& !Present
);
914 pti
= PsGetCurrentThreadWin32Thread();
915 // Been spinning, time to swap vinyl...
916 if (pti
->pClientInfo
->cSpins
>= 100)
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..
926 UserPostThreadMessage( DWORD idThread
,
934 LARGE_INTEGER LargeTickCount
;
937 DPRINT1("UserPostThreadMessage wParam 0x%x lParam 0x%x\n", wParam
,lParam
);
939 if (FindMsgMemory(Msg
) != 0)
941 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY
);
945 Status
= PsLookupThreadByThreadId((HANDLE
)idThread
,&peThread
);
947 if( Status
== STATUS_SUCCESS
)
949 pThread
= (PTHREADINFO
)peThread
->Tcb
.Win32Thread
;
951 !pThread
->MessageQueue
||
952 (pThread
->TIF_flags
& TIF_INCLEANUP
))
954 ObDereferenceObject( peThread
);
959 Message
.message
= Msg
;
960 Message
.wParam
= wParam
;
961 Message
.lParam
= lParam
;
962 Message
.pt
= gpsi
->ptCursor
;
964 KeQueryTickCount(&LargeTickCount
);
965 pThread
->timeLast
= Message
.time
= MsqCalculateMessageTime(&LargeTickCount
);
966 MsqPostMessage(pThread
->MessageQueue
, &Message
, FALSE
, QS_POSTMESSAGE
);
967 ObDereferenceObject( peThread
);
972 SetLastNtError( Status
);
978 UserPostMessage( HWND Wnd
,
985 LARGE_INTEGER LargeTickCount
;
987 if (FindMsgMemory(Msg
) != 0)
989 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY
);
995 return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
1000 if (Wnd
== HWND_BROADCAST
)
1006 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1007 List
= IntWinListChildren(DesktopWindow
);
1011 UserPostMessage(DesktopWindow
->head
.h
, Msg
, wParam
, lParam
);
1012 for (i
= 0; List
[i
]; i
++)
1014 UserPostMessage(List
[i
], Msg
, wParam
, lParam
);
1023 Window
= UserGetWindowObject(Wnd
);
1029 pti
= Window
->head
.pti
;
1030 if ( pti
->TIF_flags
& TIF_INCLEANUP
)
1032 DPRINT1("Attempted to post message to window 0x%x when the thread is in cleanup!\n", Wnd
);
1036 if ( Window
->state
& WNDS_DESTROYED
)
1038 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd
);
1039 /* FIXME - last error code? */
1045 MsqPostQuitMessage(Window
->head
.pti
->MessageQueue
, wParam
);
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
);
1064 co_IntSendMessage( HWND hWnd
,
1069 ULONG_PTR Result
= 0;
1070 if(co_IntSendMessageTimeout(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1072 return (LRESULT
)Result
;
1077 static LRESULT FASTCALL
1078 co_IntSendMessageTimeoutSingle( HWND hWnd
,
1084 ULONG_PTR
*uResult
)
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
;
1096 if (!(Window
= UserGetWindowObject(hWnd
)))
1101 UserRefObjectCo(Window
, &Ref
);
1103 Win32Thread
= PsGetCurrentThreadWin32Thread();
1105 IntCallWndProc( Window
, hWnd
, Msg
, wParam
, lParam
);
1107 if ( NULL
!= Win32Thread
&&
1108 Window
->head
.pti
->MessageQueue
== Win32Thread
->MessageQueue
)
1110 if (Win32Thread
->TIF_flags
& TIF_INCLEANUP
)
1112 /* Never send messages to exiting threads */
1116 /* See if this message type is present in the table */
1117 MsgMemoryEntry
= FindMsgMemory(Msg
);
1118 if (NULL
== MsgMemoryEntry
)
1120 lParamBufferSize
= -1;
1124 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
1127 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
, FALSE
)))
1129 DPRINT1("Failed to pack message parameters\n");
1133 ObReferenceObject(Win32Thread
->pEThread
);
1134 Result
= (ULONG_PTR
)co_IntCallWindowProc( Window
->lpfnWndProc
,
1146 ObDereferenceObject(Win32Thread
->pEThread
);
1148 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, (LRESULT
*)uResult
);
1150 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
, FALSE
)))
1152 DPRINT1("Failed to unpack message parameters\n");
1159 if (uFlags
& SMTO_ABORTIFHUNG
&& MsqIsHung(Window
->head
.pti
->MessageQueue
))
1161 /* FIXME - Set a LastError? */
1165 if (Window
->state
& WNDS_DESTROYED
)
1167 /* FIXME - last error? */
1168 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd
);
1174 Status
= co_MsqSendMessage( Window
->head
.pti
->MessageQueue
,
1180 (uFlags
& SMTO_BLOCK
),
1184 while ((STATUS_TIMEOUT
== Status
) &&
1185 (uFlags
& SMTO_NOTIMEOUTIFNOTHUNG
) &&
1186 !MsqIsHung(Window
->head
.pti
->MessageQueue
));
1188 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, (LRESULT
*)uResult
);
1190 if (STATUS_TIMEOUT
== Status
)
1194 Microsoft Windows 2000: If GetLastError returns zero, then the function
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.
1200 SetLastWin32Error(ERROR_TIMEOUT
);
1203 else if (! NT_SUCCESS(Status
))
1205 SetLastNtError(Status
);
1212 if (Window
) UserDerefObjectCo(Window
);
1217 co_IntSendMessageTimeout( HWND hWnd
,
1223 ULONG_PTR
*uResult
)
1229 if (HWND_BROADCAST
!= hWnd
)
1231 return co_IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1234 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1235 if (NULL
== DesktopWindow
)
1237 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1241 /* Send message to the desktop window too! */
1242 co_IntSendMessageTimeoutSingle(DesktopWindow
->head
.h
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1244 Children
= IntWinListChildren(DesktopWindow
);
1245 if (NULL
== Children
)
1250 for (Child
= Children
; NULL
!= *Child
; Child
++)
1252 co_IntSendMessageTimeoutSingle(*Child
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1255 ExFreePool(Children
);
1257 return (LRESULT
) TRUE
;
1261 co_IntSendMessageNoWait(HWND hWnd
,
1266 ULONG_PTR Result
= 0;
1267 co_IntSendMessageWithCallBack(hWnd
,
1278 co_IntSendMessageWithCallBack( HWND hWnd
,
1282 SENDASYNCPROC CompletionCallback
,
1283 ULONG_PTR CompletionCallbackContext
,
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
;
1296 if (!(Window
= UserGetWindowObject(hWnd
)))
1301 UserRefObjectCo(Window
, &Ref
);
1303 if (Window
->state
& WNDS_DESTROYED
)
1305 /* FIXME - last error? */
1306 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd
);
1310 Win32Thread
= PsGetCurrentThreadWin32Thread();
1312 IntCallWndProc( Window
, hWnd
, Msg
, wParam
, lParam
);
1314 if (Win32Thread
== NULL
)
1320 if (Win32Thread
->TIF_flags
& TIF_INCLEANUP
)
1322 /* Never send messages to exiting threads */
1326 /* See if this message type is present in the table */
1327 MsgMemoryEntry
= FindMsgMemory(Msg
);
1328 if (NULL
== MsgMemoryEntry
)
1330 lParamBufferSize
= -1;
1334 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
1337 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
, Window
->head
.pti
->MessageQueue
!= Win32Thread
->MessageQueue
)))
1339 DPRINT1("Failed to pack message parameters\n");
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
))
1346 ObReferenceObject(Win32Thread
->pEThread
);
1347 Result
= (ULONG_PTR
)co_IntCallWindowProc( Window
->lpfnWndProc
,
1358 ObDereferenceObject(Win32Thread
->pEThread
);
1361 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, (LRESULT
*)uResult
);
1363 if ((Window
->head
.pti
->MessageQueue
== Win32Thread
->MessageQueue
) && (CompletionCallback
== NULL
))
1365 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
, FALSE
)))
1367 DPRINT1("Failed to unpack message parameters\n");
1372 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1374 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1375 return STATUS_INSUFFICIENT_RESOURCES
;
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;
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);
1394 Message
->QS_Flags
= QS_SENDMESSAGE
;
1395 MsqWakeQueue(Window
->head
.pti
->MessageQueue
, QS_SENDMESSAGE
, FALSE
);
1397 InsertTailList(&Window
->head
.pti
->MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1398 IntDereferenceMessageQueue(Window
->head
.pti
->MessageQueue
);
1403 if (Window
) UserDerefObjectCo(Window
);
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
1411 co_IntPostOrSendMessage( HWND hWnd
,
1420 if ( hWnd
== HWND_BROADCAST
)
1425 if(!(Window
= UserGetWindowObject(hWnd
)))
1430 pti
= PsGetCurrentThreadWin32Thread();
1432 if ( Window
->head
.pti
->MessageQueue
!= pti
->MessageQueue
&&
1433 FindMsgMemory(Msg
) == 0 )
1435 Result
= UserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1439 if ( !co_IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
) )
1445 return (LRESULT
)Result
;
1449 co_IntDoSendMessage( HWND hWnd
,
1454 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1457 LRESULT Result
= TRUE
;
1460 NTUSERSENDMESSAGEINFO Info
;
1463 PMSGMEMORY MsgMemoryEntry
;
1465 RtlZeroMemory(&Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1467 /* FIXME: Call hooks. */
1468 if (HWND_BROADCAST
!= hWnd
)
1470 Window
= UserGetWindowObject(hWnd
);
1473 /* Tell usermode to not touch this one */
1474 Info
.HandledByKernel
= TRUE
;
1475 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1480 /* Check for an exiting window. */
1481 if (Window
&& Window
->state
& WNDS_DESTROYED
)
1483 DPRINT1("co_IntDoSendMessage Window Exiting!\n");
1486 /* See if the current thread can handle the message */
1487 pti
= PsGetCurrentThreadWin32Thread();
1489 // This is checked in user mode!!!!!!!
1490 if ( HWND_BROADCAST
!= hWnd
&&
1492 Window
->head
.pti
->MessageQueue
== pti
->MessageQueue
&&
1493 !ISITHOOKED(WH_CALLWNDPROC
) &&
1494 !ISITHOOKED(WH_CALLWNDPROCRET
) &&
1495 ( Msg
< WM_DDE_FIRST
|| Msg
> WM_DDE_LAST
) )
1497 /* Gather the information usermode needs to call the window proc directly */
1498 Info
.HandledByKernel
= FALSE
;
1500 Status
= MmCopyFromCaller(&(Info
.Ansi
), &(UnsafeInfo
->Ansi
), sizeof(BOOL
));
1501 if (! NT_SUCCESS(Status
))
1503 Info
.Ansi
= ! Window
->Unicode
;
1506 Info
.Ansi
= !Window
->Unicode
;
1507 Info
.Proc
= Window
->lpfnWndProc
;
1511 /* Must be handled by other thread */
1512 // if (HWND_BROADCAST != hWnd)
1514 // UserDereferenceObject(Window);
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
);
1523 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1524 if (! NT_SUCCESS(Status
))
1526 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1527 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1528 return (dsm
? 0 : -1);
1533 Result
= co_IntSendMessage( KernelModeMsg
.hwnd
,
1534 KernelModeMsg
.message
,
1535 KernelModeMsg
.wParam
,
1536 KernelModeMsg
.lParam
);
1540 Result
= co_IntSendMessageTimeout( KernelModeMsg
.hwnd
,
1541 KernelModeMsg
.message
,
1542 KernelModeMsg
.wParam
,
1543 KernelModeMsg
.lParam
,
1549 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
1550 if (! NT_SUCCESS(Status
))
1552 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1553 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1554 return(dsm
? 0 : -1);
1558 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1559 if (! NT_SUCCESS(Status
))
1561 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1564 return (LRESULT
)Result
;
1569 UserSendNotifyMessage( HWND hWnd
,
1576 if (FindMsgMemory(Msg
) != 0)
1578 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY
);
1582 // Basicly the same as IntPostOrSendMessage
1583 if (hWnd
== HWND_BROADCAST
) //Handle Broadcast
1589 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1590 List
= IntWinListChildren(DesktopWindow
);
1594 UserSendNotifyMessage(DesktopWindow
->head
.h
, Msg
, wParam
, lParam
);
1595 for (i
= 0; List
[i
]; i
++)
1597 Ret
= UserSendNotifyMessage(List
[i
], Msg
, wParam
, lParam
);
1600 DPRINT1("SendNotifyMessage: Failed in Broadcast!\n");
1609 ULONG_PTR lResult
= 0;
1610 Ret
= co_IntSendMessageWithCallBack( hWnd
,
1623 IntGetQueueStatus(DWORD Changes
)
1626 PUSER_MESSAGE_QUEUE Queue
;
1629 pti
= PsGetCurrentThreadWin32Thread();
1630 Queue
= pti
->MessageQueue
;
1632 Changes
&= (QS_ALLINPUT
|QS_ALLPOSTMESSAGE
|QS_SMRESULT
);
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
1638 Result
= MAKELONG(pti
->pcti
->fsChangeBits
& Changes
, pti
->pcti
->fsWakeBits
& Changes
);
1640 pti
->pcti
->fsChangeBits
&= ~Changes
;
1646 IntInitMessagePumpHook()
1648 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1652 pti
->pcti
->dwcPumpHook
++;
1659 IntUninitMessagePumpHook()
1661 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1665 if (pti
->pcti
->dwcPumpHook
<= 0)
1669 pti
->pcti
->dwcPumpHook
--;
1675 /** Functions ******************************************************************/
1678 NtUserPostMessage(HWND hWnd
,
1685 UserEnterExclusive();
1687 ret
= UserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1695 NtUserPostThreadMessage(DWORD idThread
,
1702 UserEnterExclusive();
1704 ret
= UserPostThreadMessage( idThread
, Msg
, wParam
, lParam
);
1711 ////////// API on the way out!
1713 NtUserSendMessageTimeout( HWND hWnd
,
1720 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1725 DPRINT("Enter NtUserSendMessageTimeout\n");
1727 dsm
.uFlags
= uFlags
;
1728 dsm
.uTimeout
= uTimeout
;
1730 UserEnterExclusive();
1732 Result
= co_IntDoSendMessage(hWnd
, Msg
, wParam
, lParam
, &dsm
, UnsafeInfo
);
1736 if(uResult
!= NULL
&& Result
!= 0)
1740 ProbeForWrite(uResult
, sizeof(ULONG_PTR
), 1);
1741 RtlCopyMemory(uResult
, &dsm
.Result
, sizeof(ULONG_PTR
));
1743 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1745 SetLastWin32Error(ERROR_INVALID_PARAMETER
);;
1755 NtUserSendMessage( HWND Wnd
,
1759 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1763 UserEnterExclusive();
1765 ret
= co_IntDoSendMessage(Wnd
, Msg
, wParam
, lParam
, NULL
, UnsafeInfo
);
1774 NtUserWaitMessage(VOID
)
1778 UserEnterExclusive();
1779 DPRINT("NtUserWaitMessage Enter\n");
1780 ret
= co_IntWaitMessage(NULL
, 0, 0);
1781 DPRINT("NtUserWaitMessage Leave\n");
1789 NtUserGetMessage( PNTUSERGETMESSAGEINFO UnsafeInfo
,
1794 * FUNCTION: Get a message from the calling thread's message queue.
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
1800 * MsgFilterMax - Integer value of the highest message value to be
1804 NTUSERGETMESSAGEINFO Info
;
1806 PMSGMEMORY MsgMemoryEntry
;
1812 if ( (MsgFilterMin
|MsgFilterMax
) & ~WM_MAXIMUM
)
1814 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1818 UserEnterExclusive();
1820 RtlZeroMemory(&Msg
, sizeof(MSG
));
1822 GotMessage
= co_IntGetPeekMessage(&Msg
, hWnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
, TRUE
);
1827 /* See if this message type is present in the table */
1828 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
1832 ProbeForWrite(UnsafeInfo
, sizeof(NTUSERGETMESSAGEINFO
), 1);
1833 RtlCopyMemory(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
1835 if (NULL
== MsgMemoryEntry
)
1837 /* Not present, no copying needed */
1838 UnsafeInfo
->LParamSize
= 0;
1842 /* Determine required size */
1843 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
, Info
.Msg
.lParam
);
1845 /* Allocate required amount of user-mode memory */
1846 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(),
1852 if (! NT_SUCCESS(Status
))
1854 SetLastNtError(Status
);
1855 _SEH2_YIELD(return (BOOL
) -1);
1858 /* Transfer lParam data to user-mode mem */
1859 ProbeForWrite(UserMem
, Size
, 1);
1860 RtlCopyMemory(UserMem
, (PVOID
)Info
.Msg
.lParam
, Size
);
1862 UnsafeInfo
->LParamSize
= Size
;
1863 UnsafeInfo
->Msg
.lParam
= (LPARAM
) UserMem
;
1866 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1868 SetLastNtError(_SEH2_GetExceptionCode());
1872 ZwFreeVirtualMemory(NtCurrentProcess(), &UserMem
, &Size
, MEM_RELEASE
);
1875 _SEH2_YIELD(return (BOOL
) -1);
1884 NtUserGetMessageX(PMSG pMsg
,
1892 if ( (MsgFilterMin
|MsgFilterMax
) & ~WM_MAXIMUM
)
1894 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1898 UserEnterExclusive();
1900 RtlZeroMemory(&Msg
, sizeof(MSG
));
1902 Ret
= co_IntGetPeekMessage(&Msg
, hWnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
, TRUE
);
1910 ProbeForWrite(pMsg
, sizeof(MSG
), 1);
1911 RtlCopyMemory(pMsg
, &Msg
, sizeof(MSG
));
1913 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1915 SetLastNtError(_SEH2_GetExceptionCode());
1925 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
1932 NTUSERGETMESSAGEINFO Info
;
1933 PMSGMEMORY MsgMemoryEntry
;
1934 PVOID UserMem
= NULL
;
1939 if ( RemoveMsg
& PM_BADMSGFLAGS
)
1941 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1945 UserEnterExclusive();
1947 RtlZeroMemory(&Msg
, sizeof(MSG
));
1949 Ret
= co_IntGetPeekMessage(&Msg
, hWnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
, FALSE
);
1956 /* See if this message type is present in the table */
1957 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
1961 ProbeForWrite(UnsafeInfo
, sizeof(NTUSERGETMESSAGEINFO
), 1);
1962 RtlCopyMemory(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
1964 if (NULL
== MsgMemoryEntry
)
1966 /* Not present, no copying needed */
1967 UnsafeInfo
->LParamSize
= 0;
1971 /* Determine required size */
1972 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
, Info
.Msg
.lParam
);
1974 /* Allocate required amount of user-mode memory */
1975 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(),
1981 if (! NT_SUCCESS(Status
))
1983 SetLastNtError(Status
);
1984 _SEH2_YIELD(return (BOOL
) -1);
1987 /* Transfer lParam data to user-mode mem */
1988 ProbeForWrite(UserMem
, Size
, 1);
1989 RtlCopyMemory(UserMem
, (PVOID
)Info
.Msg
.lParam
, Size
);
1991 UnsafeInfo
->LParamSize
= Size
;
1992 UnsafeInfo
->Msg
.lParam
= (LPARAM
) UserMem
;
1995 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1997 SetLastNtError(_SEH2_GetExceptionCode());
2002 ZwFreeVirtualMemory(NtCurrentProcess(), &UserMem
, &Size
, MEM_RELEASE
);
2012 NtUserPeekMessageX( PMSG pMsg
,
2021 if ( RemoveMsg
& PM_BADMSGFLAGS
)
2023 SetLastWin32Error(ERROR_INVALID_FLAGS
);
2027 UserEnterExclusive();
2029 RtlZeroMemory(&Msg
, sizeof(MSG
));
2031 Ret
= co_IntGetPeekMessage(&Msg
, hWnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
, FALSE
);
2039 ProbeForWrite(pMsg
, sizeof(MSG
), 1);
2040 RtlCopyMemory(pMsg
, &Msg
, sizeof(MSG
));
2042 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2044 SetLastNtError(_SEH2_GetExceptionCode());
2054 NtUserCallMsgFilter( LPMSG lpmsg
, INT code
)
2061 ProbeForRead(lpmsg
, sizeof(MSG
), 1);
2062 RtlCopyMemory( &Msg
, lpmsg
, sizeof(MSG
));
2064 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2066 _SEH2_YIELD(return FALSE
);
2070 UserEnterExclusive();
2072 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)&Msg
))
2078 Ret
= co_HOOK_CallHooks( WH_MSGFILTER
, code
, 0, (LPARAM
)&Msg
);
2085 ProbeForWrite(lpmsg
, sizeof(MSG
), 1);
2086 RtlCopyMemory(lpmsg
, &Msg
, sizeof(MSG
));
2088 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2098 NtUserDispatchMessage(PMSG UnsafeMsgInfo
)
2105 ProbeForRead(UnsafeMsgInfo
, sizeof(MSG
), 1);
2106 RtlCopyMemory(&SafeMsg
, UnsafeMsgInfo
, sizeof(MSG
));
2108 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2110 SetLastNtError(_SEH2_GetExceptionCode());
2111 _SEH2_YIELD(return FALSE
);
2115 UserEnterExclusive();
2117 Res
= IntDispatchMessage(&SafeMsg
);
2125 NtUserTranslateMessage(LPMSG lpMsg
, UINT flags
)
2132 ProbeForRead(lpMsg
, sizeof(MSG
), 1);
2133 RtlCopyMemory(&SafeMsg
, lpMsg
, sizeof(MSG
));
2135 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2137 SetLastNtError(_SEH2_GetExceptionCode());
2138 _SEH2_YIELD(return FALSE
);
2142 UserEnterExclusive();
2144 Ret
= IntTranslateKbdMessage(&SafeMsg
, flags
);
2152 NtUserMessageCall( HWND hWnd
,
2156 ULONG_PTR ResultInfo
,
2157 DWORD dwType
, // fnID?
2160 LRESULT lResult
= 0;
2163 USER_REFERENCE_ENTRY Ref
;
2165 UserEnterExclusive();
2167 /* Validate input */
2168 if (hWnd
&& (hWnd
!= INVALID_HANDLE_VALUE
))
2170 Window
= UserGetWindowObject(hWnd
);
2180 case FNID_DEFWINDOWPROC
:
2181 if (Window
) UserRefObjectCo(Window
, &Ref
);
2182 lResult
= IntDefWindowProc(Window
, Msg
, wParam
, lParam
, Ansi
);
2184 if (Window
) UserDerefObjectCo(Window
);
2186 case FNID_SENDNOTIFYMESSAGE
:
2187 Ret
= UserSendNotifyMessage(hWnd
, Msg
, wParam
, lParam
);
2189 case FNID_BROADCASTSYSTEMMESSAGE
:
2192 DWORD_PTR RetVal
= 0;
2198 ProbeForWrite((PVOID
)ResultInfo
, sizeof(BROADCASTPARM
), 1);
2199 RtlCopyMemory(&parm
, (PVOID
)ResultInfo
, sizeof(BROADCASTPARM
));
2201 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2211 if ( parm
.recipients
& BSM_ALLDESKTOPS
||
2212 parm
.recipients
== BSM_ALLCOMPONENTS
)
2215 else if (parm
.recipients
& BSM_APPLICATIONS
)
2217 if (parm
.flags
& BSF_QUERY
)
2219 if (parm
.flags
& BSF_FORCEIFHUNG
|| parm
.flags
& BSF_NOHANG
)
2221 co_IntSendMessageTimeout( HWND_BROADCAST
,
2229 else if (parm
.flags
& BSF_NOTIMEOUTIFNOTHUNG
)
2231 co_IntSendMessageTimeout( HWND_BROADCAST
,
2235 SMTO_NOTIMEOUTIFNOTHUNG
,
2241 co_IntSendMessageTimeout( HWND_BROADCAST
,
2251 else if (parm
.flags
& BSF_POSTMESSAGE
)
2253 Ret
= UserPostMessage(HWND_BROADCAST
, Msg
, wParam
, lParam
);
2255 else //Everything else,,,, if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
2257 Ret
= UserSendNotifyMessage(HWND_BROADCAST
, Msg
, wParam
, lParam
);
2262 case FNID_SENDMESSAGECALLBACK
:
2264 PCALL_BACK_INFO CallBackInfo
= (PCALL_BACK_INFO
)ResultInfo
;
2270 if (!co_IntSendMessageWithCallBack(hWnd
, Msg
, wParam
, lParam
,
2271 CallBackInfo
->CallBack
, CallBackInfo
->Context
, &uResult
))
2273 DPRINT1("Callback failure!\n");
2277 // CallNextHook bypass.
2278 case FNID_CALLWNDPROC
:
2279 case FNID_CALLWNDPROCRET
:
2282 PCLIENTINFO ClientInfo
;
2283 PHOOK NextObj
, Hook
;
2285 pti
= GetW32ThreadInfo();
2287 Hook
= pti
->sphkCurrent
;
2291 NextObj
= Hook
->phkNext
;
2292 ClientInfo
= pti
->pClientInfo
;
2295 ClientInfo
->phkCurrent
= NextObj
;
2297 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2303 if (!ClientInfo
|| !NextObj
) break;
2305 NextObj
->phkNext
= IntGetNextHook(NextObj
);
2307 if ( Hook
->HookId
== WH_CALLWNDPROC
)
2312 CWP
.wParam
= wParam
;
2313 CWP
.lParam
= lParam
;
2314 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook
, NextObj
);
2316 lResult
= co_IntCallHookProc( Hook
->HookId
,
2318 ((ClientInfo
->CI_flags
& CI_CURTHPRHOOK
) ? 1 : 0),
2329 CWPR
.wParam
= wParam
;
2330 CWPR
.lParam
= lParam
;
2331 CWPR
.lResult
= ClientInfo
->dwHookData
;
2333 lResult
= co_IntCallHookProc( Hook
->HookId
,
2335 ((ClientInfo
->CI_flags
& CI_CURTHPRHOOK
) ? 1 : 0),
2347 case FNID_DEFWINDOWPROC
:
2348 case FNID_CALLWNDPROC
:
2349 case FNID_CALLWNDPROCRET
:
2354 ProbeForWrite((PVOID
)ResultInfo
, sizeof(LRESULT
), 1);
2355 RtlCopyMemory((PVOID
)ResultInfo
, &lResult
, sizeof(LRESULT
));
2357 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2373 #define INFINITE 0xFFFFFFFF
2374 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2378 NtUserWaitForInputIdle( IN HANDLE hProcess
,
2379 IN DWORD dwMilliseconds
,
2383 PPROCESSINFO W32Process
;
2387 LARGE_INTEGER Timeout
;
2389 UserEnterExclusive();
2391 Status
= ObReferenceObjectByHandle(hProcess
,
2392 PROCESS_QUERY_INFORMATION
,
2398 if (!NT_SUCCESS(Status
))
2401 SetLastNtError(Status
);
2405 pti
= PsGetCurrentThreadWin32Thread();
2407 W32Process
= (PPROCESSINFO
)Process
->Win32Process
;
2409 if ( PsGetProcessExitProcessCalled(Process
) ||
2411 pti
->ppi
== W32Process
)
2413 ObDereferenceObject(Process
);
2415 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2419 Handles
[0] = Process
;
2420 Handles
[1] = W32Process
->InputIdleEvent
;
2421 Handles
[2] = pti
->MessageQueue
->NewMessages
; // pEventQueueServer; IntMsqSetWakeMask returns hEventQueueClient
2425 ObDereferenceObject(Process
);
2427 return STATUS_SUCCESS
; /* no event to wait on */
2430 if (dwMilliseconds
!= INFINITE
)
2431 Timeout
.QuadPart
= (LONGLONG
) dwMilliseconds
* (LONGLONG
) -10000;
2433 W32Process
->W32PF_flags
|= W32PF_WAITFORINPUTIDLE
;
2434 for (pti
= W32Process
->ptiList
; pti
; pti
= pti
->ptiSibling
)
2436 pti
->TIF_flags
|= TIF_WAITFORINPUTIDLE
;
2437 pti
->pClientInfo
->dwTIFlags
= pti
->TIF_flags
;
2440 DPRINT("WFII: ppi 0x%x\n",W32Process
);
2441 DPRINT("WFII: waiting for %p\n", Handles
[1] );
2445 Status
= KeWaitForMultipleObjects( 3,
2451 dwMilliseconds
== INFINITE
? NULL
: &Timeout
,
2453 UserEnterExclusive();
2455 if (!NT_SUCCESS(Status
))
2457 SetLastNtError(Status
);
2458 Status
= WAIT_FAILED
;
2470 co_IntGetPeekMessage( &Msg
, 0, 0, 0, PM_REMOVE
| PM_QS_SENDMESSAGE
, FALSE
);
2471 DPRINT1("WFII: WAIT 2\n");
2475 case STATUS_TIMEOUT
:
2476 DPRINT1("WFII: timeout\n");
2481 DPRINT1("WFII: finished\n");
2482 Status
= STATUS_SUCCESS
;
2489 for (pti
= W32Process
->ptiList
; pti
; pti
= pti
->ptiSibling
)
2491 pti
->TIF_flags
&= ~TIF_WAITFORINPUTIDLE
;
2492 pti
->pClientInfo
->dwTIFlags
= pti
->TIF_flags
;
2494 W32Process
->W32PF_flags
&= ~W32PF_WAITFORINPUTIDLE
;
2495 ObDereferenceObject(Process
);