2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
5 * FILE: subsys/win32k/ntuser/message.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * 06-06-2001 CSH Created
11 /* INCLUDES ******************************************************************/
24 DOSENDMESSAGE
, *PDOSENDMESSAGE
;
26 /* FUNCTIONS *****************************************************************/
29 IntInitMessageImpl(VOID
)
31 return STATUS_SUCCESS
;
35 IntCleanupMessageImpl(VOID
)
37 return STATUS_SUCCESS
;
40 #define MMS_SIZE_WPARAM -1
41 #define MMS_SIZE_WPARAMWCHAR -2
42 #define MMS_SIZE_LPARAMSZ -3
43 #define MMS_SIZE_SPECIAL -4
44 #define MMS_FLAG_READ 0x01
45 #define MMS_FLAG_WRITE 0x02
46 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
47 typedef struct tagMSGMEMORY
53 MSGMEMORY
, *PMSGMEMORY
;
55 static MSGMEMORY MsgMemory
[] =
57 { WM_CREATE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
58 { WM_DDE_ACK
, sizeof(KMDDELPARAM
), MMS_FLAG_READ
},
59 { WM_DDE_EXECUTE
, MMS_SIZE_WPARAM
, MMS_FLAG_READ
},
60 { WM_GETMINMAXINFO
, sizeof(MINMAXINFO
), MMS_FLAG_READWRITE
},
61 { WM_GETTEXT
, MMS_SIZE_WPARAMWCHAR
, MMS_FLAG_WRITE
},
62 { WM_NCCALCSIZE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
63 { WM_NCCREATE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
64 { WM_SETTEXT
, MMS_SIZE_LPARAMSZ
, MMS_FLAG_READ
},
65 { WM_STYLECHANGED
, sizeof(STYLESTRUCT
), MMS_FLAG_READ
},
66 { WM_STYLECHANGING
, sizeof(STYLESTRUCT
), MMS_FLAG_READWRITE
},
67 { WM_COPYDATA
, MMS_SIZE_SPECIAL
, MMS_FLAG_READ
},
68 { WM_WINDOWPOSCHANGED
, sizeof(WINDOWPOS
), MMS_FLAG_READ
},
69 { WM_WINDOWPOSCHANGING
, sizeof(WINDOWPOS
), MMS_FLAG_READWRITE
},
72 static PMSGMEMORY FASTCALL
73 FindMsgMemory(UINT Msg
)
75 PMSGMEMORY MsgMemoryEntry
;
77 /* See if this message type is present in the table */
78 for (MsgMemoryEntry
= MsgMemory
;
79 MsgMemoryEntry
< MsgMemory
+ sizeof(MsgMemory
) / sizeof(MSGMEMORY
);
82 if (Msg
== MsgMemoryEntry
->Message
)
84 return MsgMemoryEntry
;
92 MsgMemorySize(PMSGMEMORY MsgMemoryEntry
, WPARAM wParam
, LPARAM lParam
)
95 PUNICODE_STRING WindowName
;
96 PUNICODE_STRING ClassName
;
101 if (MMS_SIZE_WPARAM
== MsgMemoryEntry
->Size
)
105 else if (MMS_SIZE_WPARAMWCHAR
== MsgMemoryEntry
->Size
)
107 Size
= (UINT
) (wParam
* sizeof(WCHAR
));
109 else if (MMS_SIZE_LPARAMSZ
== MsgMemoryEntry
->Size
)
111 Size
= (UINT
) ((wcslen((PWSTR
) lParam
) + 1) * sizeof(WCHAR
));
113 else if (MMS_SIZE_SPECIAL
== MsgMemoryEntry
->Size
)
115 switch(MsgMemoryEntry
->Message
)
119 Cs
= (CREATESTRUCTW
*) lParam
;
120 WindowName
= (PUNICODE_STRING
) Cs
->lpszName
;
121 ClassName
= (PUNICODE_STRING
) Cs
->lpszClass
;
122 Size
= sizeof(CREATESTRUCTW
) + WindowName
->Length
+ sizeof(WCHAR
);
123 if (IS_ATOM(ClassName
->Buffer
))
125 Size
+= sizeof(WCHAR
) + sizeof(ATOM
);
129 Size
+= sizeof(WCHAR
) + ClassName
->Length
+ sizeof(WCHAR
);
134 Size
= wParam
? sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
) : sizeof(RECT
);
138 Size
= sizeof(COPYDATASTRUCT
) + ((PCOPYDATASTRUCT
)lParam
)->cbData
;
141 case WM_COPYGLOBALDATA
:
153 Size
= MsgMemoryEntry
->Size
;
156 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
158 DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode());
166 PackParam(LPARAM
*lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
168 NCCALCSIZE_PARAMS
*UnpackedNcCalcsize
;
169 NCCALCSIZE_PARAMS
*PackedNcCalcsize
;
170 CREATESTRUCTW
*UnpackedCs
;
171 CREATESTRUCTW
*PackedCs
;
172 PUNICODE_STRING WindowName
;
173 PUNICODE_STRING ClassName
;
177 *lParamPacked
= lParam
;
178 if (WM_NCCALCSIZE
== Msg
&& wParam
)
180 UnpackedNcCalcsize
= (NCCALCSIZE_PARAMS
*) lParam
;
181 if (UnpackedNcCalcsize
->lppos
!= (PWINDOWPOS
) (UnpackedNcCalcsize
+ 1))
183 PackedNcCalcsize
= ExAllocatePoolWithTag(PagedPool
,
184 sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
),
186 if (NULL
== PackedNcCalcsize
)
188 DPRINT1("Not enough memory to pack lParam\n");
189 return STATUS_NO_MEMORY
;
191 RtlCopyMemory(PackedNcCalcsize
, UnpackedNcCalcsize
, sizeof(NCCALCSIZE_PARAMS
));
192 PackedNcCalcsize
->lppos
= (PWINDOWPOS
) (PackedNcCalcsize
+ 1);
193 RtlCopyMemory(PackedNcCalcsize
->lppos
, UnpackedNcCalcsize
->lppos
, sizeof(WINDOWPOS
));
194 *lParamPacked
= (LPARAM
) PackedNcCalcsize
;
197 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
199 UnpackedCs
= (CREATESTRUCTW
*) lParam
;
200 WindowName
= (PUNICODE_STRING
) UnpackedCs
->lpszName
;
201 ClassName
= (PUNICODE_STRING
) UnpackedCs
->lpszClass
;
202 Size
= sizeof(CREATESTRUCTW
) + WindowName
->Length
+ sizeof(WCHAR
);
203 if (IS_ATOM(ClassName
->Buffer
))
205 Size
+= sizeof(WCHAR
) + sizeof(ATOM
);
209 Size
+= sizeof(WCHAR
) + ClassName
->Length
+ sizeof(WCHAR
);
211 PackedCs
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
212 if (NULL
== PackedCs
)
214 DPRINT1("Not enough memory to pack lParam\n");
215 return STATUS_NO_MEMORY
;
217 RtlCopyMemory(PackedCs
, UnpackedCs
, sizeof(CREATESTRUCTW
));
218 CsData
= (PCHAR
) (PackedCs
+ 1);
219 PackedCs
->lpszName
= (LPCWSTR
) (CsData
- (PCHAR
) PackedCs
);
220 RtlCopyMemory(CsData
, WindowName
->Buffer
, WindowName
->Length
);
221 CsData
+= WindowName
->Length
;
222 *((WCHAR
*) CsData
) = L
'\0';
223 CsData
+= sizeof(WCHAR
);
224 PackedCs
->lpszClass
= (LPCWSTR
) (CsData
- (PCHAR
) PackedCs
);
225 if (IS_ATOM(ClassName
->Buffer
))
227 *((WCHAR
*) CsData
) = L
'A';
228 CsData
+= sizeof(WCHAR
);
229 *((ATOM
*) CsData
) = (ATOM
)(DWORD_PTR
) ClassName
->Buffer
;
230 CsData
+= sizeof(ATOM
);
234 *((WCHAR
*) CsData
) = L
'S';
235 CsData
+= sizeof(WCHAR
);
236 RtlCopyMemory(CsData
, ClassName
->Buffer
, ClassName
->Length
);
237 CsData
+= ClassName
->Length
;
238 *((WCHAR
*) CsData
) = L
'\0';
239 CsData
+= sizeof(WCHAR
);
241 ASSERT(CsData
== (PCHAR
) PackedCs
+ Size
);
242 *lParamPacked
= (LPARAM
) PackedCs
;
245 return STATUS_SUCCESS
;
249 UnpackParam(LPARAM lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
251 NCCALCSIZE_PARAMS
*UnpackedParams
;
252 NCCALCSIZE_PARAMS
*PackedParams
;
253 PWINDOWPOS UnpackedWindowPos
;
255 if (lParamPacked
== lParam
)
257 return STATUS_SUCCESS
;
260 if (WM_NCCALCSIZE
== Msg
&& wParam
)
262 PackedParams
= (NCCALCSIZE_PARAMS
*) lParamPacked
;
263 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
264 UnpackedWindowPos
= UnpackedParams
->lppos
;
265 RtlCopyMemory(UnpackedParams
, PackedParams
, sizeof(NCCALCSIZE_PARAMS
));
266 UnpackedParams
->lppos
= UnpackedWindowPos
;
267 RtlCopyMemory(UnpackedWindowPos
, PackedParams
+ 1, sizeof(WINDOWPOS
));
268 ExFreePool((PVOID
) lParamPacked
);
270 return STATUS_SUCCESS
;
272 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
274 ExFreePool((PVOID
) lParamPacked
);
276 return STATUS_SUCCESS
;
281 return STATUS_INVALID_PARAMETER
;
288 ( PWINDOW_OBJECT Window
, HWND hWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
290 BOOL SameThread
= FALSE
;
292 if (Window
->ti
== ((PTHREADINFO
)PsGetCurrentThreadWin32Thread()))
295 if ((!SameThread
&& (Window
->ti
->fsHooks
& HOOKID_TO_FLAG(WH_CALLWNDPROC
))) ||
296 (SameThread
&& ISITHOOKED(WH_CALLWNDPROC
)) )
303 co_HOOK_CallHooks( WH_CALLWNDPROC
, HC_ACTION
, SameThread
, (LPARAM
)&CWP
);
311 ( PWINDOW_OBJECT Window
, HWND hWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*uResult
)
313 BOOL SameThread
= FALSE
;
315 if (Window
->ti
== ((PTHREADINFO
)PsGetCurrentThreadWin32Thread()))
318 if ((!SameThread
&& (Window
->ti
->fsHooks
& HOOKID_TO_FLAG(WH_CALLWNDPROCRET
))) ||
319 (SameThread
&& ISITHOOKED(WH_CALLWNDPROCRET
)) )
324 CWPR
.wParam
= wParam
;
325 CWPR
.lParam
= lParam
;
326 CWPR
.lResult
= *uResult
;
327 co_HOOK_CallHooks( WH_CALLWNDPROCRET
, HC_ACTION
, SameThread
, (LPARAM
)&CWPR
);
333 IntDispatchMessage(PMSG pMsg
)
335 LARGE_INTEGER TickCount
;
338 PWINDOW_OBJECT Window
= NULL
;
342 Window
= UserGetWindowObject(pMsg
->hwnd
);
343 if (!Window
|| !Window
->Wnd
) return 0;
346 if (((pMsg
->message
== WM_SYSTIMER
) ||
347 (pMsg
->message
== WM_TIMER
)) &&
350 if (pMsg
->message
== WM_TIMER
)
352 if (ValidateTimerCallback(PsGetCurrentThreadWin32Thread(),Window
,pMsg
->wParam
,pMsg
->lParam
))
354 KeQueryTickCount(&TickCount
);
355 Time
= MsqCalculateMessageTime(&TickCount
);
356 return co_IntCallWindowProc((WNDPROC
)pMsg
->lParam
,
368 PTIMER pTimer
= FindSystemTimer(pMsg
);
369 if (pTimer
&& pTimer
->pfn
)
371 KeQueryTickCount(&TickCount
);
372 Time
= MsqCalculateMessageTime(&TickCount
);
373 pTimer
->pfn(pMsg
->hwnd
, WM_SYSTIMER
, (UINT
)pMsg
->wParam
, Time
);
379 if (!Window
) return 0;
381 retval
= co_IntPostOrSendMessage(pMsg
->hwnd
, pMsg
->message
, pMsg
->wParam
, pMsg
->lParam
);
383 if (pMsg
->message
== WM_PAINT
)
385 /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
386 HRGN hrgn
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
387 co_UserGetUpdateRgn( Window
, hrgn
, TRUE
);
388 GreDeleteObject( hrgn
);
400 BOOL BadChk
= FALSE
, Ret
= TRUE
;
402 DECLARE_RETURN(BOOL
);
404 DPRINT("Enter NtUserCallMsgFilter\n");
405 UserEnterExclusive();
410 ProbeForRead((PVOID
)lpmsg
,
417 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
426 if (BadChk
) RETURN( FALSE
);
428 if (!co_HOOK_CallHooks( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)&Msg
))
430 Ret
= co_HOOK_CallHooks( WH_MSGFILTER
, code
, 0, (LPARAM
)&Msg
);
435 ProbeForWrite((PVOID
)lpmsg
,
438 RtlCopyMemory((PVOID
)lpmsg
,
442 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
447 if (BadChk
) RETURN( FALSE
);
451 DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_
);
457 NtUserDispatchMessage(PMSG UnsafeMsgInfo
)
463 UserEnterExclusive();
466 ProbeForRead(UnsafeMsgInfo
, sizeof(MSG
), 1);
467 RtlCopyMemory(&SafeMsg
, UnsafeMsgInfo
, sizeof(MSG
));
469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
471 SetLastNtError(_SEH2_GetExceptionCode());
476 if (!Hit
) Res
= IntDispatchMessage(&SafeMsg
);
484 NtUserTranslateMessage(LPMSG lpMsg
,
489 DECLARE_RETURN(BOOL
);
491 DPRINT("Enter NtUserTranslateMessage\n");
492 UserEnterExclusive();
494 Status
= MmCopyFromCaller(&SafeMsg
, lpMsg
, sizeof(MSG
));
495 if(!NT_SUCCESS(Status
))
497 SetLastNtError(Status
);
501 RETURN( IntTranslateKbdMessage(&SafeMsg
, dwhkl
));
504 DPRINT("Leave NtUserTranslateMessage: ret=%i\n",_ret_
);
511 co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
)
513 if(!Msg
->hwnd
|| ThreadQueue
->CaptureWindow
)
522 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
527 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
534 case WM_LBUTTONDBLCLK
:
535 case WM_MBUTTONDBLCLK
:
536 case WM_RBUTTONDBLCLK
:
537 case WM_XBUTTONDBLCLK
:
540 PSYSTEM_CURSORINFO CurInfo
;
542 if(!IntGetWindowStationObject(InputWindowStation
))
546 CurInfo
= IntGetSysCursorInfo(InputWindowStation
);
547 wParam
= (WPARAM
)(CurInfo
->ButtonsDown
);
548 ObDereferenceObject(InputWindowStation
);
550 co_IntSendMessage(Msg
->hwnd
, WM_MOUSEMOVE
, wParam
, Msg
->lParam
);
551 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
554 case WM_NCLBUTTONDOWN
:
555 case WM_NCMBUTTONDOWN
:
556 case WM_NCRBUTTONDOWN
:
557 case WM_NCXBUTTONDOWN
:
558 case WM_NCLBUTTONDBLCLK
:
559 case WM_NCMBUTTONDBLCLK
:
560 case WM_NCRBUTTONDBLCLK
:
561 case WM_NCXBUTTONDBLCLK
:
563 co_IntSendMessage(Msg
->hwnd
, WM_NCMOUSEMOVE
, (WPARAM
)Msg
->wParam
, Msg
->lParam
);
564 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
571 co_IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, PWINDOW_OBJECT MsgWindow
,
575 PWINDOW_OBJECT Parent
;
577 ASSERT_REFS_CO(MsgWindow
);
579 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
581 /* eat the message, search again! */
585 Parent
= IntGetParent(MsgWindow
);//fixme: deref retval?
587 /* If no parent window, pass MsgWindows HWND as wParam. Fixes bug #3111 */
588 Result
= co_IntSendMessage(MsgWindow
->hSelf
,
590 (WPARAM
) (Parent
? Parent
->hSelf
: MsgWindow
->hSelf
),
591 (LPARAM
)MAKELONG(*HitTest
, Msg
->message
)
596 case MA_NOACTIVATEANDEAT
:
600 case MA_ACTIVATEANDEAT
:
601 co_IntMouseActivateWindow(MsgWindow
);
605 co_IntMouseActivateWindow(MsgWindow
);
613 co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, USHORT
*HitTest
, BOOL Remove
)
615 PWINDOW_OBJECT Window
;
616 USER_REFERENCE_ENTRY Ref
, DesktopRef
;
618 if(!(Window
= UserGetWindowObject(Msg
->hwnd
)))
620 /* let's just eat the message?! */
624 UserRefObjectCo(Window
, &Ref
);
626 if(ThreadQueue
== Window
->MessageQueue
&&
627 ThreadQueue
->CaptureWindow
!= Window
->hSelf
)
629 /* only send WM_NCHITTEST messages if we're not capturing the window! */
630 *HitTest
= co_IntSendMessage(Window
->hSelf
, WM_NCHITTEST
, 0,
631 MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
));
633 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
635 PWINDOW_OBJECT DesktopWindow
;
636 HWND hDesktop
= IntGetDesktopWindow();
638 if((DesktopWindow
= UserGetWindowObject(hDesktop
)))
642 UserRefObjectCo(DesktopWindow
, &DesktopRef
);
644 co_WinPosWindowFromPoint(DesktopWindow
, Window
->MessageQueue
, &Msg
->pt
, &Wnd
);
649 /* post the message to the other window */
650 Msg
->hwnd
= Wnd
->hSelf
;
651 if(!(Wnd
->Status
& WINDOWSTATUS_DESTROYING
))
653 MsqPostMessage(Wnd
->MessageQueue
, Msg
, FALSE
,
654 Msg
->message
== WM_MOUSEMOVE
? QS_MOUSEMOVE
:
658 /* eat the message */
659 UserDereferenceObject(Wnd
);
660 UserDerefObjectCo(DesktopWindow
);
661 UserDerefObjectCo(Window
);
664 UserDereferenceObject(Wnd
);
667 UserDerefObjectCo(DesktopWindow
);
676 if (gspv
.bMouseClickLock
&& ((Msg
->message
== WM_LBUTTONUP
) || (Msg
->message
== WM_LBUTTONDOWN
)))
678 if (MsqIsClkLck(Msg
, Remove
))
680 // FIXME: drop the message, hack: use WM_NULL
681 Msg
->message
= WM_NULL
;
685 if(IS_BTN_MESSAGE(Msg
->message
, DOWN
))
687 /* generate double click messages, if necessary */
688 if ((((*HitTest
) != HTCLIENT
) ||
689 (Window
->Wnd
->pcls
->style
& CS_DBLCLKS
)) &&
690 MsqIsDblClk(Msg
, Remove
))
692 Msg
->message
+= WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
;
696 if(Msg
->message
!= WM_MOUSEWHEEL
)
699 if ((*HitTest
) != HTCLIENT
)
701 Msg
->message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
702 if((Msg
->message
== WM_NCRBUTTONUP
) &&
703 (((*HitTest
) == HTCAPTION
) || ((*HitTest
) == HTSYSMENU
)))
705 Msg
->message
= WM_CONTEXTMENU
;
706 Msg
->wParam
= (WPARAM
)Window
->hSelf
;
710 Msg
->wParam
= *HitTest
;
712 Msg
->lParam
= MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
);
714 else if(ThreadQueue
->MoveSize
== NULL
&&
715 ThreadQueue
->MenuOwner
== NULL
)
717 /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
718 Msg
->lParam
= MAKELONG(
719 Msg
->pt
.x
- (WORD
)Window
->Wnd
->rcClient
.left
,
720 Msg
->pt
.y
- (WORD
)Window
->Wnd
->rcClient
.top
);
724 UserDerefObjectCo(Window
);
730 * Internal version of PeekMessage() doing all the work
733 co_IntPeekMessage(PUSER_MESSAGE Msg
,
734 PWINDOW_OBJECT Window
,
740 LARGE_INTEGER LargeTickCount
;
741 PUSER_MESSAGE_QUEUE ThreadQueue
;
742 PUSER_MESSAGE Message
;
743 BOOL Present
, RemoveMessages
;
744 USER_REFERENCE_ENTRY Ref
;
746 MOUSEHOOKSTRUCT MHook
;
748 /* The queues and order in which they are checked are documented in the MSDN
749 article on GetMessage() */
751 pti
= PsGetCurrentThreadWin32Thread();
752 ThreadQueue
= pti
->MessageQueue
;
754 /* Inspect RemoveMsg flags */
755 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
756 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
762 KeQueryTickCount(&LargeTickCount
);
763 ThreadQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
765 /* Dispatch sent messages here. */
766 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
769 /* Now look for a quit message. */
771 if (ThreadQueue
->QuitPosted
)
773 /* According to the PSDK, WM_QUIT messages are always returned, regardless
774 of the filter specified */
775 Msg
->Msg
.hwnd
= NULL
;
776 Msg
->Msg
.message
= WM_QUIT
;
777 Msg
->Msg
.wParam
= ThreadQueue
->QuitExitCode
;
779 Msg
->FreeLParam
= FALSE
;
782 ThreadQueue
->QuitPosted
= FALSE
;
787 /* Now check for normal messages. */
788 Present
= co_MsqFindMessage(ThreadQueue
,
797 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
800 MsqDestroyMessage(Message
);
805 /* Check for hardware events. */
806 Present
= co_MsqFindMessage(ThreadQueue
,
815 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
818 MsqDestroyMessage(Message
);
823 /* Check for sent messages again. */
824 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
827 /* Check for paint messages. */
828 if (IntGetPaintMessage(Window
, MsgFilterMin
, MsgFilterMax
, pti
, &Msg
->Msg
, RemoveMessages
))
830 Msg
->FreeLParam
= FALSE
;
834 if (ThreadQueue
->WakeMask
& QS_TIMER
)
835 if (PostTimerMessages(Window
)) // If there are timers ready,
836 goto CheckMessages
; // go back and process them.
838 // LOL! Polling Timer Queue? How much time is spent doing this?
839 /* Check for WM_(SYS)TIMER messages */
840 Present
= MsqGetTimerMessage(ThreadQueue
, Window
, MsgFilterMin
, MsgFilterMax
,
841 &Msg
->Msg
, RemoveMessages
);
844 Msg
->FreeLParam
= FALSE
;
854 PWINDOW_OBJECT MsgWindow
= NULL
;
856 if(Msg
->Msg
.hwnd
&& (MsgWindow
= UserGetWindowObject(Msg
->Msg
.hwnd
)) &&
857 Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
)
861 UserRefObjectCo(MsgWindow
, &Ref
);
863 if(co_IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, TRUE
))
864 /* FIXME - check message filter again, if the message doesn't match anymore,
867 UserDerefObjectCo(MsgWindow
);
868 /* eat the message, search again */
872 if(ThreadQueue
->CaptureWindow
== NULL
)
874 co_IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
875 if((Msg
->Msg
.message
!= WM_MOUSEMOVE
&& Msg
->Msg
.message
!= WM_NCMOUSEMOVE
) &&
876 IS_BTN_MESSAGE(Msg
->Msg
.message
, DOWN
) &&
877 co_IntActivateWindowMouse(ThreadQueue
, &Msg
->Msg
, MsgWindow
, &HitTest
))
879 UserDerefObjectCo(MsgWindow
);
880 /* eat the message, search again */
885 UserDerefObjectCo(MsgWindow
);
889 co_IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
894 // UserDereferenceObject(MsgWindow);
900 if((Msg
->Msg
.hwnd
&& Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
) &&
901 co_IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, FALSE
))
902 /* FIXME - check message filter again, if the message doesn't match anymore,
905 /* eat the message, search again */
909 if ( ISITHOOKED(WH_MOUSE
) &&
910 Msg
->Msg
.message
>= WM_MOUSEFIRST
&&
911 Msg
->Msg
.message
<= WM_MOUSELAST
)
913 MHook
.pt
= Msg
->Msg
.pt
;
914 MHook
.hwnd
= Msg
->Msg
.hwnd
;
915 MHook
.wHitTestCode
= HitTest
;
916 MHook
.dwExtraInfo
= 0;
917 if (co_HOOK_CallHooks( WH_MOUSE
,
918 RemoveMsg
? HC_ACTION
: HC_NOREMOVE
,
922 if (ISITHOOKED(WH_CBT
))
924 MHook
.pt
= Msg
->Msg
.pt
;
925 MHook
.hwnd
= Msg
->Msg
.hwnd
;
926 MHook
.wHitTestCode
= HitTest
;
927 MHook
.dwExtraInfo
= 0;
928 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
,
929 Msg
->Msg
.message
, (LPARAM
)&MHook
);
934 if ( ISITHOOKED(WH_KEYBOARD
) &&
935 (Msg
->Msg
.message
== WM_KEYDOWN
|| Msg
->Msg
.message
== WM_KEYUP
) )
937 if (co_HOOK_CallHooks( WH_KEYBOARD
,
938 RemoveMsg
? HC_ACTION
: HC_NOREMOVE
,
939 LOWORD(Msg
->Msg
.wParam
),
942 if (ISITHOOKED(WH_CBT
))
944 /* skip this message */
945 co_HOOK_CallHooks( WH_CBT
, HCBT_KEYSKIPPED
,
946 LOWORD(Msg
->Msg
.wParam
), Msg
->Msg
.lParam
);
951 // The WH_GETMESSAGE hook enables an application to monitor messages about to
952 // be returned by the GetMessage or PeekMessage function.
953 if (ISITHOOKED(WH_GETMESSAGE
))
955 //DPRINT1("Peek WH_GETMESSAGE -> %x\n",&Msg);
956 co_HOOK_CallHooks( WH_GETMESSAGE
, HC_ACTION
, RemoveMsg
& PM_REMOVE
, (LPARAM
)&Msg
->Msg
);
965 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
973 NTUSERGETMESSAGEINFO Info
;
974 PWINDOW_OBJECT Window
;
975 PMSGMEMORY MsgMemoryEntry
;
979 DECLARE_RETURN(BOOL
);
981 DPRINT("Enter NtUserPeekMessage\n");
982 UserEnterExclusive();
984 if (hWnd
== (HWND
)-1 || hWnd
== (HWND
)0x0000FFFF || hWnd
== (HWND
)0xFFFFFFFF)
988 if (hWnd
&& hWnd
!= (HWND
)1)
990 if (!(Window
= UserGetWindowObject(hWnd
)))
997 Window
= (PWINDOW_OBJECT
)hWnd
;
1000 if (MsgFilterMax
< MsgFilterMin
)
1006 Present
= co_IntPeekMessage(&Msg
, Window
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
);
1011 /* See if this message type is present in the table */
1012 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
1013 if (NULL
== MsgMemoryEntry
)
1015 /* Not present, no copying needed */
1016 Info
.LParamSize
= 0;
1020 /* Determine required size */
1021 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
1023 /* Allocate required amount of user-mode memory */
1024 Info
.LParamSize
= Size
;
1026 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
1027 &Size
, MEM_COMMIT
, PAGE_READWRITE
);
1028 if (! NT_SUCCESS(Status
))
1030 SetLastNtError(Status
);
1033 /* Transfer lParam data to user-mode mem */
1034 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Info
.LParamSize
);
1035 if (! NT_SUCCESS(Status
))
1037 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
1038 &Size
, MEM_RELEASE
);
1039 SetLastNtError(Status
);
1042 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
1044 if (RemoveMsg
&& Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
1046 ExFreePool((void *) Msg
.Msg
.lParam
);
1048 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
1049 if (! NT_SUCCESS(Status
))
1051 SetLastNtError(Status
);
1059 DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_
);
1064 static BOOL FASTCALL
1065 co_IntWaitMessage(PWINDOW_OBJECT Window
,
1070 PUSER_MESSAGE_QUEUE ThreadQueue
;
1074 pti
= PsGetCurrentThreadWin32Thread();
1075 ThreadQueue
= pti
->MessageQueue
;
1079 if (co_IntPeekMessage(&Msg
, Window
, MsgFilterMin
, MsgFilterMax
, PM_NOREMOVE
))
1084 /* Nothing found. Wait for new messages. */
1085 Status
= co_MsqWaitForNewMessages(ThreadQueue
, Window
, MsgFilterMin
, MsgFilterMax
);
1087 while ((STATUS_WAIT_0
<= Status
&& Status
<= STATUS_WAIT_63
) || STATUS_TIMEOUT
== Status
);
1089 SetLastNtError(Status
);
1095 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
1100 * FUNCTION: Get a message from the calling thread's message queue.
1102 * UnsafeMsg - Pointer to the structure which receives the returned message.
1103 * Wnd - Window whose messages are to be retrieved.
1104 * MsgFilterMin - Integer value of the lowest message value to be
1106 * MsgFilterMax - Integer value of the highest message value to be
1111 NTUSERGETMESSAGEINFO Info
;
1113 /* FIXME: if initialization is removed, gcc complains that this may be used before initialization. Please review */
1114 PWINDOW_OBJECT Window
= NULL
;
1115 PMSGMEMORY MsgMemoryEntry
;
1119 DECLARE_RETURN(BOOL
);
1120 // USER_REFERENCE_ENTRY Ref;
1122 DPRINT("Enter NtUserGetMessage\n");
1123 UserEnterExclusive();
1125 /* Validate input */
1126 if (hWnd
&& !(Window
= UserGetWindowObject(hWnd
)))
1131 // if (Window) UserRefObjectCo(Window, &Ref);
1133 if (MsgFilterMax
< MsgFilterMin
)
1141 GotMessage
= co_IntPeekMessage(&Msg
, Window
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
);
1145 /* See if this message type is present in the table */
1146 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
1147 if (NULL
== MsgMemoryEntry
)
1149 /* Not present, no copying needed */
1150 Info
.LParamSize
= 0;
1154 /* Determine required size */
1155 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
1157 /* Allocate required amount of user-mode memory */
1158 Info
.LParamSize
= Size
;
1160 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
1161 &Size
, MEM_COMMIT
, PAGE_READWRITE
);
1163 if (! NT_SUCCESS(Status
))
1165 SetLastNtError(Status
);
1168 /* Transfer lParam data to user-mode mem */
1169 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Info
.LParamSize
);
1170 if (! NT_SUCCESS(Status
))
1172 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
1173 &Size
, MEM_DECOMMIT
);
1174 SetLastNtError(Status
);
1177 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
1179 if (Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
1181 ExFreePool((void *) Msg
.Msg
.lParam
);
1183 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
1184 if (! NT_SUCCESS(Status
))
1186 SetLastNtError(Status
);
1190 else if (! co_IntWaitMessage(Window
, MsgFilterMin
, MsgFilterMax
))
1195 while (! GotMessage
);
1197 RETURN( WM_QUIT
!= Info
.Msg
.message
);
1200 // if (Window) UserDerefObjectCo(Window);
1202 DPRINT("Leave NtUserGetMessage\n");
1208 static NTSTATUS FASTCALL
1209 CopyMsgToKernelMem(MSG
*KernelModeMsg
, MSG
*UserModeMsg
, PMSGMEMORY MsgMemoryEntry
)
1216 *KernelModeMsg
= *UserModeMsg
;
1218 /* See if this message type is present in the table */
1219 if (NULL
== MsgMemoryEntry
)
1221 /* Not present, no copying needed */
1222 return STATUS_SUCCESS
;
1225 /* Determine required size */
1226 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1230 /* Allocate kernel mem */
1231 KernelMem
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
1232 if (NULL
== KernelMem
)
1234 DPRINT1("Not enough memory to copy message to kernel mem\n");
1235 return STATUS_NO_MEMORY
;
1237 KernelModeMsg
->lParam
= (LPARAM
) KernelMem
;
1239 /* Copy data if required */
1240 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_READ
))
1242 Status
= MmCopyFromCaller(KernelMem
, (PVOID
) UserModeMsg
->lParam
, Size
);
1243 if (! NT_SUCCESS(Status
))
1245 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
1246 ExFreePoolWithTag(KernelMem
, TAG_MSG
);
1252 /* Make sure we don't pass any secrets to usermode */
1253 RtlZeroMemory(KernelMem
, Size
);
1258 KernelModeMsg
->lParam
= 0;
1261 return STATUS_SUCCESS
;
1264 static NTSTATUS FASTCALL
1265 CopyMsgToUserMem(MSG
*UserModeMsg
, MSG
*KernelModeMsg
)
1268 PMSGMEMORY MsgMemoryEntry
;
1271 /* See if this message type is present in the table */
1272 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
1273 if (NULL
== MsgMemoryEntry
)
1275 /* Not present, no copying needed */
1276 return STATUS_SUCCESS
;
1279 /* Determine required size */
1280 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1284 /* Copy data if required */
1285 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_WRITE
))
1287 Status
= MmCopyToCaller((PVOID
) UserModeMsg
->lParam
, (PVOID
) KernelModeMsg
->lParam
, Size
);
1288 if (! NT_SUCCESS(Status
))
1290 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1291 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1296 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1299 return STATUS_SUCCESS
;
1303 UserPostThreadMessage( DWORD idThread
,
1310 PTHREADINFO pThread
;
1311 LARGE_INTEGER LargeTickCount
;
1314 DPRINT1("UserPostThreadMessage wParam 0x%x lParam 0x%x\n", wParam
,lParam
);
1316 if (FindMsgMemory(Msg
) != 0)
1318 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY
);
1322 Status
= PsLookupThreadByThreadId((HANDLE
)idThread
,&peThread
);
1324 if( Status
== STATUS_SUCCESS
)
1326 pThread
= (PTHREADINFO
)peThread
->Tcb
.Win32Thread
;
1327 if( !pThread
|| !pThread
->MessageQueue
)
1329 ObDereferenceObject( peThread
);
1333 Message
.hwnd
= NULL
;
1334 Message
.message
= Msg
;
1335 Message
.wParam
= wParam
;
1336 Message
.lParam
= lParam
;
1337 IntGetCursorLocation(pThread
->Desktop
->WindowStation
, &Message
.pt
);
1338 KeQueryTickCount(&LargeTickCount
);
1339 pThread
->timeLast
= Message
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1340 MsqPostMessage(pThread
->MessageQueue
, &Message
, FALSE
, QS_POSTMESSAGE
);
1341 ObDereferenceObject( peThread
);
1346 SetLastNtError( Status
);
1352 UserPostMessage(HWND Wnd
,
1359 LARGE_INTEGER LargeTickCount
;
1361 if (FindMsgMemory(Msg
) != 0)
1363 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY
);
1368 return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
1373 pti
= PsGetCurrentThreadWin32Thread();
1374 if (Wnd
== HWND_BROADCAST
)
1377 PWINDOW_OBJECT DesktopWindow
;
1380 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1381 List
= IntWinListChildren(DesktopWindow
);
1385 for (i
= 0; List
[i
]; i
++)
1386 UserPostMessage(List
[i
], Msg
, wParam
, lParam
);
1392 PWINDOW_OBJECT Window
;
1394 Window
= UserGetWindowObject(Wnd
);
1399 if(Window
->Status
& WINDOWSTATUS_DESTROYING
)
1401 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd
);
1402 /* FIXME - last error code? */
1408 MsqPostQuitMessage(Window
->MessageQueue
, wParam
);
1413 Message
.message
= Msg
;
1414 Message
.wParam
= wParam
;
1415 Message
.lParam
= lParam
;
1416 IntGetCursorLocation(pti
->Desktop
->WindowStation
, &Message
.pt
);
1417 KeQueryTickCount(&LargeTickCount
);
1418 pti
->timeLast
= Message
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1419 MsqPostMessage(Window
->MessageQueue
, &Message
, FALSE
, QS_POSTMESSAGE
);
1427 NtUserPostMessage(HWND hWnd
,
1432 DECLARE_RETURN(BOOL
);
1434 DPRINT("Enter NtUserPostMessage\n");
1435 UserEnterExclusive();
1437 RETURN( UserPostMessage(hWnd
, Msg
, wParam
, lParam
));
1440 DPRINT("Leave NtUserPostMessage, ret=%i\n",_ret_
);
1448 NtUserPostThreadMessage(DWORD idThread
,
1453 DECLARE_RETURN(BOOL
);
1455 DPRINT("Enter NtUserPostThreadMessage\n");
1456 UserEnterExclusive();
1458 RETURN( UserPostThreadMessage( idThread
,
1464 DPRINT("Leave NtUserPostThreadMessage, ret=%i\n",_ret_
);
1470 NtUserQuerySendMessage(DWORD Unknown0
)
1478 co_IntSendMessage(HWND hWnd
,
1483 ULONG_PTR Result
= 0;
1484 if(co_IntSendMessageTimeout(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1486 return (LRESULT
)Result
;
1493 co_IntSendMessageTimeoutSingle(HWND hWnd
,
1503 PWINDOW_OBJECT Window
= NULL
;
1504 PMSGMEMORY MsgMemoryEntry
;
1505 INT lParamBufferSize
;
1506 LPARAM lParamPacked
;
1507 PTHREADINFO Win32Thread
;
1508 DECLARE_RETURN(LRESULT
);
1509 USER_REFERENCE_ENTRY Ref
;
1511 if (!(Window
= UserGetWindowObject(hWnd
)))
1516 UserRefObjectCo(Window
, &Ref
);
1518 Win32Thread
= PsGetCurrentThreadWin32Thread();
1520 IntCallWndProc( Window
, hWnd
, Msg
, wParam
, lParam
);
1522 if (NULL
!= Win32Thread
&&
1523 Window
->MessageQueue
== Win32Thread
->MessageQueue
)
1525 if (Win32Thread
->TIF_flags
& TIF_INCLEANUP
)
1527 /* Never send messages to exiting threads */
1531 /* See if this message type is present in the table */
1532 MsgMemoryEntry
= FindMsgMemory(Msg
);
1533 if (NULL
== MsgMemoryEntry
)
1535 lParamBufferSize
= -1;
1539 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
1542 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
)))
1544 DPRINT1("Failed to pack message parameters\n");
1548 Result
= (ULONG_PTR
)co_IntCallWindowProc( Window
->Wnd
->lpfnWndProc
,
1549 !Window
->Wnd
->Unicode
,
1560 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, (LRESULT
*)uResult
);
1562 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
)))
1564 DPRINT1("Failed to unpack message parameters\n");
1571 if (uFlags
& SMTO_ABORTIFHUNG
&& MsqIsHung(Window
->MessageQueue
))
1573 /* FIXME - Set a LastError? */
1577 if (Window
->Status
& WINDOWSTATUS_DESTROYING
)
1579 /* FIXME - last error? */
1580 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd
);
1586 Status
= co_MsqSendMessage( Window
->MessageQueue
,
1592 (uFlags
& SMTO_BLOCK
),
1596 while ((STATUS_TIMEOUT
== Status
) &&
1597 (uFlags
& SMTO_NOTIMEOUTIFNOTHUNG
) &&
1598 !MsqIsHung(Window
->MessageQueue
));
1600 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, (LRESULT
*)uResult
);
1602 if (STATUS_TIMEOUT
== Status
)
1606 Microsoft Windows 2000: If GetLastError returns zero, then the function
1608 XP+ : If the function fails or times out, the return value is zero.
1609 To get extended error information, call GetLastError. If GetLastError
1610 returns ERROR_TIMEOUT, then the function timed out.
1612 SetLastWin32Error(ERROR_TIMEOUT
);
1615 else if (! NT_SUCCESS(Status
))
1617 SetLastNtError(Status
);
1624 if (Window
) UserDerefObjectCo(Window
);
1629 co_IntSendMessageTimeout(HWND hWnd
,
1637 PWINDOW_OBJECT DesktopWindow
;
1641 if (HWND_BROADCAST
!= hWnd
)
1643 return co_IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1646 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1647 if (NULL
== DesktopWindow
)
1649 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1653 Children
= IntWinListChildren(DesktopWindow
);
1654 if (NULL
== Children
)
1659 for (Child
= Children
; NULL
!= *Child
; Child
++)
1661 co_IntSendMessageTimeoutSingle(*Child
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1664 ExFreePool(Children
);
1666 return (LRESULT
) TRUE
;
1670 /* This function posts a message if the destination's message queue belongs to
1671 another thread, otherwise it sends the message. It does not support broadcast
1674 co_IntPostOrSendMessage(HWND hWnd
,
1681 PWINDOW_OBJECT Window
;
1683 if(hWnd
== HWND_BROADCAST
)
1688 if(!(Window
= UserGetWindowObject(hWnd
)))
1693 pti
= PsGetCurrentThreadWin32Thread();
1694 if(Window
->MessageQueue
!= pti
->MessageQueue
&& FindMsgMemory(Msg
) ==0)
1696 Result
= UserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1700 if(!co_IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
)) {
1705 return (LRESULT
)Result
;
1709 co_IntDoSendMessage(HWND hWnd
,
1714 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1717 LRESULT Result
= TRUE
;
1719 PWINDOW_OBJECT Window
= NULL
;
1720 NTUSERSENDMESSAGEINFO Info
;
1723 PMSGMEMORY MsgMemoryEntry
;
1725 RtlZeroMemory(&Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1727 /* FIXME: Call hooks. */
1728 if (HWND_BROADCAST
!= hWnd
)
1730 Window
= UserGetWindowObject(hWnd
);
1733 /* Tell usermode to not touch this one */
1734 Info
.HandledByKernel
= TRUE
;
1735 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1742 /* FIXME: Check for an exiting window. */
1744 /* See if the current thread can handle the message */
1745 pti
= PsGetCurrentThreadWin32Thread();
1746 if (HWND_BROADCAST
!= hWnd
&& NULL
!= pti
&&
1747 Window
->MessageQueue
== pti
->MessageQueue
)
1749 /* Gather the information usermode needs to call the window proc directly */
1750 Info
.HandledByKernel
= FALSE
;
1752 Status
= MmCopyFromCaller(&(Info
.Ansi
), &(UnsafeInfo
->Ansi
),
1754 if (! NT_SUCCESS(Status
))
1756 Info
.Ansi
= ! Window
->Wnd
->Unicode
;
1759 IntCallWndProc( Window
, hWnd
, Msg
, wParam
, lParam
);
1761 Info
.Ansi
= !Window
->Wnd
->Unicode
;
1762 Info
.Proc
= Window
->Wnd
->lpfnWndProc
;
1764 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, &Result
);
1768 /* Must be handled by other thread */
1769 // if (HWND_BROADCAST != hWnd)
1771 // UserDereferenceObject(Window);
1773 Info
.HandledByKernel
= TRUE
;
1774 UserModeMsg
.hwnd
= hWnd
;
1775 UserModeMsg
.message
= Msg
;
1776 UserModeMsg
.wParam
= wParam
;
1777 UserModeMsg
.lParam
= lParam
;
1778 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1779 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1780 if (! NT_SUCCESS(Status
))
1782 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1783 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1784 return (dsm
? 0 : -1);
1788 Result
= co_IntSendMessage(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1789 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
);
1793 Result
= co_IntSendMessageTimeout(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1794 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
,
1795 dsm
->uFlags
, dsm
->uTimeout
, &dsm
->Result
);
1797 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
1798 if (! NT_SUCCESS(Status
))
1800 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1801 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1802 return(dsm
? 0 : -1);
1806 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1807 if (! NT_SUCCESS(Status
))
1809 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1812 return (LRESULT
)Result
;
1816 NtUserSendMessageTimeout(HWND hWnd
,
1823 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1827 DECLARE_RETURN(BOOL
);
1829 DPRINT("Enter NtUserSendMessageTimeout\n");
1830 UserEnterExclusive();
1832 dsm
.uFlags
= uFlags
;
1833 dsm
.uTimeout
= uTimeout
;
1834 Result
= co_IntDoSendMessage(hWnd
, Msg
, wParam
, lParam
, &dsm
, UnsafeInfo
);
1835 if(uResult
!= NULL
&& Result
!= 0)
1839 Status
= MmCopyToCaller(uResult
, &dsm
.Result
, sizeof(ULONG_PTR
));
1840 if(!NT_SUCCESS(Status
))
1842 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1849 DPRINT("Leave NtUserSendMessageTimeout, ret=%i\n",_ret_
);
1855 NtUserSendMessage(HWND Wnd
,
1859 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1861 DECLARE_RETURN(BOOL
);
1863 DPRINT("Enter NtUserSendMessage\n");
1864 UserEnterExclusive();
1866 RETURN(co_IntDoSendMessage(Wnd
, Msg
, wParam
, lParam
, NULL
, UnsafeInfo
));
1869 DPRINT("Leave NtUserSendMessage, ret=%i\n",_ret_
);
1876 UserSendNotifyMessage(HWND hWnd
,
1883 if (FindMsgMemory(Msg
) != 0)
1885 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY
);
1889 // Basicly the same as IntPostOrSendMessage
1890 if (hWnd
== HWND_BROADCAST
) //Handle Broadcast
1893 PWINDOW_OBJECT DesktopWindow
;
1896 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1897 List
= IntWinListChildren(DesktopWindow
);
1901 for (i
= 0; List
[i
]; i
++)
1903 UserSendNotifyMessage(List
[i
], Msg
, wParam
, lParam
);
1912 PWINDOW_OBJECT Window
;
1915 if(!(Window
= UserGetWindowObject(hWnd
))) return FALSE
;
1917 pti
= PsGetCurrentThreadWin32Thread();
1918 if(Window
->MessageQueue
!= pti
->MessageQueue
)
1919 { // Send message w/o waiting for it.
1920 Result
= UserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1923 { // Handle message and callback.
1924 Message
.hwnd
= hWnd
;
1925 Message
.message
= Msg
;
1926 Message
.wParam
= wParam
;
1927 Message
.lParam
= lParam
;
1929 Result
= co_IntSendMessageTimeoutSingle( hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &PResult
);
1937 NtUserWaitMessage(VOID
)
1939 DECLARE_RETURN(BOOL
);
1941 DPRINT("EnterNtUserWaitMessage\n");
1942 UserEnterExclusive();
1944 RETURN(co_IntWaitMessage(NULL
, 0, 0));
1947 DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_
);
1953 IntGetQueueStatus(BOOL ClearChanges
)
1956 PUSER_MESSAGE_QUEUE Queue
;
1958 DECLARE_RETURN(DWORD
);
1960 DPRINT("Enter IntGetQueueStatus\n");
1962 pti
= PsGetCurrentThreadWin32Thread();
1963 Queue
= pti
->MessageQueue
;
1965 Result
= MAKELONG(Queue
->QueueBits
, Queue
->ChangedBits
);
1968 Queue
->ChangedBits
= 0;
1974 DPRINT("Leave IntGetQueueStatus, ret=%i\n",_ret_
);
1979 IntInitMessagePumpHook()
1981 if (((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->pcti
)
1983 ((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->pcti
->dwcPumpHook
++;
1990 IntUninitMessagePumpHook()
1992 if (((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->pcti
)
1994 if (((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->pcti
->dwcPumpHook
<= 0)
1998 ((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->pcti
->dwcPumpHook
--;
2011 ULONG_PTR ResultInfo
,
2012 DWORD dwType
, // fnID?
2015 LRESULT lResult
= 0;
2017 BOOL BadChk
= FALSE
;
2018 PWINDOW_OBJECT Window
= NULL
;
2019 USER_REFERENCE_ENTRY Ref
;
2021 UserEnterExclusive();
2023 /* Validate input */
2024 if (hWnd
&& (hWnd
!= INVALID_HANDLE_VALUE
) && !(Window
= UserGetWindowObject(hWnd
)))
2031 case FNID_DEFWINDOWPROC
:
2032 UserRefObjectCo(Window
, &Ref
);
2033 lResult
= IntDefWindowProc(Window
, Msg
, wParam
, lParam
, Ansi
);
2035 UserDerefObjectCo(Window
);
2037 case FNID_SENDNOTIFYMESSAGE
:
2038 Ret
= UserSendNotifyMessage(hWnd
, Msg
, wParam
, lParam
);
2040 case FNID_BROADCASTSYSTEMMESSAGE
:
2043 DWORD_PTR RetVal
= 0;
2049 ProbeForWrite((PVOID
)ResultInfo
,
2050 sizeof(BROADCASTPARM
),
2052 RtlCopyMemory(&parm
, (PVOID
)ResultInfo
, sizeof(BROADCASTPARM
));
2054 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2064 if ( parm
.recipients
& BSM_ALLDESKTOPS
||
2065 parm
.recipients
== BSM_ALLCOMPONENTS
)
2068 else if (parm
.recipients
& BSM_APPLICATIONS
)
2070 if (parm
.flags
& BSF_QUERY
)
2072 if (parm
.flags
& BSF_FORCEIFHUNG
|| parm
.flags
& BSF_NOHANG
)
2074 co_IntSendMessageTimeout( HWND_BROADCAST
,
2082 else if (parm
.flags
& BSF_NOTIMEOUTIFNOTHUNG
)
2084 co_IntSendMessageTimeout( HWND_BROADCAST
,
2088 SMTO_NOTIMEOUTIFNOTHUNG
,
2094 co_IntSendMessageTimeout( HWND_BROADCAST
,
2103 else if (parm
.flags
& BSF_POSTMESSAGE
)
2105 Ret
= UserPostMessage(HWND_BROADCAST
, Msg
, wParam
, lParam
);
2107 else if ( parm
.flags
& BSF_SENDNOTIFYMESSAGE
)
2109 Ret
= UserSendNotifyMessage(HWND_BROADCAST
, Msg
, wParam
, lParam
);
2114 case FNID_SENDMESSAGECALLBACK
:
2116 // CallNextHook bypass.
2117 case FNID_CALLWNDPROC
:
2118 case FNID_CALLWNDPROCRET
:
2120 PCLIENTINFO ClientInfo
= GetWin32ClientInfo();
2121 PHOOK NextObj
, Hook
= ClientInfo
->phkCurrent
;
2123 if (!ClientInfo
|| !Hook
) break;
2125 UserReferenceObject(Hook
);
2127 if (Hook
->Thread
&& (Hook
->Thread
!= PsGetCurrentThread()))
2129 UserDereferenceObject(Hook
);
2133 NextObj
= IntGetNextHook(Hook
);
2134 ClientInfo
->phkCurrent
= NextObj
;
2136 if ( Hook
->HookId
== WH_CALLWNDPROC
)
2141 CWP
.wParam
= wParam
;
2142 CWP
.lParam
= lParam
;
2143 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook
, NextObj
);
2145 lResult
= co_IntCallHookProc( Hook
->HookId
,
2147 ((ClientInfo
->CI_flags
& CI_CURTHPRHOOK
) ? 1 : 0),
2158 CWPR
.wParam
= wParam
;
2159 CWPR
.lParam
= lParam
;
2160 CWPR
.lResult
= ClientInfo
->dwHookData
;
2162 lResult
= co_IntCallHookProc( Hook
->HookId
,
2164 ((ClientInfo
->CI_flags
& CI_CURTHPRHOOK
) ? 1 : 0),
2170 UserDereferenceObject(Hook
);
2171 lResult
= (LRESULT
) NextObj
;
2178 case FNID_DEFWINDOWPROC
:
2179 case FNID_CALLWNDPROC
:
2180 case FNID_CALLWNDPROCRET
:
2185 ProbeForWrite((PVOID
)ResultInfo
, sizeof(LRESULT
), 1);
2186 RtlCopyMemory((PVOID
)ResultInfo
, &lResult
, sizeof(LRESULT
));
2188 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2201 return BadChk
? FALSE
: Ret
;
2204 #define INFINITE 0xFFFFFFFF
2205 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2209 NtUserWaitForInputIdle(
2211 IN DWORD dwMilliseconds
,
2215 PPROCESSINFO W32Process
;
2218 LARGE_INTEGER Timeout
;
2219 ULONGLONG StartTime
, Run
, Elapsed
= 0;
2221 UserEnterExclusive();
2223 Status
= ObReferenceObjectByHandle(hProcess
,
2224 PROCESS_QUERY_INFORMATION
,
2230 if (!NT_SUCCESS(Status
))
2233 SetLastNtError(Status
);
2237 W32Process
= (PPROCESSINFO
)Process
->Win32Process
;
2240 ObDereferenceObject(Process
);
2242 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2246 EngCreateEvent((PEVENT
*)&W32Process
->InputIdleEvent
);
2248 Handles
[0] = Process
;
2249 Handles
[1] = W32Process
->InputIdleEvent
;
2253 ObDereferenceObject(Process
);
2255 return STATUS_SUCCESS
; /* no event to wait on */
2258 StartTime
= EngGetTickCount();
2260 Run
= dwMilliseconds
;
2262 DPRINT("WFII: waiting for %p\n", Handles
[1] );
2265 Timeout
.QuadPart
= Run
- Elapsed
;
2267 Status
= KeWaitForMultipleObjects( 2,
2273 dwMilliseconds
== INFINITE
? NULL
: &Timeout
,
2275 UserEnterExclusive();
2277 if (!NT_SUCCESS(Status
))
2279 SetLastNtError(Status
);
2280 Status
= WAIT_FAILED
;
2287 Status
= WAIT_FAILED
;
2293 co_IntPeekMessage( &Msg
, 0, 0, 0, PM_REMOVE
| PM_QS_SENDMESSAGE
);
2297 case STATUS_USER_APC
:
2298 case STATUS_ALERTED
:
2299 case STATUS_TIMEOUT
:
2300 DPRINT1("WFII: timeout\n");
2301 Status
= STATUS_TIMEOUT
;
2305 DPRINT1("WFII: finished\n");
2306 Status
= STATUS_SUCCESS
;
2310 if (dwMilliseconds
!= INFINITE
)
2312 Elapsed
= EngGetTickCount() - StartTime
;
2315 Status
= STATUS_TIMEOUT
;
2322 if (W32Process
->InputIdleEvent
)
2324 EngDeleteEvent((PEVENT
)W32Process
->InputIdleEvent
);
2325 W32Process
->InputIdleEvent
= NULL
;
2327 ObDereferenceObject(Process
);