2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
23 * FILE: subsys/win32k/ntuser/message.c
24 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * 06-06-2001 CSH Created
29 /* INCLUDES ******************************************************************/
42 DOSENDMESSAGE
, *PDOSENDMESSAGE
;
44 /* FUNCTIONS *****************************************************************/
47 IntInitMessageImpl(VOID
)
49 return STATUS_SUCCESS
;
53 IntCleanupMessageImpl(VOID
)
55 return STATUS_SUCCESS
;
58 #define MMS_SIZE_WPARAM -1
59 #define MMS_SIZE_WPARAMWCHAR -2
60 #define MMS_SIZE_LPARAMSZ -3
61 #define MMS_SIZE_SPECIAL -4
62 #define MMS_FLAG_READ 0x01
63 #define MMS_FLAG_WRITE 0x02
64 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
65 typedef struct tagMSGMEMORY
71 MSGMEMORY
, *PMSGMEMORY
;
73 static MSGMEMORY MsgMemory
[] =
75 { WM_CREATE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
76 { WM_DDE_ACK
, sizeof(KMDDELPARAM
), MMS_FLAG_READ
},
77 { WM_DDE_EXECUTE
, MMS_SIZE_WPARAM
, MMS_FLAG_READ
},
78 { WM_GETMINMAXINFO
, sizeof(MINMAXINFO
), MMS_FLAG_READWRITE
},
79 { WM_GETTEXT
, MMS_SIZE_WPARAMWCHAR
, MMS_FLAG_WRITE
},
80 { WM_NCCALCSIZE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
81 { WM_NCCREATE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
82 { WM_SETTEXT
, MMS_SIZE_LPARAMSZ
, MMS_FLAG_READ
},
83 { WM_STYLECHANGED
, sizeof(STYLESTRUCT
), MMS_FLAG_READ
},
84 { WM_STYLECHANGING
, sizeof(STYLESTRUCT
), MMS_FLAG_READWRITE
},
85 { WM_COPYDATA
, MMS_SIZE_SPECIAL
, MMS_FLAG_READ
},
86 { WM_WINDOWPOSCHANGED
, sizeof(WINDOWPOS
), MMS_FLAG_READ
},
87 { WM_WINDOWPOSCHANGING
, sizeof(WINDOWPOS
), MMS_FLAG_READWRITE
},
90 static PMSGMEMORY FASTCALL
91 FindMsgMemory(UINT Msg
)
93 PMSGMEMORY MsgMemoryEntry
;
95 /* See if this message type is present in the table */
96 for (MsgMemoryEntry
= MsgMemory
;
97 MsgMemoryEntry
< MsgMemory
+ sizeof(MsgMemory
) / sizeof(MSGMEMORY
);
100 if (Msg
== MsgMemoryEntry
->Message
)
102 return MsgMemoryEntry
;
110 MsgMemorySize(PMSGMEMORY MsgMemoryEntry
, WPARAM wParam
, LPARAM lParam
)
113 PUNICODE_STRING WindowName
;
114 PUNICODE_STRING ClassName
;
119 if (MMS_SIZE_WPARAM
== MsgMemoryEntry
->Size
)
123 else if (MMS_SIZE_WPARAMWCHAR
== MsgMemoryEntry
->Size
)
125 Size
= (UINT
) (wParam
* sizeof(WCHAR
));
127 else if (MMS_SIZE_LPARAMSZ
== MsgMemoryEntry
->Size
)
129 Size
= (UINT
) ((wcslen((PWSTR
) lParam
) + 1) * sizeof(WCHAR
));
131 else if (MMS_SIZE_SPECIAL
== MsgMemoryEntry
->Size
)
133 switch(MsgMemoryEntry
->Message
)
137 Cs
= (CREATESTRUCTW
*) lParam
;
138 WindowName
= (PUNICODE_STRING
) Cs
->lpszName
;
139 ClassName
= (PUNICODE_STRING
) Cs
->lpszClass
;
140 Size
= sizeof(CREATESTRUCTW
) + WindowName
->Length
+ sizeof(WCHAR
);
141 if (IS_ATOM(ClassName
->Buffer
))
143 Size
+= sizeof(WCHAR
) + sizeof(ATOM
);
147 Size
+= sizeof(WCHAR
) + ClassName
->Length
+ sizeof(WCHAR
);
152 Size
= wParam
? sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
) : sizeof(RECT
);
156 Size
= sizeof(COPYDATASTRUCT
) + ((PCOPYDATASTRUCT
)lParam
)->cbData
;
159 case WM_COPYGLOBALDATA
:
171 Size
= MsgMemoryEntry
->Size
;
174 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
176 DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode());
184 PackParam(LPARAM
*lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
186 NCCALCSIZE_PARAMS
*UnpackedNcCalcsize
;
187 NCCALCSIZE_PARAMS
*PackedNcCalcsize
;
188 CREATESTRUCTW
*UnpackedCs
;
189 CREATESTRUCTW
*PackedCs
;
190 PUNICODE_STRING WindowName
;
191 PUNICODE_STRING ClassName
;
195 *lParamPacked
= lParam
;
196 if (WM_NCCALCSIZE
== Msg
&& wParam
)
198 UnpackedNcCalcsize
= (NCCALCSIZE_PARAMS
*) lParam
;
199 if (UnpackedNcCalcsize
->lppos
!= (PWINDOWPOS
) (UnpackedNcCalcsize
+ 1))
201 PackedNcCalcsize
= ExAllocatePoolWithTag(PagedPool
,
202 sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
),
204 if (NULL
== PackedNcCalcsize
)
206 DPRINT1("Not enough memory to pack lParam\n");
207 return STATUS_NO_MEMORY
;
209 RtlCopyMemory(PackedNcCalcsize
, UnpackedNcCalcsize
, sizeof(NCCALCSIZE_PARAMS
));
210 PackedNcCalcsize
->lppos
= (PWINDOWPOS
) (PackedNcCalcsize
+ 1);
211 RtlCopyMemory(PackedNcCalcsize
->lppos
, UnpackedNcCalcsize
->lppos
, sizeof(WINDOWPOS
));
212 *lParamPacked
= (LPARAM
) PackedNcCalcsize
;
215 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
217 UnpackedCs
= (CREATESTRUCTW
*) lParam
;
218 WindowName
= (PUNICODE_STRING
) UnpackedCs
->lpszName
;
219 ClassName
= (PUNICODE_STRING
) UnpackedCs
->lpszClass
;
220 Size
= sizeof(CREATESTRUCTW
) + WindowName
->Length
+ sizeof(WCHAR
);
221 if (IS_ATOM(ClassName
->Buffer
))
223 Size
+= sizeof(WCHAR
) + sizeof(ATOM
);
227 Size
+= sizeof(WCHAR
) + ClassName
->Length
+ sizeof(WCHAR
);
229 PackedCs
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
230 if (NULL
== PackedCs
)
232 DPRINT1("Not enough memory to pack lParam\n");
233 return STATUS_NO_MEMORY
;
235 RtlCopyMemory(PackedCs
, UnpackedCs
, sizeof(CREATESTRUCTW
));
236 CsData
= (PCHAR
) (PackedCs
+ 1);
237 PackedCs
->lpszName
= (LPCWSTR
) (CsData
- (PCHAR
) PackedCs
);
238 RtlCopyMemory(CsData
, WindowName
->Buffer
, WindowName
->Length
);
239 CsData
+= WindowName
->Length
;
240 *((WCHAR
*) CsData
) = L
'\0';
241 CsData
+= sizeof(WCHAR
);
242 PackedCs
->lpszClass
= (LPCWSTR
) (CsData
- (PCHAR
) PackedCs
);
243 if (IS_ATOM(ClassName
->Buffer
))
245 *((WCHAR
*) CsData
) = L
'A';
246 CsData
+= sizeof(WCHAR
);
247 *((ATOM
*) CsData
) = (ATOM
)(DWORD_PTR
) ClassName
->Buffer
;
248 CsData
+= sizeof(ATOM
);
252 *((WCHAR
*) CsData
) = L
'S';
253 CsData
+= sizeof(WCHAR
);
254 RtlCopyMemory(CsData
, ClassName
->Buffer
, ClassName
->Length
);
255 CsData
+= ClassName
->Length
;
256 *((WCHAR
*) CsData
) = L
'\0';
257 CsData
+= sizeof(WCHAR
);
259 ASSERT(CsData
== (PCHAR
) PackedCs
+ Size
);
260 *lParamPacked
= (LPARAM
) PackedCs
;
263 return STATUS_SUCCESS
;
267 UnpackParam(LPARAM lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
269 NCCALCSIZE_PARAMS
*UnpackedParams
;
270 NCCALCSIZE_PARAMS
*PackedParams
;
271 PWINDOWPOS UnpackedWindowPos
;
273 if (lParamPacked
== lParam
)
275 return STATUS_SUCCESS
;
278 if (WM_NCCALCSIZE
== Msg
&& wParam
)
280 PackedParams
= (NCCALCSIZE_PARAMS
*) lParamPacked
;
281 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
282 UnpackedWindowPos
= UnpackedParams
->lppos
;
283 RtlCopyMemory(UnpackedParams
, PackedParams
, sizeof(NCCALCSIZE_PARAMS
));
284 UnpackedParams
->lppos
= UnpackedWindowPos
;
285 RtlCopyMemory(UnpackedWindowPos
, PackedParams
+ 1, sizeof(WINDOWPOS
));
286 ExFreePool((PVOID
) lParamPacked
);
288 return STATUS_SUCCESS
;
290 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
292 ExFreePool((PVOID
) lParamPacked
);
294 return STATUS_SUCCESS
;
299 return STATUS_INVALID_PARAMETER
;
306 ( PWINDOW_OBJECT Window
, HWND hWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
308 BOOL SameThread
= FALSE
;
310 if (Window
->ti
== ((PTHREADINFO
)PsGetCurrentThreadWin32Thread())->ThreadInfo
)
313 if ((!SameThread
&& (Window
->ti
->fsHooks
& HOOKID_TO_FLAG(WH_CALLWNDPROC
))) ||
314 (SameThread
&& ISITHOOKED(WH_CALLWNDPROC
)) )
321 co_HOOK_CallHooks( WH_CALLWNDPROC
, HC_ACTION
, SameThread
, (LPARAM
)&CWP
);
328 ( PWINDOW_OBJECT Window
, HWND hWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*uResult
)
330 BOOL SameThread
= FALSE
;
332 if (Window
->ti
== ((PTHREADINFO
)PsGetCurrentThreadWin32Thread())->ThreadInfo
)
335 if ((!SameThread
&& (Window
->ti
->fsHooks
& HOOKID_TO_FLAG(WH_CALLWNDPROCRET
))) ||
336 (SameThread
&& ISITHOOKED(WH_CALLWNDPROCRET
)) )
341 CWPR
.wParam
= wParam
;
342 CWPR
.lParam
= lParam
;
343 CWPR
.lResult
= *uResult
;
344 co_HOOK_CallHooks( WH_CALLWNDPROCRET
, HC_ACTION
, SameThread
, (LPARAM
)&CWPR
);
350 IntDispatchMessage(PMSG pMsg
)
352 LARGE_INTEGER TickCount
;
355 PWINDOW_OBJECT Window
= NULL
;
359 Window
= UserGetWindowObject(pMsg
->hwnd
);
360 if (!Window
|| !Window
->Wnd
) return 0;
363 if (((pMsg
->message
== WM_SYSTIMER
) ||
364 (pMsg
->message
== WM_TIMER
)) &&
367 if (pMsg
->message
== WM_TIMER
)
369 if (ValidateTimerCallback(PsGetCurrentThreadWin32Thread(),Window
,pMsg
->wParam
,pMsg
->lParam
))
371 KeQueryTickCount(&TickCount
);
372 Time
= MsqCalculateMessageTime(&TickCount
);
373 return co_IntCallWindowProc((WNDPROC
)pMsg
->lParam
,
385 PTIMER pTimer
= FindSystemTimer(pMsg
);
386 if (pTimer
&& pTimer
->pfn
)
388 KeQueryTickCount(&TickCount
);
389 Time
= MsqCalculateMessageTime(&TickCount
);
390 pTimer
->pfn(pMsg
->hwnd
, WM_SYSTIMER
, (UINT
)pMsg
->wParam
, Time
);
396 if (!Window
) return 0;
398 retval
= co_IntPostOrSendMessage(pMsg
->hwnd
, pMsg
->message
, pMsg
->wParam
, pMsg
->lParam
);
400 if (pMsg
->message
== WM_PAINT
)
402 /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
403 HRGN hrgn
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
404 co_UserGetUpdateRgn( Window
, hrgn
, TRUE
);
405 GreDeleteObject( hrgn
);
417 BOOL BadChk
= FALSE
, Ret
= TRUE
;
419 DECLARE_RETURN(BOOL
);
421 DPRINT("Enter NtUserCallMsgFilter\n");
422 UserEnterExclusive();
427 ProbeForRead((PVOID
)lpmsg
,
434 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
443 if (BadChk
) RETURN( FALSE
);
445 if (!co_HOOK_CallHooks( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)&Msg
))
447 Ret
= co_HOOK_CallHooks( WH_MSGFILTER
, code
, 0, (LPARAM
)&Msg
);
452 ProbeForWrite((PVOID
)lpmsg
,
455 RtlCopyMemory((PVOID
)lpmsg
,
459 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
464 if (BadChk
) RETURN( FALSE
);
468 DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_
);
474 NtUserDispatchMessage(PMSG UnsafeMsgInfo
)
480 UserEnterExclusive();
483 ProbeForRead(UnsafeMsgInfo
, sizeof(MSG
), 1);
484 RtlCopyMemory(&SafeMsg
, UnsafeMsgInfo
, sizeof(MSG
));
486 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
488 SetLastNtError(_SEH2_GetExceptionCode());
493 if (!Hit
) Res
= IntDispatchMessage(&SafeMsg
);
501 NtUserTranslateMessage(LPMSG lpMsg
,
506 DECLARE_RETURN(BOOL
);
508 DPRINT("Enter NtUserTranslateMessage\n");
509 UserEnterExclusive();
511 Status
= MmCopyFromCaller(&SafeMsg
, lpMsg
, sizeof(MSG
));
512 if(!NT_SUCCESS(Status
))
514 SetLastNtError(Status
);
518 RETURN( IntTranslateKbdMessage(&SafeMsg
, dwhkl
));
521 DPRINT("Leave NtUserTranslateMessage: ret=%i\n",_ret_
);
528 co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
)
530 if(!Msg
->hwnd
|| ThreadQueue
->CaptureWindow
)
539 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
544 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
551 case WM_LBUTTONDBLCLK
:
552 case WM_MBUTTONDBLCLK
:
553 case WM_RBUTTONDBLCLK
:
554 case WM_XBUTTONDBLCLK
:
557 PSYSTEM_CURSORINFO CurInfo
;
559 if(!IntGetWindowStationObject(InputWindowStation
))
563 CurInfo
= IntGetSysCursorInfo(InputWindowStation
);
564 wParam
= (WPARAM
)(CurInfo
->ButtonsDown
);
565 ObDereferenceObject(InputWindowStation
);
567 co_IntSendMessage(Msg
->hwnd
, WM_MOUSEMOVE
, wParam
, Msg
->lParam
);
568 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
571 case WM_NCLBUTTONDOWN
:
572 case WM_NCMBUTTONDOWN
:
573 case WM_NCRBUTTONDOWN
:
574 case WM_NCXBUTTONDOWN
:
575 case WM_NCLBUTTONDBLCLK
:
576 case WM_NCMBUTTONDBLCLK
:
577 case WM_NCRBUTTONDBLCLK
:
578 case WM_NCXBUTTONDBLCLK
:
580 co_IntSendMessage(Msg
->hwnd
, WM_NCMOUSEMOVE
, (WPARAM
)Msg
->wParam
, Msg
->lParam
);
581 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
588 co_IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, PWINDOW_OBJECT MsgWindow
,
592 PWINDOW_OBJECT Parent
;
594 ASSERT_REFS_CO(MsgWindow
);
596 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
598 /* eat the message, search again! */
602 Parent
= IntGetParent(MsgWindow
);//fixme: deref retval?
604 /* If no parent window, pass MsgWindows HWND as wParam. Fixes bug #3111 */
605 Result
= co_IntSendMessage(MsgWindow
->hSelf
,
607 (WPARAM
) (Parent
? Parent
->hSelf
: MsgWindow
->hSelf
),
608 (LPARAM
)MAKELONG(*HitTest
, Msg
->message
)
613 case MA_NOACTIVATEANDEAT
:
617 case MA_ACTIVATEANDEAT
:
618 co_IntMouseActivateWindow(MsgWindow
);
622 co_IntMouseActivateWindow(MsgWindow
);
630 co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, USHORT
*HitTest
, BOOL Remove
)
632 PWINDOW_OBJECT Window
;
633 USER_REFERENCE_ENTRY Ref
, DesktopRef
;
635 if(!(Window
= UserGetWindowObject(Msg
->hwnd
)))
637 /* let's just eat the message?! */
641 UserRefObjectCo(Window
, &Ref
);
643 if(ThreadQueue
== Window
->MessageQueue
&&
644 ThreadQueue
->CaptureWindow
!= Window
->hSelf
)
646 /* only send WM_NCHITTEST messages if we're not capturing the window! */
647 *HitTest
= co_IntSendMessage(Window
->hSelf
, WM_NCHITTEST
, 0,
648 MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
));
650 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
652 PWINDOW_OBJECT DesktopWindow
;
653 HWND hDesktop
= IntGetDesktopWindow();
655 if((DesktopWindow
= UserGetWindowObject(hDesktop
)))
659 UserRefObjectCo(DesktopWindow
, &DesktopRef
);
661 co_WinPosWindowFromPoint(DesktopWindow
, Window
->MessageQueue
, &Msg
->pt
, &Wnd
);
666 /* post the message to the other window */
667 Msg
->hwnd
= Wnd
->hSelf
;
668 if(!(Wnd
->Status
& WINDOWSTATUS_DESTROYING
))
670 MsqPostMessage(Wnd
->MessageQueue
, Msg
, FALSE
,
671 Msg
->message
== WM_MOUSEMOVE
? QS_MOUSEMOVE
:
675 /* eat the message */
676 UserDereferenceObject(Wnd
);
677 UserDerefObjectCo(DesktopWindow
);
678 UserDerefObjectCo(Window
);
681 UserDereferenceObject(Wnd
);
684 UserDerefObjectCo(DesktopWindow
);
693 if(IS_BTN_MESSAGE(Msg
->message
, DOWN
))
695 /* generate double click messages, if necessary */
696 if ((((*HitTest
) != HTCLIENT
) ||
697 (Window
->Wnd
->pcls
->Style
& CS_DBLCLKS
)) &&
698 MsqIsDblClk(Msg
, Remove
))
700 Msg
->message
+= WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
;
704 if(Msg
->message
!= WM_MOUSEWHEEL
)
707 if ((*HitTest
) != HTCLIENT
)
709 Msg
->message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
710 if((Msg
->message
== WM_NCRBUTTONUP
) &&
711 (((*HitTest
) == HTCAPTION
) || ((*HitTest
) == HTSYSMENU
)))
713 Msg
->message
= WM_CONTEXTMENU
;
714 Msg
->wParam
= (WPARAM
)Window
->hSelf
;
718 Msg
->wParam
= *HitTest
;
720 Msg
->lParam
= MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
);
722 else if(ThreadQueue
->MoveSize
== NULL
&&
723 ThreadQueue
->MenuOwner
== NULL
)
725 /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
726 Msg
->lParam
= MAKELONG(
727 Msg
->pt
.x
- (WORD
)Window
->Wnd
->rcClient
.left
,
728 Msg
->pt
.y
- (WORD
)Window
->Wnd
->rcClient
.top
);
732 UserDerefObjectCo(Window
);
738 * Internal version of PeekMessage() doing all the work
741 co_IntPeekMessage(PUSER_MESSAGE Msg
,
742 PWINDOW_OBJECT Window
,
748 LARGE_INTEGER LargeTickCount
;
749 PUSER_MESSAGE_QUEUE ThreadQueue
;
750 PUSER_MESSAGE Message
;
751 BOOL Present
, RemoveMessages
;
752 USER_REFERENCE_ENTRY Ref
;
754 MOUSEHOOKSTRUCT MHook
;
756 /* The queues and order in which they are checked are documented in the MSDN
757 article on GetMessage() */
759 pti
= PsGetCurrentThreadWin32Thread();
760 ThreadQueue
= pti
->MessageQueue
;
762 /* Inspect RemoveMsg flags */
763 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
764 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
770 KeQueryTickCount(&LargeTickCount
);
771 ThreadQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
773 /* Dispatch sent messages here. */
774 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
777 /* Now look for a quit message. */
779 if (ThreadQueue
->QuitPosted
)
781 /* According to the PSDK, WM_QUIT messages are always returned, regardless
782 of the filter specified */
783 Msg
->Msg
.hwnd
= NULL
;
784 Msg
->Msg
.message
= WM_QUIT
;
785 Msg
->Msg
.wParam
= ThreadQueue
->QuitExitCode
;
787 Msg
->FreeLParam
= FALSE
;
790 ThreadQueue
->QuitPosted
= FALSE
;
795 /* Now check for normal messages. */
796 Present
= co_MsqFindMessage(ThreadQueue
,
805 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
808 MsqDestroyMessage(Message
);
813 /* Check for hardware events. */
814 Present
= co_MsqFindMessage(ThreadQueue
,
823 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
826 MsqDestroyMessage(Message
);
831 /* Check for sent messages again. */
832 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
835 /* Check for paint messages. */
836 if (IntGetPaintMessage(Window
, MsgFilterMin
, MsgFilterMax
, pti
, &Msg
->Msg
, RemoveMessages
))
838 Msg
->FreeLParam
= FALSE
;
842 if (ThreadQueue
->WakeMask
& QS_TIMER
)
843 if (PostTimerMessages(Window
)) // If there are timers ready,
844 goto CheckMessages
; // go back and process them.
846 // LOL! Polling Timer Queue? How much time is spent doing this?
847 /* Check for WM_(SYS)TIMER messages */
848 Present
= MsqGetTimerMessage(ThreadQueue
, Window
, MsgFilterMin
, MsgFilterMax
,
849 &Msg
->Msg
, RemoveMessages
);
852 Msg
->FreeLParam
= FALSE
;
862 PWINDOW_OBJECT MsgWindow
= NULL
;
864 if(Msg
->Msg
.hwnd
&& (MsgWindow
= UserGetWindowObject(Msg
->Msg
.hwnd
)) &&
865 Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
)
869 UserRefObjectCo(MsgWindow
, &Ref
);
871 if(co_IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, TRUE
))
872 /* FIXME - check message filter again, if the message doesn't match anymore,
875 UserDerefObjectCo(MsgWindow
);
876 /* eat the message, search again */
880 if(ThreadQueue
->CaptureWindow
== NULL
)
882 co_IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
883 if((Msg
->Msg
.message
!= WM_MOUSEMOVE
&& Msg
->Msg
.message
!= WM_NCMOUSEMOVE
) &&
884 IS_BTN_MESSAGE(Msg
->Msg
.message
, DOWN
) &&
885 co_IntActivateWindowMouse(ThreadQueue
, &Msg
->Msg
, MsgWindow
, &HitTest
))
887 UserDerefObjectCo(MsgWindow
);
888 /* eat the message, search again */
893 UserDerefObjectCo(MsgWindow
);
897 co_IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
902 // UserDereferenceObject(MsgWindow);
908 if((Msg
->Msg
.hwnd
&& Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
) &&
909 co_IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, FALSE
))
910 /* FIXME - check message filter again, if the message doesn't match anymore,
913 /* eat the message, search again */
917 if ( ISITHOOKED(WH_MOUSE
) &&
918 Msg
->Msg
.message
>= WM_MOUSEFIRST
&&
919 Msg
->Msg
.message
<= WM_MOUSELAST
)
921 MHook
.pt
= Msg
->Msg
.pt
;
922 MHook
.hwnd
= Msg
->Msg
.hwnd
;
923 MHook
.wHitTestCode
= HitTest
;
924 MHook
.dwExtraInfo
= 0;
925 if (co_HOOK_CallHooks( WH_MOUSE
,
926 RemoveMsg
? HC_ACTION
: HC_NOREMOVE
,
930 if (ISITHOOKED(WH_CBT
))
932 MHook
.pt
= Msg
->Msg
.pt
;
933 MHook
.hwnd
= Msg
->Msg
.hwnd
;
934 MHook
.wHitTestCode
= HitTest
;
935 MHook
.dwExtraInfo
= 0;
936 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
,
937 Msg
->Msg
.message
, (LPARAM
)&MHook
);
942 if ( ISITHOOKED(WH_KEYBOARD
) &&
943 (Msg
->Msg
.message
== WM_KEYDOWN
|| Msg
->Msg
.message
== WM_KEYUP
) )
945 if (co_HOOK_CallHooks( WH_KEYBOARD
,
946 RemoveMsg
? HC_ACTION
: HC_NOREMOVE
,
947 LOWORD(Msg
->Msg
.wParam
),
950 if (ISITHOOKED(WH_CBT
))
952 /* skip this message */
953 co_HOOK_CallHooks( WH_CBT
, HCBT_KEYSKIPPED
,
954 LOWORD(Msg
->Msg
.wParam
), Msg
->Msg
.lParam
);
959 // The WH_GETMESSAGE hook enables an application to monitor messages about to
960 // be returned by the GetMessage or PeekMessage function.
961 if (ISITHOOKED(WH_GETMESSAGE
))
963 //DPRINT1("Peek WH_GETMESSAGE -> %x\n",&Msg);
964 co_HOOK_CallHooks( WH_GETMESSAGE
, HC_ACTION
, RemoveMsg
& PM_REMOVE
, (LPARAM
)&Msg
->Msg
);
973 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
981 NTUSERGETMESSAGEINFO Info
;
982 PWINDOW_OBJECT Window
;
983 PMSGMEMORY MsgMemoryEntry
;
987 DECLARE_RETURN(BOOL
);
989 DPRINT("Enter NtUserPeekMessage\n");
990 UserEnterExclusive();
992 if (hWnd
== (HWND
)-1 || hWnd
== (HWND
)0x0000FFFF || hWnd
== (HWND
)0xFFFFFFFF)
996 if (hWnd
&& hWnd
!= (HWND
)1)
998 if (!(Window
= UserGetWindowObject(hWnd
)))
1005 Window
= (PWINDOW_OBJECT
)hWnd
;
1008 if (MsgFilterMax
< MsgFilterMin
)
1014 Present
= co_IntPeekMessage(&Msg
, Window
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
);
1019 /* See if this message type is present in the table */
1020 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
1021 if (NULL
== MsgMemoryEntry
)
1023 /* Not present, no copying needed */
1024 Info
.LParamSize
= 0;
1028 /* Determine required size */
1029 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
1031 /* Allocate required amount of user-mode memory */
1032 Info
.LParamSize
= Size
;
1034 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
1035 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
1036 if (! NT_SUCCESS(Status
))
1038 SetLastNtError(Status
);
1041 /* Transfer lParam data to user-mode mem */
1042 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
1043 if (! NT_SUCCESS(Status
))
1045 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
1046 &Info
.LParamSize
, MEM_RELEASE
);
1047 SetLastNtError(Status
);
1050 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
1052 if (RemoveMsg
&& Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
1054 ExFreePool((void *) Msg
.Msg
.lParam
);
1056 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
1057 if (! NT_SUCCESS(Status
))
1059 SetLastNtError(Status
);
1067 DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_
);
1072 static BOOL FASTCALL
1073 co_IntWaitMessage(PWINDOW_OBJECT Window
,
1078 PUSER_MESSAGE_QUEUE ThreadQueue
;
1082 pti
= PsGetCurrentThreadWin32Thread();
1083 ThreadQueue
= pti
->MessageQueue
;
1087 if (co_IntPeekMessage(&Msg
, Window
, MsgFilterMin
, MsgFilterMax
, PM_NOREMOVE
))
1092 /* Nothing found. Wait for new messages. */
1093 Status
= co_MsqWaitForNewMessages(ThreadQueue
, Window
, MsgFilterMin
, MsgFilterMax
);
1095 while ((STATUS_WAIT_0
<= Status
&& Status
<= STATUS_WAIT_63
) || STATUS_TIMEOUT
== Status
);
1097 SetLastNtError(Status
);
1103 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
1108 * FUNCTION: Get a message from the calling thread's message queue.
1110 * UnsafeMsg - Pointer to the structure which receives the returned message.
1111 * Wnd - Window whose messages are to be retrieved.
1112 * MsgFilterMin - Integer value of the lowest message value to be
1114 * MsgFilterMax - Integer value of the highest message value to be
1119 NTUSERGETMESSAGEINFO Info
;
1121 /* FIXME: if initialization is removed, gcc complains that this may be used before initialization. Please review */
1122 PWINDOW_OBJECT Window
= NULL
;
1123 PMSGMEMORY MsgMemoryEntry
;
1127 DECLARE_RETURN(BOOL
);
1128 // USER_REFERENCE_ENTRY Ref;
1130 DPRINT("Enter NtUserGetMessage\n");
1131 UserEnterExclusive();
1133 /* Validate input */
1134 if (hWnd
&& !(Window
= UserGetWindowObject(hWnd
)))
1139 // if (Window) UserRefObjectCo(Window, &Ref);
1141 if (MsgFilterMax
< MsgFilterMin
)
1149 GotMessage
= co_IntPeekMessage(&Msg
, Window
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
);
1153 /* See if this message type is present in the table */
1154 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
1155 if (NULL
== MsgMemoryEntry
)
1157 /* Not present, no copying needed */
1158 Info
.LParamSize
= 0;
1162 /* Determine required size */
1163 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
1165 /* Allocate required amount of user-mode memory */
1166 Info
.LParamSize
= Size
;
1168 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
1169 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
1171 if (! NT_SUCCESS(Status
))
1173 SetLastNtError(Status
);
1176 /* Transfer lParam data to user-mode mem */
1177 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
1178 if (! NT_SUCCESS(Status
))
1180 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
1181 &Info
.LParamSize
, MEM_DECOMMIT
);
1182 SetLastNtError(Status
);
1185 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
1187 if (Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
1189 ExFreePool((void *) Msg
.Msg
.lParam
);
1191 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
1192 if (! NT_SUCCESS(Status
))
1194 SetLastNtError(Status
);
1198 else if (! co_IntWaitMessage(Window
, MsgFilterMin
, MsgFilterMax
))
1203 while (! GotMessage
);
1205 RETURN( WM_QUIT
!= Info
.Msg
.message
);
1208 // if (Window) UserDerefObjectCo(Window);
1210 DPRINT("Leave NtUserGetMessage\n");
1216 static NTSTATUS FASTCALL
1217 CopyMsgToKernelMem(MSG
*KernelModeMsg
, MSG
*UserModeMsg
, PMSGMEMORY MsgMemoryEntry
)
1224 *KernelModeMsg
= *UserModeMsg
;
1226 /* See if this message type is present in the table */
1227 if (NULL
== MsgMemoryEntry
)
1229 /* Not present, no copying needed */
1230 return STATUS_SUCCESS
;
1233 /* Determine required size */
1234 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1238 /* Allocate kernel mem */
1239 KernelMem
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
1240 if (NULL
== KernelMem
)
1242 DPRINT1("Not enough memory to copy message to kernel mem\n");
1243 return STATUS_NO_MEMORY
;
1245 KernelModeMsg
->lParam
= (LPARAM
) KernelMem
;
1247 /* Copy data if required */
1248 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_READ
))
1250 Status
= MmCopyFromCaller(KernelMem
, (PVOID
) UserModeMsg
->lParam
, Size
);
1251 if (! NT_SUCCESS(Status
))
1253 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
1254 ExFreePoolWithTag(KernelMem
, TAG_MSG
);
1260 /* Make sure we don't pass any secrets to usermode */
1261 RtlZeroMemory(KernelMem
, Size
);
1266 KernelModeMsg
->lParam
= 0;
1269 return STATUS_SUCCESS
;
1272 static NTSTATUS FASTCALL
1273 CopyMsgToUserMem(MSG
*UserModeMsg
, MSG
*KernelModeMsg
)
1276 PMSGMEMORY MsgMemoryEntry
;
1279 /* See if this message type is present in the table */
1280 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
1281 if (NULL
== MsgMemoryEntry
)
1283 /* Not present, no copying needed */
1284 return STATUS_SUCCESS
;
1287 /* Determine required size */
1288 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1292 /* Copy data if required */
1293 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_WRITE
))
1295 Status
= MmCopyToCaller((PVOID
) UserModeMsg
->lParam
, (PVOID
) KernelModeMsg
->lParam
, Size
);
1296 if (! NT_SUCCESS(Status
))
1298 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1299 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1304 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1307 return STATUS_SUCCESS
;
1311 UserPostThreadMessage( DWORD idThread
,
1318 PTHREADINFO pThread
;
1319 LARGE_INTEGER LargeTickCount
;
1322 DPRINT1("UserPostThreadMessage wParam 0x%x lParam 0x%x\n", wParam
,lParam
);
1324 if (FindMsgMemory(Msg
) != 0)
1326 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY
);
1330 Status
= PsLookupThreadByThreadId((HANDLE
)idThread
,&peThread
);
1332 if( Status
== STATUS_SUCCESS
)
1334 pThread
= (PTHREADINFO
)peThread
->Tcb
.Win32Thread
;
1335 if( !pThread
|| !pThread
->MessageQueue
)
1337 ObDereferenceObject( peThread
);
1341 Message
.hwnd
= NULL
;
1342 Message
.message
= Msg
;
1343 Message
.wParam
= wParam
;
1344 Message
.lParam
= lParam
;
1345 IntGetCursorLocation(pThread
->Desktop
->WindowStation
, &Message
.pt
);
1346 KeQueryTickCount(&LargeTickCount
);
1347 pThread
->timeLast
= Message
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1348 MsqPostMessage(pThread
->MessageQueue
, &Message
, FALSE
, QS_POSTMESSAGE
);
1349 ObDereferenceObject( peThread
);
1354 SetLastNtError( Status
);
1360 UserPostMessage(HWND Wnd
,
1367 LARGE_INTEGER LargeTickCount
;
1369 if (FindMsgMemory(Msg
) != 0)
1371 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY
);
1376 return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
1381 pti
= PsGetCurrentThreadWin32Thread();
1382 if (Wnd
== HWND_BROADCAST
)
1385 PWINDOW_OBJECT DesktopWindow
;
1388 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1389 List
= IntWinListChildren(DesktopWindow
);
1393 for (i
= 0; List
[i
]; i
++)
1394 UserPostMessage(List
[i
], Msg
, wParam
, lParam
);
1400 PWINDOW_OBJECT Window
;
1402 Window
= UserGetWindowObject(Wnd
);
1407 if(Window
->Status
& WINDOWSTATUS_DESTROYING
)
1409 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd
);
1410 /* FIXME - last error code? */
1416 MsqPostQuitMessage(Window
->MessageQueue
, wParam
);
1421 Message
.message
= Msg
;
1422 Message
.wParam
= wParam
;
1423 Message
.lParam
= lParam
;
1424 IntGetCursorLocation(pti
->Desktop
->WindowStation
, &Message
.pt
);
1425 KeQueryTickCount(&LargeTickCount
);
1426 pti
->timeLast
= Message
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1427 MsqPostMessage(Window
->MessageQueue
, &Message
, FALSE
, QS_POSTMESSAGE
);
1435 NtUserPostMessage(HWND hWnd
,
1440 DECLARE_RETURN(BOOL
);
1442 DPRINT("Enter NtUserPostMessage\n");
1443 UserEnterExclusive();
1445 RETURN( UserPostMessage(hWnd
, Msg
, wParam
, lParam
));
1448 DPRINT("Leave NtUserPostMessage, ret=%i\n",_ret_
);
1456 NtUserPostThreadMessage(DWORD idThread
,
1461 DECLARE_RETURN(BOOL
);
1463 DPRINT("Enter NtUserPostThreadMessage\n");
1464 UserEnterExclusive();
1466 RETURN( UserPostThreadMessage( idThread
,
1472 DPRINT("Leave NtUserPostThreadMessage, ret=%i\n",_ret_
);
1478 NtUserQuerySendMessage(DWORD Unknown0
)
1486 co_IntSendMessage(HWND hWnd
,
1491 ULONG_PTR Result
= 0;
1492 if(co_IntSendMessageTimeout(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1494 return (LRESULT
)Result
;
1501 co_IntSendMessageTimeoutSingle(HWND hWnd
,
1511 PWINDOW_OBJECT Window
= NULL
;
1512 PMSGMEMORY MsgMemoryEntry
;
1513 INT lParamBufferSize
;
1514 LPARAM lParamPacked
;
1515 PTHREADINFO Win32Thread
;
1516 DECLARE_RETURN(LRESULT
);
1517 USER_REFERENCE_ENTRY Ref
;
1519 if (!(Window
= UserGetWindowObject(hWnd
)))
1524 UserRefObjectCo(Window
, &Ref
);
1526 Win32Thread
= PsGetCurrentThreadWin32Thread();
1528 IntCallWndProc( Window
, hWnd
, Msg
, wParam
, lParam
);
1530 if (NULL
!= Win32Thread
&&
1531 Window
->MessageQueue
== Win32Thread
->MessageQueue
)
1533 if (Win32Thread
->IsExiting
)
1535 /* Never send messages to exiting threads */
1539 /* See if this message type is present in the table */
1540 MsgMemoryEntry
= FindMsgMemory(Msg
);
1541 if (NULL
== MsgMemoryEntry
)
1543 lParamBufferSize
= -1;
1547 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
1550 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
)))
1552 DPRINT1("Failed to pack message parameters\n");
1556 Result
= (ULONG_PTR
)co_IntCallWindowProc(Window
->Wnd
->lpfnWndProc
, !Window
->Wnd
->Unicode
, hWnd
, Msg
, wParam
,
1557 lParamPacked
,lParamBufferSize
);
1564 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, (LRESULT
*)uResult
);
1566 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
)))
1568 DPRINT1("Failed to unpack message parameters\n");
1575 if (uFlags
& SMTO_ABORTIFHUNG
&& MsqIsHung(Window
->MessageQueue
))
1577 /* FIXME - Set a LastError? */
1581 if (Window
->Status
& WINDOWSTATUS_DESTROYING
)
1583 /* FIXME - last error? */
1584 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd
);
1590 Status
= co_MsqSendMessage( Window
->MessageQueue
,
1596 (uFlags
& SMTO_BLOCK
),
1600 while ((STATUS_TIMEOUT
== Status
) &&
1601 (uFlags
& SMTO_NOTIMEOUTIFNOTHUNG
) &&
1602 !MsqIsHung(Window
->MessageQueue
));
1604 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, (LRESULT
*)uResult
);
1606 if (STATUS_TIMEOUT
== Status
)
1610 Microsoft Windows 2000: If GetLastError returns zero, then the function
1612 XP+ : If the function fails or times out, the return value is zero.
1613 To get extended error information, call GetLastError. If GetLastError
1614 returns ERROR_TIMEOUT, then the function timed out.
1616 SetLastWin32Error(ERROR_TIMEOUT
);
1619 else if (! NT_SUCCESS(Status
))
1621 SetLastNtError(Status
);
1628 if (Window
) UserDerefObjectCo(Window
);
1633 co_IntSendMessageTimeout(HWND hWnd
,
1641 PWINDOW_OBJECT DesktopWindow
;
1645 if (HWND_BROADCAST
!= hWnd
)
1647 return co_IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1650 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1651 if (NULL
== DesktopWindow
)
1653 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1657 Children
= IntWinListChildren(DesktopWindow
);
1658 if (NULL
== Children
)
1663 for (Child
= Children
; NULL
!= *Child
; Child
++)
1665 co_IntSendMessageTimeoutSingle(*Child
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1668 ExFreePool(Children
);
1670 return (LRESULT
) TRUE
;
1674 /* This function posts a message if the destination's message queue belongs to
1675 another thread, otherwise it sends the message. It does not support broadcast
1678 co_IntPostOrSendMessage(HWND hWnd
,
1685 PWINDOW_OBJECT Window
;
1687 if(hWnd
== HWND_BROADCAST
)
1692 if(!(Window
= UserGetWindowObject(hWnd
)))
1697 pti
= PsGetCurrentThreadWin32Thread();
1698 if(Window
->MessageQueue
!= pti
->MessageQueue
&& FindMsgMemory(Msg
) ==0)
1700 Result
= UserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1704 if(!co_IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
)) {
1709 return (LRESULT
)Result
;
1713 co_IntDoSendMessage(HWND hWnd
,
1718 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1721 LRESULT Result
= TRUE
;
1723 PWINDOW_OBJECT Window
= NULL
;
1724 NTUSERSENDMESSAGEINFO Info
;
1727 PMSGMEMORY MsgMemoryEntry
;
1729 RtlZeroMemory(&Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1731 /* FIXME: Call hooks. */
1732 if (HWND_BROADCAST
!= hWnd
)
1734 Window
= UserGetWindowObject(hWnd
);
1737 /* Tell usermode to not touch this one */
1738 Info
.HandledByKernel
= TRUE
;
1739 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1746 /* FIXME: Check for an exiting window. */
1748 /* See if the current thread can handle the message */
1749 pti
= PsGetCurrentThreadWin32Thread();
1750 if (HWND_BROADCAST
!= hWnd
&& NULL
!= pti
&&
1751 Window
->MessageQueue
== pti
->MessageQueue
)
1753 /* Gather the information usermode needs to call the window proc directly */
1754 Info
.HandledByKernel
= FALSE
;
1756 Status
= MmCopyFromCaller(&(Info
.Ansi
), &(UnsafeInfo
->Ansi
),
1758 if (! NT_SUCCESS(Status
))
1760 Info
.Ansi
= ! Window
->Wnd
->Unicode
;
1763 IntCallWndProc( Window
, hWnd
, Msg
, wParam
, lParam
);
1765 if (Window
->Wnd
->IsSystem
)
1767 Info
.Proc
= (!Info
.Ansi
? Window
->Wnd
->lpfnWndProc
: Window
->Wnd
->WndProcExtra
);
1771 Info
.Ansi
= !Window
->Wnd
->Unicode
;
1772 Info
.Proc
= Window
->Wnd
->lpfnWndProc
;
1775 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, &Result
);
1780 /* Must be handled by other thread */
1781 // if (HWND_BROADCAST != hWnd)
1783 // UserDereferenceObject(Window);
1785 Info
.HandledByKernel
= TRUE
;
1786 UserModeMsg
.hwnd
= hWnd
;
1787 UserModeMsg
.message
= Msg
;
1788 UserModeMsg
.wParam
= wParam
;
1789 UserModeMsg
.lParam
= lParam
;
1790 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1791 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1792 if (! NT_SUCCESS(Status
))
1794 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1795 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1796 return (dsm
? 0 : -1);
1800 Result
= co_IntSendMessage(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1801 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
);
1805 Result
= co_IntSendMessageTimeout(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1806 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
,
1807 dsm
->uFlags
, dsm
->uTimeout
, &dsm
->Result
);
1809 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
1810 if (! NT_SUCCESS(Status
))
1812 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1813 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1814 return(dsm
? 0 : -1);
1818 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1819 if (! NT_SUCCESS(Status
))
1821 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1824 return (LRESULT
)Result
;
1828 NtUserSendMessageTimeout(HWND hWnd
,
1835 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1839 DECLARE_RETURN(BOOL
);
1841 DPRINT("Enter NtUserSendMessageTimeout\n");
1842 UserEnterExclusive();
1844 dsm
.uFlags
= uFlags
;
1845 dsm
.uTimeout
= uTimeout
;
1846 Result
= co_IntDoSendMessage(hWnd
, Msg
, wParam
, lParam
, &dsm
, UnsafeInfo
);
1847 if(uResult
!= NULL
&& Result
!= 0)
1851 Status
= MmCopyToCaller(uResult
, &dsm
.Result
, sizeof(ULONG_PTR
));
1852 if(!NT_SUCCESS(Status
))
1854 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1861 DPRINT("Leave NtUserSendMessageTimeout, ret=%i\n",_ret_
);
1867 NtUserSendMessage(HWND Wnd
,
1871 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1873 DECLARE_RETURN(BOOL
);
1875 DPRINT("Enter NtUserSendMessage\n");
1876 UserEnterExclusive();
1878 RETURN(co_IntDoSendMessage(Wnd
, Msg
, wParam
, lParam
, NULL
, UnsafeInfo
));
1881 DPRINT("Leave NtUserSendMessage, ret=%i\n",_ret_
);
1888 UserSendNotifyMessage(HWND hWnd
,
1895 if (FindMsgMemory(Msg
) != 0)
1897 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY
);
1901 // Basicly the same as IntPostOrSendMessage
1902 if (hWnd
== HWND_BROADCAST
) //Handle Broadcast
1905 PWINDOW_OBJECT DesktopWindow
;
1908 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1909 List
= IntWinListChildren(DesktopWindow
);
1913 for (i
= 0; List
[i
]; i
++)
1915 UserSendNotifyMessage(List
[i
], Msg
, wParam
, lParam
);
1924 PWINDOW_OBJECT Window
;
1927 if(!(Window
= UserGetWindowObject(hWnd
))) return FALSE
;
1929 pti
= PsGetCurrentThreadWin32Thread();
1930 if(Window
->MessageQueue
!= pti
->MessageQueue
)
1931 { // Send message w/o waiting for it.
1932 Result
= UserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1935 { // Handle message and callback.
1936 Message
.hwnd
= hWnd
;
1937 Message
.message
= Msg
;
1938 Message
.wParam
= wParam
;
1939 Message
.lParam
= lParam
;
1941 Result
= co_IntSendMessageTimeoutSingle( hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &PResult
);
1949 NtUserWaitMessage(VOID
)
1951 DECLARE_RETURN(BOOL
);
1953 DPRINT("EnterNtUserWaitMessage\n");
1954 UserEnterExclusive();
1956 RETURN(co_IntWaitMessage(NULL
, 0, 0));
1959 DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_
);
1965 IntGetQueueStatus(BOOL ClearChanges
)
1968 PUSER_MESSAGE_QUEUE Queue
;
1970 DECLARE_RETURN(DWORD
);
1972 DPRINT("Enter IntGetQueueStatus\n");
1974 pti
= PsGetCurrentThreadWin32Thread();
1975 Queue
= pti
->MessageQueue
;
1977 Result
= MAKELONG(Queue
->QueueBits
, Queue
->ChangedBits
);
1980 Queue
->ChangedBits
= 0;
1986 DPRINT("Leave IntGetQueueStatus, ret=%i\n",_ret_
);
1991 IntInitMessagePumpHook()
1993 if (((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->pcti
)
1995 ((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->pcti
->dwcPumpHook
++;
2002 IntUninitMessagePumpHook()
2004 if (((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->pcti
)
2006 if (((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->pcti
->dwcPumpHook
<= 0)
2010 ((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->pcti
->dwcPumpHook
--;
2023 ULONG_PTR ResultInfo
,
2024 DWORD dwType
, // fnID?
2027 LRESULT lResult
= 0;
2029 BOOL BadChk
= FALSE
;
2030 PWINDOW_OBJECT Window
= NULL
;
2031 USER_REFERENCE_ENTRY Ref
;
2033 UserEnterExclusive();
2035 /* Validate input */
2036 if (hWnd
&& (hWnd
!= INVALID_HANDLE_VALUE
) && !(Window
= UserGetWindowObject(hWnd
)))
2043 case FNID_DEFWINDOWPROC
:
2044 UserRefObjectCo(Window
, &Ref
);
2045 lResult
= IntDefWindowProc(Window
, Msg
, wParam
, lParam
, Ansi
);
2047 UserDerefObjectCo(Window
);
2049 case FNID_SENDNOTIFYMESSAGE
:
2050 Ret
= UserSendNotifyMessage(hWnd
, Msg
, wParam
, lParam
);
2052 case FNID_BROADCASTSYSTEMMESSAGE
:
2055 DWORD_PTR RetVal
= 0;
2061 ProbeForWrite((PVOID
)ResultInfo
,
2062 sizeof(BROADCASTPARM
),
2064 RtlCopyMemory(&parm
, (PVOID
)ResultInfo
, sizeof(BROADCASTPARM
));
2066 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2076 if ( parm
.recipients
& BSM_ALLDESKTOPS
||
2077 parm
.recipients
== BSM_ALLCOMPONENTS
)
2080 else if (parm
.recipients
& BSM_APPLICATIONS
)
2082 if (parm
.flags
& BSF_QUERY
)
2084 if (parm
.flags
& BSF_FORCEIFHUNG
|| parm
.flags
& BSF_NOHANG
)
2086 co_IntSendMessageTimeout( HWND_BROADCAST
,
2094 else if (parm
.flags
& BSF_NOTIMEOUTIFNOTHUNG
)
2096 co_IntSendMessageTimeout( HWND_BROADCAST
,
2100 SMTO_NOTIMEOUTIFNOTHUNG
,
2106 co_IntSendMessageTimeout( HWND_BROADCAST
,
2115 else if (parm
.flags
& BSF_POSTMESSAGE
)
2117 Ret
= UserPostMessage(HWND_BROADCAST
, Msg
, wParam
, lParam
);
2119 else if ( parm
.flags
& BSF_SENDNOTIFYMESSAGE
)
2121 Ret
= UserSendNotifyMessage(HWND_BROADCAST
, Msg
, wParam
, lParam
);
2126 case FNID_SENDMESSAGECALLBACK
:
2128 // CallNextHook bypass.
2129 case FNID_CALLWNDPROC
:
2130 case FNID_CALLWNDPROCRET
:
2132 PCLIENTINFO ClientInfo
= GetWin32ClientInfo();
2133 PHOOK NextObj
, Hook
= ClientInfo
->phkCurrent
;
2135 if (!ClientInfo
|| !Hook
) break;
2137 UserReferenceObject(Hook
);
2139 if (Hook
->Thread
&& (Hook
->Thread
!= PsGetCurrentThread()))
2141 UserDereferenceObject(Hook
);
2145 NextObj
= IntGetNextHook(Hook
);
2146 ClientInfo
->phkCurrent
= NextObj
;
2148 if ( Hook
->HookId
== WH_CALLWNDPROC
)
2153 CWP
.wParam
= wParam
;
2154 CWP
.lParam
= lParam
;
2155 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook
, NextObj
);
2157 lResult
= co_IntCallHookProc( Hook
->HookId
,
2159 ((ClientInfo
->CI_flags
& CI_CURTHPRHOOK
) ? 1 : 0),
2170 CWPR
.wParam
= wParam
;
2171 CWPR
.lParam
= lParam
;
2172 CWPR
.lResult
= ClientInfo
->dwHookData
;
2174 lResult
= co_IntCallHookProc( Hook
->HookId
,
2176 ((ClientInfo
->CI_flags
& CI_CURTHPRHOOK
) ? 1 : 0),
2182 UserDereferenceObject(Hook
);
2183 lResult
= (LRESULT
) NextObj
;
2190 case FNID_DEFWINDOWPROC
:
2191 case FNID_CALLWNDPROC
:
2192 case FNID_CALLWNDPROCRET
:
2197 ProbeForWrite((PVOID
)ResultInfo
, sizeof(LRESULT
), 1);
2198 RtlCopyMemory((PVOID
)ResultInfo
, &lResult
, sizeof(LRESULT
));
2200 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2213 return BadChk
? FALSE
: Ret
;
2216 #define INFINITE 0xFFFFFFFF
2217 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2221 NtUserWaitForInputIdle(
2223 IN DWORD dwMilliseconds
,
2227 PW32PROCESS W32Process
;
2230 LARGE_INTEGER Timeout
;
2231 ULONGLONG StartTime
, Run
, Elapsed
= 0;
2233 UserEnterExclusive();
2235 Status
= ObReferenceObjectByHandle(hProcess
,
2236 PROCESS_QUERY_INFORMATION
,
2242 if (!NT_SUCCESS(Status
))
2245 SetLastNtError(Status
);
2249 W32Process
= (PW32PROCESS
)Process
->Win32Process
;
2252 ObDereferenceObject(Process
);
2254 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2258 EngCreateEvent((PEVENT
*)&W32Process
->InputIdleEvent
);
2260 Handles
[0] = Process
;
2261 Handles
[1] = W32Process
->InputIdleEvent
;
2265 ObDereferenceObject(Process
);
2267 return STATUS_SUCCESS
; /* no event to wait on */
2270 StartTime
= EngGetTickCount();
2272 Run
= dwMilliseconds
;
2274 DPRINT("WFII: waiting for %p\n", Handles
[1] );
2277 Timeout
.QuadPart
= Run
- Elapsed
;
2279 Status
= KeWaitForMultipleObjects( 2,
2285 dwMilliseconds
== INFINITE
? NULL
: &Timeout
,
2287 UserEnterExclusive();
2289 if (!NT_SUCCESS(Status
))
2291 SetLastNtError(Status
);
2292 Status
= WAIT_FAILED
;
2299 Status
= WAIT_FAILED
;
2305 co_IntPeekMessage( &Msg
, 0, 0, 0, PM_REMOVE
| PM_QS_SENDMESSAGE
);
2309 case STATUS_USER_APC
:
2310 case STATUS_ALERTED
:
2311 case STATUS_TIMEOUT
:
2312 DPRINT1("WFII: timeout\n");
2313 Status
= STATUS_TIMEOUT
;
2317 DPRINT1("WFII: finished\n");
2318 Status
= STATUS_SUCCESS
;
2322 if (dwMilliseconds
!= INFINITE
)
2324 Elapsed
= EngGetTickCount() - StartTime
;
2327 Status
= STATUS_TIMEOUT
;
2334 if (W32Process
->InputIdleEvent
)
2336 EngDeleteEvent((PEVENT
)W32Process
->InputIdleEvent
);
2337 W32Process
->InputIdleEvent
= NULL
;
2339 ObDereferenceObject(Process
);