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
;
167 Size
= MsgMemoryEntry
->Size
;
170 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
172 DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode());
180 PackParam(LPARAM
*lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
182 NCCALCSIZE_PARAMS
*UnpackedNcCalcsize
;
183 NCCALCSIZE_PARAMS
*PackedNcCalcsize
;
184 CREATESTRUCTW
*UnpackedCs
;
185 CREATESTRUCTW
*PackedCs
;
186 PUNICODE_STRING WindowName
;
187 PUNICODE_STRING ClassName
;
191 *lParamPacked
= lParam
;
192 if (WM_NCCALCSIZE
== Msg
&& wParam
)
194 UnpackedNcCalcsize
= (NCCALCSIZE_PARAMS
*) lParam
;
195 if (UnpackedNcCalcsize
->lppos
!= (PWINDOWPOS
) (UnpackedNcCalcsize
+ 1))
197 PackedNcCalcsize
= ExAllocatePoolWithTag(PagedPool
,
198 sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
),
200 if (NULL
== PackedNcCalcsize
)
202 DPRINT1("Not enough memory to pack lParam\n");
203 return STATUS_NO_MEMORY
;
205 RtlCopyMemory(PackedNcCalcsize
, UnpackedNcCalcsize
, sizeof(NCCALCSIZE_PARAMS
));
206 PackedNcCalcsize
->lppos
= (PWINDOWPOS
) (PackedNcCalcsize
+ 1);
207 RtlCopyMemory(PackedNcCalcsize
->lppos
, UnpackedNcCalcsize
->lppos
, sizeof(WINDOWPOS
));
208 *lParamPacked
= (LPARAM
) PackedNcCalcsize
;
211 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
213 UnpackedCs
= (CREATESTRUCTW
*) lParam
;
214 WindowName
= (PUNICODE_STRING
) UnpackedCs
->lpszName
;
215 ClassName
= (PUNICODE_STRING
) UnpackedCs
->lpszClass
;
216 Size
= sizeof(CREATESTRUCTW
) + WindowName
->Length
+ sizeof(WCHAR
);
217 if (IS_ATOM(ClassName
->Buffer
))
219 Size
+= sizeof(WCHAR
) + sizeof(ATOM
);
223 Size
+= sizeof(WCHAR
) + ClassName
->Length
+ sizeof(WCHAR
);
225 PackedCs
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
226 if (NULL
== PackedCs
)
228 DPRINT1("Not enough memory to pack lParam\n");
229 return STATUS_NO_MEMORY
;
231 RtlCopyMemory(PackedCs
, UnpackedCs
, sizeof(CREATESTRUCTW
));
232 CsData
= (PCHAR
) (PackedCs
+ 1);
233 PackedCs
->lpszName
= (LPCWSTR
) (CsData
- (PCHAR
) PackedCs
);
234 RtlCopyMemory(CsData
, WindowName
->Buffer
, WindowName
->Length
);
235 CsData
+= WindowName
->Length
;
236 *((WCHAR
*) CsData
) = L
'\0';
237 CsData
+= sizeof(WCHAR
);
238 PackedCs
->lpszClass
= (LPCWSTR
) (CsData
- (PCHAR
) PackedCs
);
239 if (IS_ATOM(ClassName
->Buffer
))
241 *((WCHAR
*) CsData
) = L
'A';
242 CsData
+= sizeof(WCHAR
);
243 *((ATOM
*) CsData
) = (ATOM
)(DWORD_PTR
) ClassName
->Buffer
;
244 CsData
+= sizeof(ATOM
);
248 *((WCHAR
*) CsData
) = L
'S';
249 CsData
+= sizeof(WCHAR
);
250 RtlCopyMemory(CsData
, ClassName
->Buffer
, ClassName
->Length
);
251 CsData
+= ClassName
->Length
;
252 *((WCHAR
*) CsData
) = L
'\0';
253 CsData
+= sizeof(WCHAR
);
255 ASSERT(CsData
== (PCHAR
) PackedCs
+ Size
);
256 *lParamPacked
= (LPARAM
) PackedCs
;
259 return STATUS_SUCCESS
;
263 UnpackParam(LPARAM lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
265 NCCALCSIZE_PARAMS
*UnpackedParams
;
266 NCCALCSIZE_PARAMS
*PackedParams
;
267 PWINDOWPOS UnpackedWindowPos
;
269 if (lParamPacked
== lParam
)
271 return STATUS_SUCCESS
;
274 if (WM_NCCALCSIZE
== Msg
&& wParam
)
276 PackedParams
= (NCCALCSIZE_PARAMS
*) lParamPacked
;
277 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
278 UnpackedWindowPos
= UnpackedParams
->lppos
;
279 RtlCopyMemory(UnpackedParams
, PackedParams
, sizeof(NCCALCSIZE_PARAMS
));
280 UnpackedParams
->lppos
= UnpackedWindowPos
;
281 RtlCopyMemory(UnpackedWindowPos
, PackedParams
+ 1, sizeof(WINDOWPOS
));
282 ExFreePool((PVOID
) lParamPacked
);
284 return STATUS_SUCCESS
;
286 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
288 ExFreePool((PVOID
) lParamPacked
);
290 return STATUS_SUCCESS
;
295 return STATUS_INVALID_PARAMETER
;
302 ( PWINDOW_OBJECT Window
, HWND hWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
304 BOOL SameThread
= FALSE
;
306 if (Window
->ti
== ((PTHREADINFO
)PsGetCurrentThreadWin32Thread())->ThreadInfo
)
309 if ((!SameThread
&& (Window
->ti
->Hooks
& HOOKID_TO_FLAG(WH_CALLWNDPROC
))) ||
310 (SameThread
&& ISITHOOKED(WH_CALLWNDPROC
)) )
317 co_HOOK_CallHooks( WH_CALLWNDPROC
, HC_ACTION
, SameThread
, (LPARAM
)&CWP
);
324 ( PWINDOW_OBJECT Window
, HWND hWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*uResult
)
326 BOOL SameThread
= FALSE
;
328 if (Window
->ti
== ((PTHREADINFO
)PsGetCurrentThreadWin32Thread())->ThreadInfo
)
331 if ((!SameThread
&& (Window
->ti
->Hooks
& HOOKID_TO_FLAG(WH_CALLWNDPROCRET
))) ||
332 (SameThread
&& ISITHOOKED(WH_CALLWNDPROCRET
)) )
337 CWPR
.wParam
= wParam
;
338 CWPR
.lParam
= lParam
;
339 CWPR
.lResult
= *uResult
;
340 co_HOOK_CallHooks( WH_CALLWNDPROCRET
, HC_ACTION
, SameThread
, (LPARAM
)&CWPR
);
346 IntDispatchMessage(PMSG pMsg
)
349 PWINDOW_OBJECT Window
= NULL
;
353 Window
= UserGetWindowObject(pMsg
->hwnd
);
354 if (!Window
|| !Window
->Wnd
) return 0;
357 if (((pMsg
->message
== WM_SYSTIMER
) ||
358 (pMsg
->message
== WM_TIMER
)) &&
361 if (pMsg
->message
== WM_TIMER
)
363 if (ValidateTimerCallback(GetW32ThreadInfo(),Window
,pMsg
->wParam
,pMsg
->lParam
))
365 return co_IntCallWindowProc((WNDPROC
)pMsg
->lParam
,
370 (LPARAM
)EngGetTickCount(),
377 PTIMER pTimer
= FindSystemTimer(pMsg
);
378 if (pTimer
&& pTimer
->pfn
)
380 pTimer
->pfn(pMsg
->hwnd
, WM_SYSTIMER
, (UINT
)pMsg
->wParam
, (DWORD
)EngGetTickCount());
386 if (!Window
) return 0;
388 retval
= co_IntPostOrSendMessage(pMsg
->hwnd
, pMsg
->message
, pMsg
->wParam
, pMsg
->lParam
);
390 if (pMsg
->message
== WM_PAINT
)
392 /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
393 HRGN hrgn
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
394 co_UserGetUpdateRgn( Window
, hrgn
, TRUE
);
395 NtGdiDeleteObject( hrgn
);
407 BOOL BadChk
= FALSE
, Ret
= TRUE
;
409 DECLARE_RETURN(BOOL
);
411 DPRINT("Enter NtUserCallMsgFilter\n");
412 UserEnterExclusive();
417 ProbeForRead((PVOID
)lpmsg
,
424 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
433 if (BadChk
) RETURN( FALSE
);
435 if (!co_HOOK_CallHooks( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)&Msg
))
437 Ret
= co_HOOK_CallHooks( WH_MSGFILTER
, code
, 0, (LPARAM
)&Msg
);
442 ProbeForWrite((PVOID
)lpmsg
,
445 RtlCopyMemory((PVOID
)lpmsg
,
449 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
454 if (BadChk
) RETURN( FALSE
);
458 DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_
);
464 NtUserDispatchMessage(PMSG UnsafeMsgInfo
)
470 UserEnterExclusive();
473 ProbeForRead(UnsafeMsgInfo
, sizeof(MSG
), 1);
474 RtlCopyMemory(&SafeMsg
, UnsafeMsgInfo
, sizeof(MSG
));
476 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
478 SetLastNtError(_SEH2_GetExceptionCode());
483 if (!Hit
) Res
= IntDispatchMessage(&SafeMsg
);
491 NtUserTranslateMessage(LPMSG lpMsg
,
496 DECLARE_RETURN(BOOL
);
498 DPRINT("Enter NtUserTranslateMessage\n");
499 UserEnterExclusive();
501 Status
= MmCopyFromCaller(&SafeMsg
, lpMsg
, sizeof(MSG
));
502 if(!NT_SUCCESS(Status
))
504 SetLastNtError(Status
);
508 RETURN( IntTranslateKbdMessage(&SafeMsg
, dwhkl
));
511 DPRINT("Leave NtUserTranslateMessage: ret=%i\n",_ret_
);
518 co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
)
520 if(!Msg
->hwnd
|| ThreadQueue
->CaptureWindow
)
529 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
534 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
541 case WM_LBUTTONDBLCLK
:
542 case WM_MBUTTONDBLCLK
:
543 case WM_RBUTTONDBLCLK
:
544 case WM_XBUTTONDBLCLK
:
547 PSYSTEM_CURSORINFO CurInfo
;
549 if(!IntGetWindowStationObject(InputWindowStation
))
553 CurInfo
= IntGetSysCursorInfo(InputWindowStation
);
554 wParam
= (WPARAM
)(CurInfo
->ButtonsDown
);
555 ObDereferenceObject(InputWindowStation
);
557 co_IntSendMessage(Msg
->hwnd
, WM_MOUSEMOVE
, wParam
, Msg
->lParam
);
558 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
561 case WM_NCLBUTTONDOWN
:
562 case WM_NCMBUTTONDOWN
:
563 case WM_NCRBUTTONDOWN
:
564 case WM_NCXBUTTONDOWN
:
565 case WM_NCLBUTTONDBLCLK
:
566 case WM_NCMBUTTONDBLCLK
:
567 case WM_NCRBUTTONDBLCLK
:
568 case WM_NCXBUTTONDBLCLK
:
570 co_IntSendMessage(Msg
->hwnd
, WM_NCMOUSEMOVE
, (WPARAM
)Msg
->wParam
, Msg
->lParam
);
571 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
578 co_IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, PWINDOW_OBJECT MsgWindow
,
582 PWINDOW_OBJECT Parent
;
584 ASSERT_REFS_CO(MsgWindow
);
586 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
588 /* eat the message, search again! */
592 Parent
= IntGetParent(MsgWindow
);//fixme: deref retval?
594 /* If no parent window, pass MsgWindows HWND as wParam. Fixes bug #3111 */
595 Result
= co_IntSendMessage(MsgWindow
->hSelf
,
597 (WPARAM
) (Parent
? Parent
->hSelf
: MsgWindow
->hSelf
),
598 (LPARAM
)MAKELONG(*HitTest
, Msg
->message
)
603 case MA_NOACTIVATEANDEAT
:
607 case MA_ACTIVATEANDEAT
:
608 co_IntMouseActivateWindow(MsgWindow
);
612 co_IntMouseActivateWindow(MsgWindow
);
620 co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, USHORT
*HitTest
, BOOL Remove
)
622 PWINDOW_OBJECT Window
;
623 USER_REFERENCE_ENTRY Ref
, DesktopRef
;
625 if(!(Window
= UserGetWindowObject(Msg
->hwnd
)))
627 /* let's just eat the message?! */
631 UserRefObjectCo(Window
, &Ref
);
633 if(ThreadQueue
== Window
->MessageQueue
&&
634 ThreadQueue
->CaptureWindow
!= Window
->hSelf
)
636 /* only send WM_NCHITTEST messages if we're not capturing the window! */
637 *HitTest
= co_IntSendMessage(Window
->hSelf
, WM_NCHITTEST
, 0,
638 MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
));
640 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
642 PWINDOW_OBJECT DesktopWindow
;
643 HWND hDesktop
= IntGetDesktopWindow();
645 if((DesktopWindow
= UserGetWindowObject(hDesktop
)))
649 UserRefObjectCo(DesktopWindow
, &DesktopRef
);
651 co_WinPosWindowFromPoint(DesktopWindow
, Window
->MessageQueue
, &Msg
->pt
, &Wnd
);
656 /* post the message to the other window */
657 Msg
->hwnd
= Wnd
->hSelf
;
658 if(!(Wnd
->Status
& WINDOWSTATUS_DESTROYING
))
660 MsqPostMessage(Wnd
->MessageQueue
, Msg
, FALSE
,
661 Msg
->message
== WM_MOUSEMOVE
? QS_MOUSEMOVE
:
665 /* eat the message */
666 UserDereferenceObject(Wnd
);
667 UserDerefObjectCo(DesktopWindow
);
668 UserDerefObjectCo(Window
);
671 UserDereferenceObject(Wnd
);
674 UserDerefObjectCo(DesktopWindow
);
683 if(IS_BTN_MESSAGE(Msg
->message
, DOWN
))
685 /* generate double click messages, if necessary */
686 if ((((*HitTest
) != HTCLIENT
) ||
687 (Window
->Wnd
->Class
->Style
& CS_DBLCLKS
)) &&
688 MsqIsDblClk(Msg
, Remove
))
690 Msg
->message
+= WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
;
694 if(Msg
->message
!= WM_MOUSEWHEEL
)
697 if ((*HitTest
) != HTCLIENT
)
699 Msg
->message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
700 if((Msg
->message
== WM_NCRBUTTONUP
) &&
701 (((*HitTest
) == HTCAPTION
) || ((*HitTest
) == HTSYSMENU
)))
703 Msg
->message
= WM_CONTEXTMENU
;
704 Msg
->wParam
= (WPARAM
)Window
->hSelf
;
708 Msg
->wParam
= *HitTest
;
710 Msg
->lParam
= MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
);
712 else if(ThreadQueue
->MoveSize
== NULL
&&
713 ThreadQueue
->MenuOwner
== NULL
)
715 /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
716 Msg
->lParam
= MAKELONG(
717 Msg
->pt
.x
- (WORD
)Window
->Wnd
->ClientRect
.left
,
718 Msg
->pt
.y
- (WORD
)Window
->Wnd
->ClientRect
.top
);
722 UserDerefObjectCo(Window
);
728 * Internal version of PeekMessage() doing all the work
731 co_IntPeekMessage(PUSER_MESSAGE Msg
,
738 LARGE_INTEGER LargeTickCount
;
739 PUSER_MESSAGE_QUEUE ThreadQueue
;
740 PUSER_MESSAGE Message
;
741 BOOL Present
, RemoveMessages
;
742 USER_REFERENCE_ENTRY Ref
;
744 MOUSEHOOKSTRUCT MHook
;
746 /* The queues and order in which they are checked are documented in the MSDN
747 article on GetMessage() */
749 pti
= PsGetCurrentThreadWin32Thread();
750 ThreadQueue
= pti
->MessageQueue
;
752 /* Inspect RemoveMsg flags */
753 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
754 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
760 KeQueryTickCount(&LargeTickCount
);
761 ThreadQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
763 /* Dispatch sent messages here. */
764 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
767 /* Now look for a quit message. */
769 if (ThreadQueue
->QuitPosted
)
771 /* According to the PSDK, WM_QUIT messages are always returned, regardless
772 of the filter specified */
773 Msg
->Msg
.hwnd
= NULL
;
774 Msg
->Msg
.message
= WM_QUIT
;
775 Msg
->Msg
.wParam
= ThreadQueue
->QuitExitCode
;
777 Msg
->FreeLParam
= FALSE
;
780 ThreadQueue
->QuitPosted
= FALSE
;
785 /* Now check for normal messages. */
786 Present
= co_MsqFindMessage(ThreadQueue
,
795 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
798 MsqDestroyMessage(Message
);
803 /* Check for hardware events. */
804 Present
= co_MsqFindMessage(ThreadQueue
,
813 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
816 MsqDestroyMessage(Message
);
821 /* Check for sent messages again. */
822 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
825 /* Check for paint messages. */
826 if (IntGetPaintMessage(hWnd
, MsgFilterMin
, MsgFilterMax
, pti
, &Msg
->Msg
, RemoveMessages
))
828 Msg
->FreeLParam
= FALSE
;
832 /* Check for WM_(SYS)TIMER messages */
833 Present
= MsqGetTimerMessage(ThreadQueue
, hWnd
, MsgFilterMin
, MsgFilterMax
,
834 &Msg
->Msg
, RemoveMessages
);
837 Msg
->FreeLParam
= FALSE
;
847 PWINDOW_OBJECT MsgWindow
= NULL
;
849 if(Msg
->Msg
.hwnd
&& (MsgWindow
= UserGetWindowObject(Msg
->Msg
.hwnd
)) &&
850 Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
)
854 UserRefObjectCo(MsgWindow
, &Ref
);
856 if(co_IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, TRUE
))
857 /* FIXME - check message filter again, if the message doesn't match anymore,
860 UserDerefObjectCo(MsgWindow
);
861 /* eat the message, search again */
865 if(ThreadQueue
->CaptureWindow
== NULL
)
867 co_IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
868 if((Msg
->Msg
.message
!= WM_MOUSEMOVE
&& Msg
->Msg
.message
!= WM_NCMOUSEMOVE
) &&
869 IS_BTN_MESSAGE(Msg
->Msg
.message
, DOWN
) &&
870 co_IntActivateWindowMouse(ThreadQueue
, &Msg
->Msg
, MsgWindow
, &HitTest
))
872 UserDerefObjectCo(MsgWindow
);
873 /* eat the message, search again */
878 UserDerefObjectCo(MsgWindow
);
882 co_IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
887 // UserDereferenceObject(MsgWindow);
893 if((Msg
->Msg
.hwnd
&& Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
) &&
894 co_IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, FALSE
))
895 /* FIXME - check message filter again, if the message doesn't match anymore,
898 /* eat the message, search again */
902 if ( ISITHOOKED(WH_MOUSE
) &&
903 Msg
->Msg
.message
>= WM_MOUSEFIRST
&&
904 Msg
->Msg
.message
<= WM_MOUSELAST
)
906 MHook
.pt
= Msg
->Msg
.pt
;
907 MHook
.hwnd
= Msg
->Msg
.hwnd
;
908 MHook
.wHitTestCode
= HitTest
;
909 MHook
.dwExtraInfo
= 0;
910 if (co_HOOK_CallHooks( WH_MOUSE
,
911 RemoveMsg
? HC_ACTION
: HC_NOREMOVE
,
915 if (ISITHOOKED(WH_CBT
))
917 MHook
.pt
= Msg
->Msg
.pt
;
918 MHook
.hwnd
= Msg
->Msg
.hwnd
;
919 MHook
.wHitTestCode
= HitTest
;
920 MHook
.dwExtraInfo
= 0;
921 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
,
922 Msg
->Msg
.message
, (LPARAM
)&MHook
);
927 if ( ISITHOOKED(WH_KEYBOARD
) &&
928 (Msg
->Msg
.message
== WM_KEYDOWN
|| Msg
->Msg
.message
== WM_KEYUP
) )
930 if (co_HOOK_CallHooks( WH_KEYBOARD
,
931 RemoveMsg
? HC_ACTION
: HC_NOREMOVE
,
932 LOWORD(Msg
->Msg
.wParam
),
935 if (ISITHOOKED(WH_CBT
))
937 /* skip this message */
938 co_HOOK_CallHooks( WH_CBT
, HCBT_KEYSKIPPED
,
939 LOWORD(Msg
->Msg
.wParam
), Msg
->Msg
.lParam
);
944 // The WH_GETMESSAGE hook enables an application to monitor messages about to
945 // be returned by the GetMessage or PeekMessage function.
946 if (ISITHOOKED(WH_GETMESSAGE
))
948 //DPRINT1("Peek WH_GETMESSAGE -> %x\n",&Msg);
949 co_HOOK_CallHooks( WH_GETMESSAGE
, HC_ACTION
, RemoveMsg
& PM_REMOVE
, (LPARAM
)&Msg
->Msg
);
958 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
966 NTUSERGETMESSAGEINFO Info
;
967 PWINDOW_OBJECT Window
;
968 PMSGMEMORY MsgMemoryEntry
;
972 DECLARE_RETURN(BOOL
);
974 DPRINT("Enter NtUserPeekMessage\n");
975 UserEnterExclusive();
978 if (hWnd
&& hWnd
!= INVALID_HANDLE_VALUE
)
980 if (!(Window
= UserGetWindowObject(hWnd
)))
986 if (MsgFilterMax
< MsgFilterMin
)
992 Present
= co_IntPeekMessage(&Msg
, hWnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
);
997 /* See if this message type is present in the table */
998 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
999 if (NULL
== MsgMemoryEntry
)
1001 /* Not present, no copying needed */
1002 Info
.LParamSize
= 0;
1006 /* Determine required size */
1007 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
1009 /* Allocate required amount of user-mode memory */
1010 Info
.LParamSize
= Size
;
1012 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
1013 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
1014 if (! NT_SUCCESS(Status
))
1016 SetLastNtError(Status
);
1019 /* Transfer lParam data to user-mode mem */
1020 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
1021 if (! NT_SUCCESS(Status
))
1023 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
1024 &Info
.LParamSize
, MEM_RELEASE
);
1025 SetLastNtError(Status
);
1028 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
1030 if (RemoveMsg
&& Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
1032 ExFreePool((void *) Msg
.Msg
.lParam
);
1034 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
1035 if (! NT_SUCCESS(Status
))
1037 SetLastNtError(Status
);
1045 DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_
);
1050 static BOOL FASTCALL
1051 co_IntWaitMessage(HWND Wnd
,
1056 PUSER_MESSAGE_QUEUE ThreadQueue
;
1060 pti
= PsGetCurrentThreadWin32Thread();
1061 ThreadQueue
= pti
->MessageQueue
;
1065 if (co_IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_NOREMOVE
))
1070 /* Nothing found. Wait for new messages. */
1071 Status
= co_MsqWaitForNewMessages(ThreadQueue
, Wnd
, MsgFilterMin
, MsgFilterMax
);
1073 while ((STATUS_WAIT_0
<= Status
&& Status
<= STATUS_WAIT_63
) || STATUS_TIMEOUT
== Status
);
1075 SetLastNtError(Status
);
1081 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
1086 * FUNCTION: Get a message from the calling thread's message queue.
1088 * UnsafeMsg - Pointer to the structure which receives the returned message.
1089 * Wnd - Window whose messages are to be retrieved.
1090 * MsgFilterMin - Integer value of the lowest message value to be
1092 * MsgFilterMax - Integer value of the highest message value to be
1097 NTUSERGETMESSAGEINFO Info
;
1099 /* FIXME: if initialization is removed, gcc complains that this may be used before initialization. Please review */
1100 PWINDOW_OBJECT Window
= NULL
;
1101 PMSGMEMORY MsgMemoryEntry
;
1105 DECLARE_RETURN(BOOL
);
1106 // USER_REFERENCE_ENTRY Ref;
1108 DPRINT("Enter NtUserGetMessage\n");
1109 UserEnterExclusive();
1111 /* Validate input */
1112 if (hWnd
&& !(Window
= UserGetWindowObject(hWnd
)))
1117 // if (Window) UserRefObjectCo(Window, &Ref);
1119 if (MsgFilterMax
< MsgFilterMin
)
1127 GotMessage
= co_IntPeekMessage(&Msg
, hWnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
);
1131 /* See if this message type is present in the table */
1132 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
1133 if (NULL
== MsgMemoryEntry
)
1135 /* Not present, no copying needed */
1136 Info
.LParamSize
= 0;
1140 /* Determine required size */
1141 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
1143 /* Allocate required amount of user-mode memory */
1144 Info
.LParamSize
= Size
;
1146 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
1147 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
1149 if (! NT_SUCCESS(Status
))
1151 SetLastNtError(Status
);
1154 /* Transfer lParam data to user-mode mem */
1155 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
1156 if (! NT_SUCCESS(Status
))
1158 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
1159 &Info
.LParamSize
, MEM_DECOMMIT
);
1160 SetLastNtError(Status
);
1163 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
1165 if (Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
1167 ExFreePool((void *) Msg
.Msg
.lParam
);
1169 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
1170 if (! NT_SUCCESS(Status
))
1172 SetLastNtError(Status
);
1176 else if (! co_IntWaitMessage(hWnd
, MsgFilterMin
, MsgFilterMax
))
1181 while (! GotMessage
);
1183 RETURN( WM_QUIT
!= Info
.Msg
.message
);
1186 // if (Window) UserDerefObjectCo(Window);
1188 DPRINT("Leave NtUserGetMessage\n");
1194 static NTSTATUS FASTCALL
1195 CopyMsgToKernelMem(MSG
*KernelModeMsg
, MSG
*UserModeMsg
, PMSGMEMORY MsgMemoryEntry
)
1202 *KernelModeMsg
= *UserModeMsg
;
1204 /* See if this message type is present in the table */
1205 if (NULL
== MsgMemoryEntry
)
1207 /* Not present, no copying needed */
1208 return STATUS_SUCCESS
;
1211 /* Determine required size */
1212 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1216 /* Allocate kernel mem */
1217 KernelMem
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
1218 if (NULL
== KernelMem
)
1220 DPRINT1("Not enough memory to copy message to kernel mem\n");
1221 return STATUS_NO_MEMORY
;
1223 KernelModeMsg
->lParam
= (LPARAM
) KernelMem
;
1225 /* Copy data if required */
1226 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_READ
))
1228 Status
= MmCopyFromCaller(KernelMem
, (PVOID
) UserModeMsg
->lParam
, Size
);
1229 if (! NT_SUCCESS(Status
))
1231 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
1232 ExFreePoolWithTag(KernelMem
, TAG_MSG
);
1238 /* Make sure we don't pass any secrets to usermode */
1239 RtlZeroMemory(KernelMem
, Size
);
1244 KernelModeMsg
->lParam
= 0;
1247 return STATUS_SUCCESS
;
1250 static NTSTATUS FASTCALL
1251 CopyMsgToUserMem(MSG
*UserModeMsg
, MSG
*KernelModeMsg
)
1254 PMSGMEMORY MsgMemoryEntry
;
1257 /* See if this message type is present in the table */
1258 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
1259 if (NULL
== MsgMemoryEntry
)
1261 /* Not present, no copying needed */
1262 return STATUS_SUCCESS
;
1265 /* Determine required size */
1266 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1270 /* Copy data if required */
1271 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_WRITE
))
1273 Status
= MmCopyToCaller((PVOID
) UserModeMsg
->lParam
, (PVOID
) KernelModeMsg
->lParam
, Size
);
1274 if (! NT_SUCCESS(Status
))
1276 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1277 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1282 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1285 return STATUS_SUCCESS
;
1289 UserPostMessage(HWND Wnd
,
1295 MSG UserModeMsg
, KernelModeMsg
;
1296 LARGE_INTEGER LargeTickCount
;
1298 PMSGMEMORY MsgMemoryEntry
;
1300 pti
= PsGetCurrentThreadWin32Thread();
1303 MsqPostQuitMessage(pti
->MessageQueue
, wParam
);
1305 else if (Wnd
== HWND_BROADCAST
)
1308 PWINDOW_OBJECT DesktopWindow
;
1311 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1312 List
= IntWinListChildren(DesktopWindow
);
1316 for (i
= 0; List
[i
]; i
++)
1317 UserPostMessage(List
[i
], Msg
, wParam
, lParam
);
1323 PWINDOW_OBJECT Window
;
1325 Window
= UserGetWindowObject(Wnd
);
1330 if(Window
->Status
& WINDOWSTATUS_DESTROYING
)
1332 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd
);
1333 /* FIXME - last error code? */
1337 UserModeMsg
.hwnd
= Wnd
;
1338 UserModeMsg
.message
= Msg
;
1339 UserModeMsg
.wParam
= wParam
;
1340 UserModeMsg
.lParam
= lParam
;
1341 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1342 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1343 if (! NT_SUCCESS(Status
))
1345 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1348 IntGetCursorLocation(pti
->Desktop
->WindowStation
,
1350 KeQueryTickCount(&LargeTickCount
);
1351 KernelModeMsg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1352 MsqPostMessage(Window
->MessageQueue
, &KernelModeMsg
,
1353 NULL
!= MsgMemoryEntry
&& 0 != KernelModeMsg
.lParam
,
1362 NtUserPostMessage(HWND hWnd
,
1367 DECLARE_RETURN(BOOL
);
1369 DPRINT("Enter NtUserPostMessage\n");
1370 UserEnterExclusive();
1372 RETURN(UserPostMessage(hWnd
, Msg
, wParam
, lParam
));
1375 DPRINT("Leave NtUserPostMessage, ret=%i\n",_ret_
);
1383 NtUserPostThreadMessage(DWORD idThread
,
1388 MSG UserModeMsg
, KernelModeMsg
;
1390 PTHREADINFO pThread
;
1392 PMSGMEMORY MsgMemoryEntry
;
1393 DECLARE_RETURN(BOOL
);
1395 DPRINT("Enter NtUserPostThreadMessage\n");
1396 UserEnterExclusive();
1398 Status
= PsLookupThreadByThreadId((HANDLE
)idThread
,&peThread
);
1400 if( Status
== STATUS_SUCCESS
)
1402 pThread
= (PTHREADINFO
)peThread
->Tcb
.Win32Thread
;
1403 if( !pThread
|| !pThread
->MessageQueue
)
1405 ObDereferenceObject( peThread
);
1409 UserModeMsg
.hwnd
= NULL
;
1410 UserModeMsg
.message
= Msg
;
1411 UserModeMsg
.wParam
= wParam
;
1412 UserModeMsg
.lParam
= lParam
;
1413 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1414 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1415 if (! NT_SUCCESS(Status
))
1417 ObDereferenceObject( peThread
);
1418 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1421 MsqPostMessage(pThread
->MessageQueue
, &KernelModeMsg
,
1422 NULL
!= MsgMemoryEntry
&& 0 != KernelModeMsg
.lParam
,
1424 ObDereferenceObject( peThread
);
1429 SetLastNtError( Status
);
1434 DPRINT("Leave NtUserPostThreadMessage, ret=%i\n",_ret_
);
1440 NtUserQuerySendMessage(DWORD Unknown0
)
1448 co_IntSendMessage(HWND hWnd
,
1453 ULONG_PTR Result
= 0;
1454 if(co_IntSendMessageTimeout(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1456 return (LRESULT
)Result
;
1463 co_IntSendMessageTimeoutSingle(HWND hWnd
,
1473 PWINDOW_OBJECT Window
= NULL
;
1474 PMSGMEMORY MsgMemoryEntry
;
1475 INT lParamBufferSize
;
1476 LPARAM lParamPacked
;
1477 PTHREADINFO Win32Thread
;
1478 DECLARE_RETURN(LRESULT
);
1479 USER_REFERENCE_ENTRY Ref
;
1481 if (!(Window
= UserGetWindowObject(hWnd
)))
1486 UserRefObjectCo(Window
, &Ref
);
1488 Win32Thread
= PsGetCurrentThreadWin32Thread();
1490 IntCallWndProc( Window
, hWnd
, Msg
, wParam
, lParam
);
1492 if (NULL
!= Win32Thread
&&
1493 Window
->MessageQueue
== Win32Thread
->MessageQueue
)
1495 if (Win32Thread
->IsExiting
)
1497 /* Never send messages to exiting threads */
1501 /* See if this message type is present in the table */
1502 MsgMemoryEntry
= FindMsgMemory(Msg
);
1503 if (NULL
== MsgMemoryEntry
)
1505 lParamBufferSize
= -1;
1509 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
1512 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
)))
1514 DPRINT1("Failed to pack message parameters\n");
1518 Result
= (ULONG_PTR
)co_IntCallWindowProc(Window
->Wnd
->WndProc
, !Window
->Wnd
->Unicode
, hWnd
, Msg
, wParam
,
1519 lParamPacked
,lParamBufferSize
);
1526 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, (LRESULT
*)uResult
);
1528 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
)))
1530 DPRINT1("Failed to unpack message parameters\n");
1537 if (uFlags
& SMTO_ABORTIFHUNG
&& MsqIsHung(Window
->MessageQueue
))
1539 /* FIXME - Set a LastError? */
1543 if (Window
->Status
& WINDOWSTATUS_DESTROYING
)
1545 /* FIXME - last error? */
1546 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd
);
1552 Status
= co_MsqSendMessage( Window
->MessageQueue
,
1558 (uFlags
& SMTO_BLOCK
),
1562 while ((STATUS_TIMEOUT
== Status
) &&
1563 (uFlags
& SMTO_NOTIMEOUTIFNOTHUNG
) &&
1564 !MsqIsHung(Window
->MessageQueue
));
1566 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, (LRESULT
*)uResult
);
1568 if (STATUS_TIMEOUT
== Status
)
1572 Microsoft Windows 2000: If GetLastError returns zero, then the function
1574 XP+ : If the function fails or times out, the return value is zero.
1575 To get extended error information, call GetLastError. If GetLastError
1576 returns ERROR_TIMEOUT, then the function timed out.
1578 SetLastWin32Error(ERROR_TIMEOUT
);
1581 else if (! NT_SUCCESS(Status
))
1583 SetLastNtError(Status
);
1590 if (Window
) UserDerefObjectCo(Window
);
1595 co_IntSendMessageTimeout(HWND hWnd
,
1603 PWINDOW_OBJECT DesktopWindow
;
1607 if (HWND_BROADCAST
!= hWnd
)
1609 return co_IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1612 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1613 if (NULL
== DesktopWindow
)
1615 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1619 Children
= IntWinListChildren(DesktopWindow
);
1620 if (NULL
== Children
)
1625 for (Child
= Children
; NULL
!= *Child
; Child
++)
1627 co_IntSendMessageTimeoutSingle(*Child
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1630 ExFreePool(Children
);
1632 return (LRESULT
) TRUE
;
1636 /* This function posts a message if the destination's message queue belongs to
1637 another thread, otherwise it sends the message. It does not support broadcast
1640 co_IntPostOrSendMessage(HWND hWnd
,
1647 PWINDOW_OBJECT Window
;
1649 if(hWnd
== HWND_BROADCAST
)
1654 if(!(Window
= UserGetWindowObject(hWnd
)))
1659 pti
= PsGetCurrentThreadWin32Thread();
1660 if(Window
->MessageQueue
!= pti
->MessageQueue
)
1662 Result
= UserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1666 if(!co_IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
)) {
1671 return (LRESULT
)Result
;
1675 co_IntDoSendMessage(HWND hWnd
,
1680 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1683 LRESULT Result
= TRUE
;
1685 PWINDOW_OBJECT Window
= NULL
;
1686 NTUSERSENDMESSAGEINFO Info
;
1689 PMSGMEMORY MsgMemoryEntry
;
1691 RtlZeroMemory(&Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1693 /* FIXME: Call hooks. */
1694 if (HWND_BROADCAST
!= hWnd
)
1696 Window
= UserGetWindowObject(hWnd
);
1699 /* Tell usermode to not touch this one */
1700 Info
.HandledByKernel
= TRUE
;
1701 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1708 /* FIXME: Check for an exiting window. */
1710 /* See if the current thread can handle the message */
1711 pti
= PsGetCurrentThreadWin32Thread();
1712 if (HWND_BROADCAST
!= hWnd
&& NULL
!= pti
&&
1713 Window
->MessageQueue
== pti
->MessageQueue
)
1715 /* Gather the information usermode needs to call the window proc directly */
1716 Info
.HandledByKernel
= FALSE
;
1718 Status
= MmCopyFromCaller(&(Info
.Ansi
), &(UnsafeInfo
->Ansi
),
1720 if (! NT_SUCCESS(Status
))
1722 Info
.Ansi
= ! Window
->Wnd
->Unicode
;
1725 IntCallWndProc( Window
, hWnd
, Msg
, wParam
, lParam
);
1727 if (Window
->Wnd
->IsSystem
)
1729 Info
.Proc
= (!Info
.Ansi
? Window
->Wnd
->WndProc
: Window
->Wnd
->WndProcExtra
);
1733 Info
.Ansi
= !Window
->Wnd
->Unicode
;
1734 Info
.Proc
= Window
->Wnd
->WndProc
;
1737 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, &Result
);
1742 /* Must be handled by other thread */
1743 // if (HWND_BROADCAST != hWnd)
1745 // UserDereferenceObject(Window);
1747 Info
.HandledByKernel
= TRUE
;
1748 UserModeMsg
.hwnd
= hWnd
;
1749 UserModeMsg
.message
= Msg
;
1750 UserModeMsg
.wParam
= wParam
;
1751 UserModeMsg
.lParam
= lParam
;
1752 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1753 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1754 if (! NT_SUCCESS(Status
))
1756 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1757 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1758 return (dsm
? 0 : -1);
1762 Result
= co_IntSendMessage(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1763 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
);
1767 Result
= co_IntSendMessageTimeout(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1768 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
,
1769 dsm
->uFlags
, dsm
->uTimeout
, &dsm
->Result
);
1771 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
1772 if (! NT_SUCCESS(Status
))
1774 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1775 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1776 return(dsm
? 0 : -1);
1780 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1781 if (! NT_SUCCESS(Status
))
1783 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1786 return (LRESULT
)Result
;
1790 NtUserSendMessageTimeout(HWND hWnd
,
1797 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1801 DECLARE_RETURN(BOOL
);
1803 DPRINT("Enter NtUserSendMessageTimeout\n");
1804 UserEnterExclusive();
1806 dsm
.uFlags
= uFlags
;
1807 dsm
.uTimeout
= uTimeout
;
1808 Result
= co_IntDoSendMessage(hWnd
, Msg
, wParam
, lParam
, &dsm
, UnsafeInfo
);
1809 if(uResult
!= NULL
&& Result
!= 0)
1813 Status
= MmCopyToCaller(uResult
, &dsm
.Result
, sizeof(ULONG_PTR
));
1814 if(!NT_SUCCESS(Status
))
1816 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1823 DPRINT("Leave NtUserSendMessageTimeout, ret=%i\n",_ret_
);
1829 NtUserSendMessage(HWND Wnd
,
1833 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1835 DECLARE_RETURN(BOOL
);
1837 DPRINT("Enter NtUserSendMessage\n");
1838 UserEnterExclusive();
1840 RETURN(co_IntDoSendMessage(Wnd
, Msg
, wParam
, lParam
, NULL
, UnsafeInfo
));
1843 DPRINT("Leave NtUserSendMessage, ret=%i\n",_ret_
);
1850 UserSendNotifyMessage(HWND hWnd
,
1856 // Basicly the same as IntPostOrSendMessage
1857 if (hWnd
== HWND_BROADCAST
) //Handle Broadcast
1860 PWINDOW_OBJECT DesktopWindow
;
1863 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1864 List
= IntWinListChildren(DesktopWindow
);
1868 for (i
= 0; List
[i
]; i
++)
1870 UserSendNotifyMessage(List
[i
], Msg
, wParam
, lParam
);
1879 PWINDOW_OBJECT Window
;
1883 PMSGMEMORY MsgMemoryEntry
;
1885 if(!(Window
= UserGetWindowObject(hWnd
))) return FALSE
;
1887 pti
= PsGetCurrentThreadWin32Thread();
1888 if(Window
->MessageQueue
!= pti
->MessageQueue
)
1889 { // Send message w/o waiting for it.
1890 Result
= UserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1893 { // Handle message and callback.
1894 UserModeMsg
.hwnd
= hWnd
;
1895 UserModeMsg
.message
= Msg
;
1896 UserModeMsg
.wParam
= wParam
;
1897 UserModeMsg
.lParam
= lParam
;
1898 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1899 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1900 if (! NT_SUCCESS(Status
))
1902 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1905 Result
= co_IntSendMessageTimeoutSingle(
1906 KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1907 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
,
1908 SMTO_NORMAL
, 0, &PResult
);
1910 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
1911 if (! NT_SUCCESS(Status
))
1913 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1923 NtUserSendNotifyMessage(HWND hWnd
,
1928 DECLARE_RETURN(BOOL
);
1930 DPRINT("EnterNtUserSendNotifyMessage\n");
1931 UserEnterExclusive();
1933 RETURN(UserSendNotifyMessage(hWnd
, Msg
, wParam
, lParam
));
1936 DPRINT("Leave NtUserSendNotifyMessage, ret=%i\n",_ret_
);
1944 NtUserWaitMessage(VOID
)
1946 DECLARE_RETURN(BOOL
);
1948 DPRINT("EnterNtUserWaitMessage\n");
1949 UserEnterExclusive();
1951 RETURN(co_IntWaitMessage(NULL
, 0, 0));
1954 DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_
);
1960 IntGetQueueStatus(BOOL ClearChanges
)
1963 PUSER_MESSAGE_QUEUE Queue
;
1965 DECLARE_RETURN(DWORD
);
1967 DPRINT("Enter IntGetQueueStatus\n");
1969 pti
= PsGetCurrentThreadWin32Thread();
1970 Queue
= pti
->MessageQueue
;
1972 Result
= MAKELONG(Queue
->QueueBits
, Queue
->ChangedBits
);
1975 Queue
->ChangedBits
= 0;
1981 DPRINT("Leave IntGetQueueStatus, ret=%i\n",_ret_
);
1986 IntInitMessagePumpHook()
1988 if (((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->ThreadInfo
)
1990 ((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->ThreadInfo
->ClientThreadInfo
.dwcPumpHook
++;
1997 IntUninitMessagePumpHook()
1999 if (((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->ThreadInfo
)
2001 if (((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->ThreadInfo
->ClientThreadInfo
.dwcPumpHook
<= 0)
2005 ((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->ThreadInfo
->ClientThreadInfo
.dwcPumpHook
--;
2018 ULONG_PTR ResultInfo
,
2019 DWORD dwType
, // fnID?
2022 LRESULT lResult
= 0;
2023 PWINDOW_OBJECT Window
= NULL
;
2024 USER_REFERENCE_ENTRY Ref
;
2026 UserEnterExclusive();
2028 /* Validate input */
2029 if (hWnd
&& (hWnd
!= INVALID_HANDLE_VALUE
) && !(Window
= UserGetWindowObject(hWnd
)))
2035 case FNID_DEFWINDOWPROC
:
2036 UserRefObjectCo(Window
, &Ref
);
2037 lResult
= IntDefWindowProc(Window
, Msg
, wParam
, lParam
, Ansi
);
2038 UserDerefObjectCo(Window
);
2040 case FNID_BROADCASTSYSTEMMESSAGE
:
2042 PBROADCASTPARM parm
;
2043 BOOL BadChk
= FALSE
;
2044 DWORD_PTR RetVal
= 0;
2051 ProbeForWrite((PVOID
)ResultInfo
,
2052 sizeof(BROADCASTPARM
),
2054 parm
= (PBROADCASTPARM
)ResultInfo
;
2056 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2066 if ( parm
->recipients
& BSM_ALLDESKTOPS
||
2067 parm
->recipients
== BSM_ALLCOMPONENTS
)
2070 else if (parm
->recipients
& BSM_APPLICATIONS
)
2072 if (parm
->flags
& BSF_QUERY
)
2074 if (parm
->flags
& BSF_FORCEIFHUNG
|| parm
->flags
& BSF_NOHANG
)
2076 co_IntSendMessageTimeout( HWND_BROADCAST
,
2084 else if (parm
->flags
& BSF_NOTIMEOUTIFNOTHUNG
)
2086 co_IntSendMessageTimeout( HWND_BROADCAST
,
2090 SMTO_NOTIMEOUTIFNOTHUNG
,
2096 co_IntSendMessageTimeout( HWND_BROADCAST
,
2105 else if (parm
->flags
& BSF_POSTMESSAGE
)
2107 lResult
= UserPostMessage(HWND_BROADCAST
, Msg
, wParam
, lParam
);
2109 else if ( parm
->flags
& BSF_SENDNOTIFYMESSAGE
)
2111 lResult
= UserSendNotifyMessage(HWND_BROADCAST
, Msg
, wParam
, lParam
);
2116 case FNID_SENDMESSAGECALLBACK
:
2118 // CallNextHook bypass.
2119 case FNID_CALLWNDPROC
:
2120 case FNID_CALLWNDPROCRET
:
2122 PCLIENTINFO ClientInfo
= GetWin32ClientInfo();
2123 PHOOK NextObj
, Hook
= ClientInfo
->phkCurrent
;
2125 if (!ClientInfo
|| !Hook
) break;
2127 UserReferenceObject(Hook
);
2129 if (Hook
->Thread
&& (Hook
->Thread
!= PsGetCurrentThread()))
2131 UserDereferenceObject(Hook
);
2135 NextObj
= IntGetNextHook(Hook
);
2136 ClientInfo
->phkCurrent
= NextObj
;
2138 if ( Hook
->HookId
== WH_CALLWNDPROC
)
2143 CWP
.wParam
= wParam
;
2144 CWP
.lParam
= lParam
;
2145 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook
, NextObj
);
2147 lResult
= co_IntCallHookProc( Hook
->HookId
,
2149 ((ClientInfo
->CI_flags
& CI_CURTHPRHOOK
) ? 1 : 0),
2160 CWPR
.wParam
= wParam
;
2161 CWPR
.lParam
= lParam
;
2162 CWPR
.lResult
= ClientInfo
->dwHookData
;
2164 lResult
= co_IntCallHookProc( Hook
->HookId
,
2166 ((ClientInfo
->CI_flags
& CI_CURTHPRHOOK
) ? 1 : 0),
2172 UserDereferenceObject(Hook
);
2173 lResult
= (LRESULT
) NextObj
;
2181 #define INFINITE 0xFFFFFFFF
2182 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2186 NtUserWaitForInputIdle(
2188 IN DWORD dwMilliseconds
,
2192 PW32PROCESS W32Process
;
2195 LARGE_INTEGER Timeout
;
2196 ULONGLONG StartTime
, Run
, Elapsed
= 0;
2198 UserEnterExclusive();
2200 Status
= ObReferenceObjectByHandle(hProcess
,
2201 PROCESS_QUERY_INFORMATION
,
2207 if (!NT_SUCCESS(Status
))
2210 SetLastNtError(Status
);
2214 W32Process
= (PW32PROCESS
)Process
->Win32Process
;
2217 ObDereferenceObject(Process
);
2219 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2223 EngCreateEvent((PEVENT
*)&W32Process
->InputIdleEvent
);
2225 Handles
[0] = Process
;
2226 Handles
[1] = W32Process
->InputIdleEvent
;
2230 ObDereferenceObject(Process
);
2232 return STATUS_SUCCESS
; /* no event to wait on */
2235 StartTime
= EngGetTickCount();
2237 Run
= dwMilliseconds
;
2239 DPRINT("WFII: waiting for %p\n", Handles
[1] );
2242 Timeout
.QuadPart
= Run
- Elapsed
;
2244 Status
= KeWaitForMultipleObjects( 2,
2250 dwMilliseconds
== INFINITE
? NULL
: &Timeout
,
2252 UserEnterExclusive();
2254 if (!NT_SUCCESS(Status
))
2256 SetLastNtError(Status
);
2257 Status
= WAIT_FAILED
;
2264 Status
= WAIT_FAILED
;
2270 co_IntPeekMessage( &Msg
, 0, 0, 0, PM_REMOVE
| PM_QS_SENDMESSAGE
);
2274 case STATUS_USER_APC
:
2275 case STATUS_ALERTED
:
2276 case STATUS_TIMEOUT
:
2277 DPRINT1("WFII: timeout\n");
2278 Status
= STATUS_TIMEOUT
;
2282 DPRINT1("WFII: finished\n");
2283 Status
= STATUS_SUCCESS
;
2287 if (dwMilliseconds
!= INFINITE
)
2289 Elapsed
= EngGetTickCount() - StartTime
;
2292 Status
= STATUS_TIMEOUT
;
2299 if (W32Process
->InputIdleEvent
)
2301 EngDeleteEvent((PEVENT
)W32Process
->InputIdleEvent
);
2302 W32Process
->InputIdleEvent
= NULL
;
2304 ObDereferenceObject(Process
);