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
);
351 BOOL BadChk
= FALSE
, Ret
= TRUE
;
353 DECLARE_RETURN(BOOL
);
355 DPRINT("Enter NtUserCallMsgFilter\n");
356 UserEnterExclusive();
361 ProbeForRead((PVOID
)lpmsg
,
368 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
377 if (BadChk
) RETURN( FALSE
);
379 if (!co_HOOK_CallHooks( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)&Msg
))
381 Ret
= co_HOOK_CallHooks( WH_MSGFILTER
, code
, 0, (LPARAM
)&Msg
);
386 ProbeForWrite((PVOID
)lpmsg
,
389 RtlCopyMemory((PVOID
)lpmsg
,
393 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
398 if (BadChk
) RETURN( FALSE
);
402 DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_
);
408 NtUserDispatchMessage(PNTUSERDISPATCHMESSAGEINFO UnsafeMsgInfo
)
411 NTUSERDISPATCHMESSAGEINFO MsgInfo
;
412 LRESULT Result
= TRUE
;
413 DECLARE_RETURN(LRESULT
);
415 DPRINT("Enter NtUserDispatchMessage\n");
416 UserEnterExclusive();
418 Status
= MmCopyFromCaller(&MsgInfo
, UnsafeMsgInfo
, sizeof(NTUSERDISPATCHMESSAGEINFO
));
419 if (! NT_SUCCESS(Status
))
421 SetLastNtError(Status
);
425 /* Process timer messages. */
426 if (WM_TIMER
== MsgInfo
.Msg
.message
&& 0 != MsgInfo
.Msg
.lParam
)
428 LARGE_INTEGER LargeTickCount
;
429 /* FIXME: Call hooks. */
431 /* FIXME: Check for continuing validity of timer. */
433 MsgInfo
.HandledByKernel
= FALSE
;
434 KeQueryTickCount(&LargeTickCount
);
435 MsgInfo
.Proc
= (WNDPROC
) MsgInfo
.Msg
.lParam
;
436 MsgInfo
.Msg
.lParam
= (LPARAM
)LargeTickCount
.u
.LowPart
;
438 else if (NULL
== MsgInfo
.Msg
.hwnd
)
440 MsgInfo
.HandledByKernel
= TRUE
;
445 PWINDOW_OBJECT Window
;
447 /* Get the window object. */
448 Window
= UserGetWindowObject(MsgInfo
.Msg
.hwnd
);
451 MsgInfo
.HandledByKernel
= TRUE
;
456 if (Window
->OwnerThread
!= PsGetCurrentThread())
458 DPRINT1("Window doesn't belong to the calling thread!\n");
459 MsgInfo
.HandledByKernel
= TRUE
;
464 /* FIXME: Call hook procedures. */
466 MsgInfo
.HandledByKernel
= FALSE
;
469 if (Window
->Wnd
->IsSystem
)
471 MsgInfo
.Proc
= (!MsgInfo
.Ansi
? Window
->Wnd
->WndProc
: Window
->Wnd
->WndProcExtra
);
475 MsgInfo
.Ansi
= !Window
->Wnd
->Unicode
;
476 MsgInfo
.Proc
= Window
->Wnd
->WndProc
;
481 Status
= MmCopyToCaller(UnsafeMsgInfo
, &MsgInfo
, sizeof(NTUSERDISPATCHMESSAGEINFO
));
482 if (! NT_SUCCESS(Status
))
484 SetLastNtError(Status
);
491 DPRINT("Leave NtUserDispatchMessage. ret=%i\n", _ret_
);
498 NtUserTranslateMessage(LPMSG lpMsg
,
503 DECLARE_RETURN(BOOL
);
505 DPRINT("Enter NtUserTranslateMessage\n");
506 UserEnterExclusive();
508 Status
= MmCopyFromCaller(&SafeMsg
, lpMsg
, sizeof(MSG
));
509 if(!NT_SUCCESS(Status
))
511 SetLastNtError(Status
);
515 RETURN( IntTranslateKbdMessage(&SafeMsg
, dwhkl
));
518 DPRINT("Leave NtUserTranslateMessage: ret=%i\n",_ret_
);
525 co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
)
527 if(!Msg
->hwnd
|| ThreadQueue
->CaptureWindow
)
536 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
541 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
548 case WM_LBUTTONDBLCLK
:
549 case WM_MBUTTONDBLCLK
:
550 case WM_RBUTTONDBLCLK
:
551 case WM_XBUTTONDBLCLK
:
554 PSYSTEM_CURSORINFO CurInfo
;
556 if(!IntGetWindowStationObject(InputWindowStation
))
560 CurInfo
= IntGetSysCursorInfo(InputWindowStation
);
561 wParam
= (WPARAM
)(CurInfo
->ButtonsDown
);
562 ObDereferenceObject(InputWindowStation
);
564 co_IntSendMessage(Msg
->hwnd
, WM_MOUSEMOVE
, wParam
, Msg
->lParam
);
565 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
568 case WM_NCLBUTTONDOWN
:
569 case WM_NCMBUTTONDOWN
:
570 case WM_NCRBUTTONDOWN
:
571 case WM_NCXBUTTONDOWN
:
572 case WM_NCLBUTTONDBLCLK
:
573 case WM_NCMBUTTONDBLCLK
:
574 case WM_NCRBUTTONDBLCLK
:
575 case WM_NCXBUTTONDBLCLK
:
577 co_IntSendMessage(Msg
->hwnd
, WM_NCMOUSEMOVE
, (WPARAM
)Msg
->wParam
, Msg
->lParam
);
578 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
585 co_IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, PWINDOW_OBJECT MsgWindow
,
589 PWINDOW_OBJECT Parent
;
591 ASSERT_REFS_CO(MsgWindow
);
593 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
595 /* eat the message, search again! */
599 Parent
= IntGetParent(MsgWindow
);//fixme: deref retval?
601 /* If no parent window, pass MsgWindows HWND as wParam. Fixes bug #3111 */
602 Result
= co_IntSendMessage(MsgWindow
->hSelf
,
604 (WPARAM
) (Parent
? Parent
->hSelf
: MsgWindow
->hSelf
),
605 (LPARAM
)MAKELONG(*HitTest
, Msg
->message
)
610 case MA_NOACTIVATEANDEAT
:
614 case MA_ACTIVATEANDEAT
:
615 co_IntMouseActivateWindow(MsgWindow
);
619 co_IntMouseActivateWindow(MsgWindow
);
627 co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, USHORT
*HitTest
, BOOL Remove
)
629 PWINDOW_OBJECT Window
;
630 USER_REFERENCE_ENTRY Ref
, DesktopRef
;
632 if(!(Window
= UserGetWindowObject(Msg
->hwnd
)))
634 /* let's just eat the message?! */
638 UserRefObjectCo(Window
, &Ref
);
640 if(ThreadQueue
== Window
->MessageQueue
&&
641 ThreadQueue
->CaptureWindow
!= Window
->hSelf
)
643 /* only send WM_NCHITTEST messages if we're not capturing the window! */
644 *HitTest
= co_IntSendMessage(Window
->hSelf
, WM_NCHITTEST
, 0,
645 MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
));
647 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
649 PWINDOW_OBJECT DesktopWindow
;
650 HWND hDesktop
= IntGetDesktopWindow();
652 if((DesktopWindow
= UserGetWindowObject(hDesktop
)))
656 UserRefObjectCo(DesktopWindow
, &DesktopRef
);
658 co_WinPosWindowFromPoint(DesktopWindow
, Window
->MessageQueue
, &Msg
->pt
, &Wnd
);
663 /* post the message to the other window */
664 Msg
->hwnd
= Wnd
->hSelf
;
665 if(!(Wnd
->Status
& WINDOWSTATUS_DESTROYING
))
667 MsqPostMessage(Wnd
->MessageQueue
, Msg
, FALSE
,
668 Msg
->message
== WM_MOUSEMOVE
? QS_MOUSEMOVE
:
672 /* eat the message */
673 UserDereferenceObject(Wnd
);
674 UserDerefObjectCo(DesktopWindow
);
675 UserDerefObjectCo(Window
);
678 UserDereferenceObject(Wnd
);
681 UserDerefObjectCo(DesktopWindow
);
690 if(IS_BTN_MESSAGE(Msg
->message
, DOWN
))
692 /* generate double click messages, if necessary */
693 if ((((*HitTest
) != HTCLIENT
) ||
694 (Window
->Wnd
->Class
->Style
& CS_DBLCLKS
)) &&
695 MsqIsDblClk(Msg
, Remove
))
697 Msg
->message
+= WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
;
701 if(Msg
->message
!= WM_MOUSEWHEEL
)
704 if ((*HitTest
) != HTCLIENT
)
706 Msg
->message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
707 if((Msg
->message
== WM_NCRBUTTONUP
) &&
708 (((*HitTest
) == HTCAPTION
) || ((*HitTest
) == HTSYSMENU
)))
710 Msg
->message
= WM_CONTEXTMENU
;
711 Msg
->wParam
= (WPARAM
)Window
->hSelf
;
715 Msg
->wParam
= *HitTest
;
717 Msg
->lParam
= MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
);
719 else if(ThreadQueue
->MoveSize
== NULL
&&
720 ThreadQueue
->MenuOwner
== NULL
)
722 /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
723 Msg
->lParam
= MAKELONG(
724 Msg
->pt
.x
- (WORD
)Window
->Wnd
->ClientRect
.left
,
725 Msg
->pt
.y
- (WORD
)Window
->Wnd
->ClientRect
.top
);
729 UserDerefObjectCo(Window
);
735 * Internal version of PeekMessage() doing all the work
738 co_IntPeekMessage(PUSER_MESSAGE Msg
,
745 LARGE_INTEGER LargeTickCount
;
746 PUSER_MESSAGE_QUEUE ThreadQueue
;
747 PUSER_MESSAGE Message
;
748 BOOL Present
, RemoveMessages
;
749 USER_REFERENCE_ENTRY Ref
;
751 MOUSEHOOKSTRUCT MHook
;
753 /* The queues and order in which they are checked are documented in the MSDN
754 article on GetMessage() */
756 pti
= PsGetCurrentThreadWin32Thread();
757 ThreadQueue
= pti
->MessageQueue
;
759 /* Inspect RemoveMsg flags */
760 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
761 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
767 KeQueryTickCount(&LargeTickCount
);
768 ThreadQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
770 /* Dispatch sent messages here. */
771 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
774 /* Now look for a quit message. */
776 if (ThreadQueue
->QuitPosted
)
778 /* According to the PSDK, WM_QUIT messages are always returned, regardless
779 of the filter specified */
780 Msg
->Msg
.hwnd
= NULL
;
781 Msg
->Msg
.message
= WM_QUIT
;
782 Msg
->Msg
.wParam
= ThreadQueue
->QuitExitCode
;
784 Msg
->FreeLParam
= FALSE
;
787 ThreadQueue
->QuitPosted
= FALSE
;
792 /* Now check for normal messages. */
793 Present
= co_MsqFindMessage(ThreadQueue
,
802 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
805 MsqDestroyMessage(Message
);
810 /* Check for hardware events. */
811 Present
= co_MsqFindMessage(ThreadQueue
,
820 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
823 MsqDestroyMessage(Message
);
828 /* Check for sent messages again. */
829 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
832 /* Check for paint messages. */
833 if (IntGetPaintMessage(hWnd
, MsgFilterMin
, MsgFilterMax
, pti
, &Msg
->Msg
, RemoveMessages
))
835 Msg
->FreeLParam
= FALSE
;
839 /* Check for WM_(SYS)TIMER messages */
840 Present
= MsqGetTimerMessage(ThreadQueue
, hWnd
, 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();
985 if (hWnd
&& hWnd
!= INVALID_HANDLE_VALUE
)
987 if (!(Window
= UserGetWindowObject(hWnd
)))
993 if (MsgFilterMax
< MsgFilterMin
)
999 Present
= co_IntPeekMessage(&Msg
, hWnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
);
1004 /* See if this message type is present in the table */
1005 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
1006 if (NULL
== MsgMemoryEntry
)
1008 /* Not present, no copying needed */
1009 Info
.LParamSize
= 0;
1013 /* Determine required size */
1014 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
1016 /* Allocate required amount of user-mode memory */
1017 Info
.LParamSize
= Size
;
1019 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
1020 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
1021 if (! NT_SUCCESS(Status
))
1023 SetLastNtError(Status
);
1026 /* Transfer lParam data to user-mode mem */
1027 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
1028 if (! NT_SUCCESS(Status
))
1030 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
1031 &Info
.LParamSize
, MEM_RELEASE
);
1032 SetLastNtError(Status
);
1035 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
1037 if (RemoveMsg
&& Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
1039 ExFreePool((void *) Msg
.Msg
.lParam
);
1041 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
1042 if (! NT_SUCCESS(Status
))
1044 SetLastNtError(Status
);
1052 DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_
);
1057 static BOOL FASTCALL
1058 co_IntWaitMessage(HWND Wnd
,
1063 PUSER_MESSAGE_QUEUE ThreadQueue
;
1067 pti
= PsGetCurrentThreadWin32Thread();
1068 ThreadQueue
= pti
->MessageQueue
;
1072 if (co_IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_NOREMOVE
))
1077 /* Nothing found. Wait for new messages. */
1078 Status
= co_MsqWaitForNewMessages(ThreadQueue
, Wnd
, MsgFilterMin
, MsgFilterMax
);
1080 while ((STATUS_WAIT_0
<= Status
&& Status
<= STATUS_WAIT_63
) || STATUS_TIMEOUT
== Status
);
1082 SetLastNtError(Status
);
1088 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
1093 * FUNCTION: Get a message from the calling thread's message queue.
1095 * UnsafeMsg - Pointer to the structure which receives the returned message.
1096 * Wnd - Window whose messages are to be retrieved.
1097 * MsgFilterMin - Integer value of the lowest message value to be
1099 * MsgFilterMax - Integer value of the highest message value to be
1104 NTUSERGETMESSAGEINFO Info
;
1106 /* FIXME: if initialization is removed, gcc complains that this may be used before initialization. Please review */
1107 PWINDOW_OBJECT Window
= NULL
;
1108 PMSGMEMORY MsgMemoryEntry
;
1112 DECLARE_RETURN(BOOL
);
1113 // USER_REFERENCE_ENTRY Ref;
1115 DPRINT("Enter NtUserGetMessage\n");
1116 UserEnterExclusive();
1118 /* Validate input */
1119 if (hWnd
&& !(Window
= UserGetWindowObject(hWnd
)))
1124 // if (Window) UserRefObjectCo(Window, &Ref);
1126 if (MsgFilterMax
< MsgFilterMin
)
1134 GotMessage
= co_IntPeekMessage(&Msg
, hWnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
);
1138 /* See if this message type is present in the table */
1139 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
1140 if (NULL
== MsgMemoryEntry
)
1142 /* Not present, no copying needed */
1143 Info
.LParamSize
= 0;
1147 /* Determine required size */
1148 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
1150 /* Allocate required amount of user-mode memory */
1151 Info
.LParamSize
= Size
;
1153 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
1154 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
1156 if (! NT_SUCCESS(Status
))
1158 SetLastNtError(Status
);
1161 /* Transfer lParam data to user-mode mem */
1162 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
1163 if (! NT_SUCCESS(Status
))
1165 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
1166 &Info
.LParamSize
, MEM_DECOMMIT
);
1167 SetLastNtError(Status
);
1170 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
1172 if (Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
1174 ExFreePool((void *) Msg
.Msg
.lParam
);
1176 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
1177 if (! NT_SUCCESS(Status
))
1179 SetLastNtError(Status
);
1183 else if (! co_IntWaitMessage(hWnd
, MsgFilterMin
, MsgFilterMax
))
1188 while (! GotMessage
);
1190 RETURN( WM_QUIT
!= Info
.Msg
.message
);
1193 // if (Window) UserDerefObjectCo(Window);
1195 DPRINT("Leave NtUserGetMessage\n");
1201 static NTSTATUS FASTCALL
1202 CopyMsgToKernelMem(MSG
*KernelModeMsg
, MSG
*UserModeMsg
, PMSGMEMORY MsgMemoryEntry
)
1209 *KernelModeMsg
= *UserModeMsg
;
1211 /* See if this message type is present in the table */
1212 if (NULL
== MsgMemoryEntry
)
1214 /* Not present, no copying needed */
1215 return STATUS_SUCCESS
;
1218 /* Determine required size */
1219 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1223 /* Allocate kernel mem */
1224 KernelMem
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
1225 if (NULL
== KernelMem
)
1227 DPRINT1("Not enough memory to copy message to kernel mem\n");
1228 return STATUS_NO_MEMORY
;
1230 KernelModeMsg
->lParam
= (LPARAM
) KernelMem
;
1232 /* Copy data if required */
1233 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_READ
))
1235 Status
= MmCopyFromCaller(KernelMem
, (PVOID
) UserModeMsg
->lParam
, Size
);
1236 if (! NT_SUCCESS(Status
))
1238 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
1239 ExFreePoolWithTag(KernelMem
, TAG_MSG
);
1245 /* Make sure we don't pass any secrets to usermode */
1246 RtlZeroMemory(KernelMem
, Size
);
1251 KernelModeMsg
->lParam
= 0;
1254 return STATUS_SUCCESS
;
1257 static NTSTATUS FASTCALL
1258 CopyMsgToUserMem(MSG
*UserModeMsg
, MSG
*KernelModeMsg
)
1261 PMSGMEMORY MsgMemoryEntry
;
1264 /* See if this message type is present in the table */
1265 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
1266 if (NULL
== MsgMemoryEntry
)
1268 /* Not present, no copying needed */
1269 return STATUS_SUCCESS
;
1272 /* Determine required size */
1273 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1277 /* Copy data if required */
1278 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_WRITE
))
1280 Status
= MmCopyToCaller((PVOID
) UserModeMsg
->lParam
, (PVOID
) KernelModeMsg
->lParam
, Size
);
1281 if (! NT_SUCCESS(Status
))
1283 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1284 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1289 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1292 return STATUS_SUCCESS
;
1296 UserPostMessage(HWND Wnd
,
1302 MSG UserModeMsg
, KernelModeMsg
;
1303 LARGE_INTEGER LargeTickCount
;
1305 PMSGMEMORY MsgMemoryEntry
;
1307 pti
= PsGetCurrentThreadWin32Thread();
1310 MsqPostQuitMessage(pti
->MessageQueue
, wParam
);
1312 else if (Wnd
== HWND_BROADCAST
)
1315 PWINDOW_OBJECT DesktopWindow
;
1318 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1319 List
= IntWinListChildren(DesktopWindow
);
1323 for (i
= 0; List
[i
]; i
++)
1324 UserPostMessage(List
[i
], Msg
, wParam
, lParam
);
1330 PWINDOW_OBJECT Window
;
1332 Window
= UserGetWindowObject(Wnd
);
1337 if(Window
->Status
& WINDOWSTATUS_DESTROYING
)
1339 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd
);
1340 /* FIXME - last error code? */
1344 UserModeMsg
.hwnd
= Wnd
;
1345 UserModeMsg
.message
= Msg
;
1346 UserModeMsg
.wParam
= wParam
;
1347 UserModeMsg
.lParam
= lParam
;
1348 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1349 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1350 if (! NT_SUCCESS(Status
))
1352 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1355 IntGetCursorLocation(pti
->Desktop
->WindowStation
,
1357 KeQueryTickCount(&LargeTickCount
);
1358 KernelModeMsg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1359 MsqPostMessage(Window
->MessageQueue
, &KernelModeMsg
,
1360 NULL
!= MsgMemoryEntry
&& 0 != KernelModeMsg
.lParam
,
1369 NtUserPostMessage(HWND hWnd
,
1374 DECLARE_RETURN(BOOL
);
1376 DPRINT("Enter NtUserPostMessage\n");
1377 UserEnterExclusive();
1379 RETURN(UserPostMessage(hWnd
, Msg
, wParam
, lParam
));
1382 DPRINT("Leave NtUserPostMessage, ret=%i\n",_ret_
);
1390 NtUserPostThreadMessage(DWORD idThread
,
1395 MSG UserModeMsg
, KernelModeMsg
;
1397 PTHREADINFO pThread
;
1399 PMSGMEMORY MsgMemoryEntry
;
1400 DECLARE_RETURN(BOOL
);
1402 DPRINT("Enter NtUserPostThreadMessage\n");
1403 UserEnterExclusive();
1405 Status
= PsLookupThreadByThreadId((HANDLE
)idThread
,&peThread
);
1407 if( Status
== STATUS_SUCCESS
)
1409 pThread
= (PTHREADINFO
)peThread
->Tcb
.Win32Thread
;
1410 if( !pThread
|| !pThread
->MessageQueue
)
1412 ObDereferenceObject( peThread
);
1416 UserModeMsg
.hwnd
= NULL
;
1417 UserModeMsg
.message
= Msg
;
1418 UserModeMsg
.wParam
= wParam
;
1419 UserModeMsg
.lParam
= lParam
;
1420 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1421 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1422 if (! NT_SUCCESS(Status
))
1424 ObDereferenceObject( peThread
);
1425 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1428 MsqPostMessage(pThread
->MessageQueue
, &KernelModeMsg
,
1429 NULL
!= MsgMemoryEntry
&& 0 != KernelModeMsg
.lParam
,
1431 ObDereferenceObject( peThread
);
1436 SetLastNtError( Status
);
1441 DPRINT("Leave NtUserPostThreadMessage, ret=%i\n",_ret_
);
1447 NtUserQuerySendMessage(DWORD Unknown0
)
1455 co_IntSendMessage(HWND hWnd
,
1460 ULONG_PTR Result
= 0;
1461 if(co_IntSendMessageTimeout(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1463 return (LRESULT
)Result
;
1470 co_IntSendMessageTimeoutSingle(HWND hWnd
,
1480 PWINDOW_OBJECT Window
= NULL
;
1481 PMSGMEMORY MsgMemoryEntry
;
1482 INT lParamBufferSize
;
1483 LPARAM lParamPacked
;
1484 PTHREADINFO Win32Thread
;
1485 DECLARE_RETURN(LRESULT
);
1486 USER_REFERENCE_ENTRY Ref
;
1488 if (!(Window
= UserGetWindowObject(hWnd
)))
1493 UserRefObjectCo(Window
, &Ref
);
1495 Win32Thread
= PsGetCurrentThreadWin32Thread();
1497 IntCallWndProc( Window
, hWnd
, Msg
, wParam
, lParam
);
1499 if (NULL
!= Win32Thread
&&
1500 Window
->MessageQueue
== Win32Thread
->MessageQueue
)
1502 if (Win32Thread
->IsExiting
)
1504 /* Never send messages to exiting threads */
1508 /* See if this message type is present in the table */
1509 MsgMemoryEntry
= FindMsgMemory(Msg
);
1510 if (NULL
== MsgMemoryEntry
)
1512 lParamBufferSize
= -1;
1516 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
1519 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
)))
1521 DPRINT1("Failed to pack message parameters\n");
1525 Result
= (ULONG_PTR
)co_IntCallWindowProc(Window
->Wnd
->WndProc
, !Window
->Wnd
->Unicode
, hWnd
, Msg
, wParam
,
1526 lParamPacked
,lParamBufferSize
);
1533 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, (LRESULT
*)uResult
);
1535 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
)))
1537 DPRINT1("Failed to unpack message parameters\n");
1544 if (uFlags
& SMTO_ABORTIFHUNG
&& MsqIsHung(Window
->MessageQueue
))
1546 /* FIXME - Set a LastError? */
1550 if (Window
->Status
& WINDOWSTATUS_DESTROYING
)
1552 /* FIXME - last error? */
1553 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd
);
1559 Status
= co_MsqSendMessage( Window
->MessageQueue
,
1565 (uFlags
& SMTO_BLOCK
),
1569 while ((STATUS_TIMEOUT
== Status
) &&
1570 (uFlags
& SMTO_NOTIMEOUTIFNOTHUNG
) &&
1571 !MsqIsHung(Window
->MessageQueue
));
1573 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, (LRESULT
*)uResult
);
1575 if (STATUS_TIMEOUT
== Status
)
1579 Microsoft Windows 2000: If GetLastError returns zero, then the function
1581 XP+ : If the function fails or times out, the return value is zero.
1582 To get extended error information, call GetLastError. If GetLastError
1583 returns ERROR_TIMEOUT, then the function timed out.
1585 SetLastWin32Error(ERROR_TIMEOUT
);
1588 else if (! NT_SUCCESS(Status
))
1590 SetLastNtError(Status
);
1597 if (Window
) UserDerefObjectCo(Window
);
1602 co_IntSendMessageTimeout(HWND hWnd
,
1610 PWINDOW_OBJECT DesktopWindow
;
1614 if (HWND_BROADCAST
!= hWnd
)
1616 return co_IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1619 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1620 if (NULL
== DesktopWindow
)
1622 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1626 Children
= IntWinListChildren(DesktopWindow
);
1627 if (NULL
== Children
)
1632 for (Child
= Children
; NULL
!= *Child
; Child
++)
1634 co_IntSendMessageTimeoutSingle(*Child
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1637 ExFreePool(Children
);
1639 return (LRESULT
) TRUE
;
1643 /* This function posts a message if the destination's message queue belongs to
1644 another thread, otherwise it sends the message. It does not support broadcast
1647 co_IntPostOrSendMessage(HWND hWnd
,
1654 PWINDOW_OBJECT Window
;
1656 if(hWnd
== HWND_BROADCAST
)
1661 if(!(Window
= UserGetWindowObject(hWnd
)))
1666 pti
= PsGetCurrentThreadWin32Thread();
1667 if(Window
->MessageQueue
!= pti
->MessageQueue
)
1669 Result
= UserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1673 if(!co_IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
)) {
1678 return (LRESULT
)Result
;
1682 co_IntDoSendMessage(HWND hWnd
,
1687 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1690 LRESULT Result
= TRUE
;
1692 PWINDOW_OBJECT Window
= NULL
;
1693 NTUSERSENDMESSAGEINFO Info
;
1696 PMSGMEMORY MsgMemoryEntry
;
1698 RtlZeroMemory(&Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1700 /* FIXME: Call hooks. */
1701 if (HWND_BROADCAST
!= hWnd
)
1703 Window
= UserGetWindowObject(hWnd
);
1706 /* Tell usermode to not touch this one */
1707 Info
.HandledByKernel
= TRUE
;
1708 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1715 /* FIXME: Check for an exiting window. */
1717 /* See if the current thread can handle the message */
1718 pti
= PsGetCurrentThreadWin32Thread();
1719 if (HWND_BROADCAST
!= hWnd
&& NULL
!= pti
&&
1720 Window
->MessageQueue
== pti
->MessageQueue
)
1722 /* Gather the information usermode needs to call the window proc directly */
1723 Info
.HandledByKernel
= FALSE
;
1725 Status
= MmCopyFromCaller(&(Info
.Ansi
), &(UnsafeInfo
->Ansi
),
1727 if (! NT_SUCCESS(Status
))
1729 Info
.Ansi
= ! Window
->Wnd
->Unicode
;
1732 IntCallWndProc( Window
, hWnd
, Msg
, wParam
, lParam
);
1734 if (Window
->Wnd
->IsSystem
)
1736 Info
.Proc
= (!Info
.Ansi
? Window
->Wnd
->WndProc
: Window
->Wnd
->WndProcExtra
);
1740 Info
.Ansi
= !Window
->Wnd
->Unicode
;
1741 Info
.Proc
= Window
->Wnd
->WndProc
;
1744 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, &Result
);
1749 /* Must be handled by other thread */
1750 // if (HWND_BROADCAST != hWnd)
1752 // UserDereferenceObject(Window);
1754 Info
.HandledByKernel
= TRUE
;
1755 UserModeMsg
.hwnd
= hWnd
;
1756 UserModeMsg
.message
= Msg
;
1757 UserModeMsg
.wParam
= wParam
;
1758 UserModeMsg
.lParam
= lParam
;
1759 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1760 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1761 if (! NT_SUCCESS(Status
))
1763 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1764 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1765 return (dsm
? 0 : -1);
1769 Result
= co_IntSendMessage(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1770 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
);
1774 Result
= co_IntSendMessageTimeout(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1775 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
,
1776 dsm
->uFlags
, dsm
->uTimeout
, &dsm
->Result
);
1778 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
1779 if (! NT_SUCCESS(Status
))
1781 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1782 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1783 return(dsm
? 0 : -1);
1787 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1788 if (! NT_SUCCESS(Status
))
1790 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1793 return (LRESULT
)Result
;
1797 NtUserSendMessageTimeout(HWND hWnd
,
1804 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1808 DECLARE_RETURN(BOOL
);
1810 DPRINT("Enter NtUserSendMessageTimeout\n");
1811 UserEnterExclusive();
1813 dsm
.uFlags
= uFlags
;
1814 dsm
.uTimeout
= uTimeout
;
1815 Result
= co_IntDoSendMessage(hWnd
, Msg
, wParam
, lParam
, &dsm
, UnsafeInfo
);
1816 if(uResult
!= NULL
&& Result
!= 0)
1820 Status
= MmCopyToCaller(uResult
, &dsm
.Result
, sizeof(ULONG_PTR
));
1821 if(!NT_SUCCESS(Status
))
1823 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1830 DPRINT("Leave NtUserSendMessageTimeout, ret=%i\n",_ret_
);
1836 NtUserSendMessage(HWND Wnd
,
1840 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1842 DECLARE_RETURN(BOOL
);
1844 DPRINT("Enter NtUserSendMessage\n");
1845 UserEnterExclusive();
1847 RETURN(co_IntDoSendMessage(Wnd
, Msg
, wParam
, lParam
, NULL
, UnsafeInfo
));
1850 DPRINT("Leave NtUserSendMessage, ret=%i\n",_ret_
);
1857 UserSendNotifyMessage(HWND hWnd
,
1863 // Basicly the same as IntPostOrSendMessage
1864 if (hWnd
== HWND_BROADCAST
) //Handle Broadcast
1867 PWINDOW_OBJECT DesktopWindow
;
1870 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1871 List
= IntWinListChildren(DesktopWindow
);
1875 for (i
= 0; List
[i
]; i
++)
1877 UserSendNotifyMessage(List
[i
], Msg
, wParam
, lParam
);
1886 PWINDOW_OBJECT Window
;
1890 PMSGMEMORY MsgMemoryEntry
;
1892 if(!(Window
= UserGetWindowObject(hWnd
))) return FALSE
;
1894 pti
= PsGetCurrentThreadWin32Thread();
1895 if(Window
->MessageQueue
!= pti
->MessageQueue
)
1896 { // Send message w/o waiting for it.
1897 Result
= UserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1900 { // Handle message and callback.
1901 UserModeMsg
.hwnd
= hWnd
;
1902 UserModeMsg
.message
= Msg
;
1903 UserModeMsg
.wParam
= wParam
;
1904 UserModeMsg
.lParam
= lParam
;
1905 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1906 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1907 if (! NT_SUCCESS(Status
))
1909 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1912 Result
= co_IntSendMessageTimeoutSingle(
1913 KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1914 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
,
1915 SMTO_NORMAL
, 0, &PResult
);
1917 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
1918 if (! NT_SUCCESS(Status
))
1920 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1930 NtUserSendNotifyMessage(HWND hWnd
,
1935 DECLARE_RETURN(BOOL
);
1937 DPRINT("EnterNtUserSendNotifyMessage\n");
1938 UserEnterExclusive();
1940 RETURN(UserSendNotifyMessage(hWnd
, Msg
, wParam
, lParam
));
1943 DPRINT("Leave NtUserSendNotifyMessage, ret=%i\n",_ret_
);
1951 NtUserWaitMessage(VOID
)
1953 DECLARE_RETURN(BOOL
);
1955 DPRINT("EnterNtUserWaitMessage\n");
1956 UserEnterExclusive();
1958 RETURN(co_IntWaitMessage(NULL
, 0, 0));
1961 DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_
);
1967 IntGetQueueStatus(BOOL ClearChanges
)
1970 PUSER_MESSAGE_QUEUE Queue
;
1972 DECLARE_RETURN(DWORD
);
1974 DPRINT("Enter IntGetQueueStatus\n");
1976 pti
= PsGetCurrentThreadWin32Thread();
1977 Queue
= pti
->MessageQueue
;
1979 Result
= MAKELONG(Queue
->QueueBits
, Queue
->ChangedBits
);
1982 Queue
->ChangedBits
= 0;
1988 DPRINT("Leave IntGetQueueStatus, ret=%i\n",_ret_
);
1993 IntInitMessagePumpHook()
1995 if (((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->ThreadInfo
)
1997 ((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->ThreadInfo
->ClientThreadInfo
.dwcPumpHook
++;
2004 IntUninitMessagePumpHook()
2006 if (((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->ThreadInfo
)
2008 if (((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->ThreadInfo
->ClientThreadInfo
.dwcPumpHook
<= 0)
2012 ((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->ThreadInfo
->ClientThreadInfo
.dwcPumpHook
--;
2025 ULONG_PTR ResultInfo
,
2026 DWORD dwType
, // fnID?
2029 LRESULT lResult
= 0;
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
)))
2042 case FNID_DEFWINDOWPROC
:
2043 UserRefObjectCo(Window
, &Ref
);
2044 lResult
= IntDefWindowProc(Window
, Msg
, wParam
, lParam
, Ansi
);
2045 UserDerefObjectCo(Window
);
2047 case FNID_BROADCASTSYSTEMMESSAGE
:
2049 PBROADCASTPARM parm
;
2050 BOOL BadChk
= FALSE
;
2051 DWORD_PTR RetVal
= 0;
2058 ProbeForWrite((PVOID
)ResultInfo
,
2059 sizeof(BROADCASTPARM
),
2061 parm
= (PBROADCASTPARM
)ResultInfo
;
2063 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2073 if ( parm
->recipients
& BSM_ALLDESKTOPS
||
2074 parm
->recipients
== BSM_ALLCOMPONENTS
)
2077 else if (parm
->recipients
& BSM_APPLICATIONS
)
2079 if (parm
->flags
& BSF_QUERY
)
2081 if (parm
->flags
& BSF_FORCEIFHUNG
|| parm
->flags
& BSF_NOHANG
)
2083 co_IntSendMessageTimeout( HWND_BROADCAST
,
2091 else if (parm
->flags
& BSF_NOTIMEOUTIFNOTHUNG
)
2093 co_IntSendMessageTimeout( HWND_BROADCAST
,
2097 SMTO_NOTIMEOUTIFNOTHUNG
,
2103 co_IntSendMessageTimeout( HWND_BROADCAST
,
2112 else if (parm
->flags
& BSF_POSTMESSAGE
)
2114 lResult
= UserPostMessage(HWND_BROADCAST
, Msg
, wParam
, lParam
);
2116 else if ( parm
->flags
& BSF_SENDNOTIFYMESSAGE
)
2118 lResult
= UserSendNotifyMessage(HWND_BROADCAST
, Msg
, wParam
, lParam
);
2123 case FNID_SENDMESSAGECALLBACK
:
2125 // CallNextHook bypass.
2126 case FNID_CALLWNDPROC
:
2127 case FNID_CALLWNDPROCRET
:
2129 PCLIENTINFO ClientInfo
= GetWin32ClientInfo();
2130 PHOOK NextObj
, Hook
= ClientInfo
->phkCurrent
;
2132 if (!ClientInfo
|| !Hook
) break;
2134 UserReferenceObject(Hook
);
2136 if (Hook
->Thread
&& (Hook
->Thread
!= PsGetCurrentThread()))
2138 UserDereferenceObject(Hook
);
2142 NextObj
= IntGetNextHook(Hook
);
2143 ClientInfo
->phkCurrent
= NextObj
;
2145 if ( Hook
->HookId
== WH_CALLWNDPROC
)
2150 CWP
.wParam
= wParam
;
2151 CWP
.lParam
= lParam
;
2152 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook
, NextObj
);
2154 lResult
= co_IntCallHookProc( Hook
->HookId
,
2156 ((ClientInfo
->CI_flags
& CI_CURTHPRHOOK
) ? 1 : 0),
2167 CWPR
.wParam
= wParam
;
2168 CWPR
.lParam
= lParam
;
2169 CWPR
.lResult
= ClientInfo
->dwHookData
;
2171 lResult
= co_IntCallHookProc( Hook
->HookId
,
2173 ((ClientInfo
->CI_flags
& CI_CURTHPRHOOK
) ? 1 : 0),
2179 UserDereferenceObject(Hook
);
2180 lResult
= (LRESULT
) NextObj
;
2188 #define INFINITE 0xFFFFFFFF
2189 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2193 NtUserWaitForInputIdle(
2195 IN DWORD dwMilliseconds
,
2199 PW32PROCESS W32Process
;
2202 LARGE_INTEGER Timeout
;
2203 ULONGLONG StartTime
, Run
, Elapsed
= 0;
2205 UserEnterExclusive();
2207 Status
= ObReferenceObjectByHandle(hProcess
,
2208 PROCESS_QUERY_INFORMATION
,
2214 if (!NT_SUCCESS(Status
))
2217 SetLastNtError(Status
);
2221 W32Process
= (PW32PROCESS
)Process
->Win32Process
;
2224 ObDereferenceObject(Process
);
2226 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2230 EngCreateEvent((PEVENT
*)&W32Process
->InputIdleEvent
);
2232 Handles
[0] = Process
;
2233 Handles
[1] = W32Process
->InputIdleEvent
;
2237 ObDereferenceObject(Process
);
2239 return STATUS_SUCCESS
; /* no event to wait on */
2242 StartTime
= EngGetTickCount();
2244 Run
= dwMilliseconds
;
2246 DPRINT("WFII: waiting for %p\n", Handles
[1] );
2249 Timeout
.QuadPart
= Run
- Elapsed
;
2251 Status
= KeWaitForMultipleObjects( 2,
2257 dwMilliseconds
== INFINITE
? NULL
: &Timeout
,
2259 UserEnterExclusive();
2261 if (!NT_SUCCESS(Status
))
2263 SetLastNtError(Status
);
2264 Status
= WAIT_FAILED
;
2271 Status
= WAIT_FAILED
;
2277 co_IntPeekMessage( &Msg
, 0, 0, 0, PM_REMOVE
| PM_QS_SENDMESSAGE
);
2281 case STATUS_USER_APC
:
2282 case STATUS_ALERTED
:
2283 case STATUS_TIMEOUT
:
2284 DPRINT1("WFII: timeout\n");
2285 Status
= STATUS_TIMEOUT
;
2289 DPRINT1("WFII: finished\n");
2290 Status
= STATUS_SUCCESS
;
2294 if (dwMilliseconds
!= INFINITE
)
2296 Elapsed
= EngGetTickCount() - StartTime
;
2299 Status
= STATUS_TIMEOUT
;
2306 if (W32Process
->InputIdleEvent
)
2308 EngDeleteEvent((PEVENT
)W32Process
->InputIdleEvent
);
2309 W32Process
->InputIdleEvent
= NULL
;
2311 ObDereferenceObject(Process
);