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.
19 /* $Id: message.c,v 1.63 2004/05/10 17:07:18 weiden Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
24 * FILE: subsys/win32k/ntuser/message.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH Created
30 /* 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
70 } MSGMEMORY
, *PMSGMEMORY
;
72 static MSGMEMORY MsgMemory
[] =
74 { WM_CREATE
, sizeof(CREATESTRUCTW
), MMS_FLAG_READWRITE
},
75 { WM_DDE_ACK
, sizeof(KMDDELPARAM
), MMS_FLAG_READ
},
76 { WM_DDE_EXECUTE
, MMS_SIZE_WPARAM
, MMS_FLAG_READ
},
77 { WM_GETMINMAXINFO
, sizeof(MINMAXINFO
), MMS_FLAG_READWRITE
},
78 { WM_GETTEXT
, MMS_SIZE_WPARAMWCHAR
, MMS_FLAG_WRITE
},
79 { WM_NCCALCSIZE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
80 { WM_NCCREATE
, sizeof(CREATESTRUCTW
), MMS_FLAG_READWRITE
},
81 { WM_SETTEXT
, MMS_SIZE_LPARAMSZ
, MMS_FLAG_READ
},
82 { WM_STYLECHANGED
, sizeof(STYLESTRUCT
), MMS_FLAG_READ
},
83 { WM_STYLECHANGING
, sizeof(STYLESTRUCT
), MMS_FLAG_READWRITE
},
84 { WM_WINDOWPOSCHANGED
, sizeof(WINDOWPOS
), MMS_FLAG_READ
},
85 { WM_WINDOWPOSCHANGING
, sizeof(WINDOWPOS
), MMS_FLAG_READWRITE
},
88 static PMSGMEMORY FASTCALL
89 FindMsgMemory(UINT Msg
)
91 PMSGMEMORY MsgMemoryEntry
;
93 /* See if this message type is present in the table */
94 for (MsgMemoryEntry
= MsgMemory
;
95 MsgMemoryEntry
< MsgMemory
+ sizeof(MsgMemory
) / sizeof(MSGMEMORY
);
98 if (Msg
== MsgMemoryEntry
->Message
)
100 return MsgMemoryEntry
;
108 MsgMemorySize(PMSGMEMORY MsgMemoryEntry
, WPARAM wParam
, LPARAM lParam
)
110 if (MMS_SIZE_WPARAM
== MsgMemoryEntry
->Size
)
112 return (UINT
) wParam
;
114 else if (MMS_SIZE_WPARAMWCHAR
== MsgMemoryEntry
->Size
)
116 return (UINT
) (wParam
* sizeof(WCHAR
));
118 else if (MMS_SIZE_LPARAMSZ
== MsgMemoryEntry
->Size
)
120 return (UINT
) ((wcslen((PWSTR
) lParam
) + 1) * sizeof(WCHAR
));
122 else if (MMS_SIZE_SPECIAL
== MsgMemoryEntry
->Size
)
124 switch(MsgMemoryEntry
->Message
)
127 return wParam
? sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
) : sizeof(RECT
);
137 return MsgMemoryEntry
->Size
;
141 static FASTCALL NTSTATUS
142 PackParam(LPARAM
*lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
144 NCCALCSIZE_PARAMS
*UnpackedParams
;
145 NCCALCSIZE_PARAMS
*PackedParams
;
147 *lParamPacked
= lParam
;
148 if (WM_NCCALCSIZE
== Msg
&& wParam
)
150 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
151 if (UnpackedParams
->lppos
!= (PWINDOWPOS
) (UnpackedParams
+ 1))
153 PackedParams
= ExAllocatePoolWithTag(PagedPool
,
154 sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
),
156 if (NULL
== PackedParams
)
158 DPRINT1("Not enough memory to pack lParam\n");
159 return STATUS_NO_MEMORY
;
161 RtlCopyMemory(PackedParams
, UnpackedParams
, sizeof(NCCALCSIZE_PARAMS
));
162 PackedParams
->lppos
= (PWINDOWPOS
) (PackedParams
+ 1);
163 RtlCopyMemory(PackedParams
->lppos
, UnpackedParams
->lppos
, sizeof(WINDOWPOS
));
164 *lParamPacked
= (LPARAM
) PackedParams
;
168 return STATUS_SUCCESS
;
171 static FASTCALL NTSTATUS
172 UnpackParam(LPARAM lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
174 NCCALCSIZE_PARAMS
*UnpackedParams
;
175 NCCALCSIZE_PARAMS
*PackedParams
;
176 PWINDOWPOS UnpackedWindowPos
;
178 if (lParamPacked
== lParam
)
180 return STATUS_SUCCESS
;
183 if (WM_NCCALCSIZE
== Msg
&& wParam
)
185 PackedParams
= (NCCALCSIZE_PARAMS
*) lParamPacked
;
186 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
187 UnpackedWindowPos
= UnpackedParams
->lppos
;
188 RtlCopyMemory(UnpackedParams
, PackedParams
, sizeof(NCCALCSIZE_PARAMS
));
189 UnpackedParams
->lppos
= UnpackedWindowPos
;
190 RtlCopyMemory(UnpackedWindowPos
, PackedParams
+ 1, sizeof(WINDOWPOS
));
191 ExFreePool((PVOID
) lParamPacked
);
193 return STATUS_SUCCESS
;
198 return STATUS_INVALID_PARAMETER
;
203 NtUserDispatchMessage(PNTUSERDISPATCHMESSAGEINFO UnsafeMsgInfo
)
206 NTUSERDISPATCHMESSAGEINFO MsgInfo
;
207 PWINDOW_OBJECT WindowObject
;
210 Status
= MmCopyFromCaller(&MsgInfo
, UnsafeMsgInfo
, sizeof(NTUSERDISPATCHMESSAGEINFO
));
211 if (! NT_SUCCESS(Status
))
213 SetLastNtError(Status
);
217 /* Process timer messages. */
218 if (WM_TIMER
== MsgInfo
.Msg
.message
&& 0 != MsgInfo
.Msg
.lParam
)
220 LARGE_INTEGER LargeTickCount
;
221 /* FIXME: Call hooks. */
223 /* FIXME: Check for continuing validity of timer. */
225 MsgInfo
.HandledByKernel
= FALSE
;
226 KeQueryTickCount(&LargeTickCount
);
227 MsgInfo
.Proc
= (WNDPROC
) MsgInfo
.Msg
.lParam
;
228 MsgInfo
.Msg
.lParam
= (LPARAM
)LargeTickCount
.u
.LowPart
;
230 else if (NULL
== MsgInfo
.Msg
.hwnd
)
232 MsgInfo
.HandledByKernel
= TRUE
;
237 /* Get the window object. */
238 WindowObject
= IntGetWindowObject(MsgInfo
.Msg
.hwnd
);
239 if (NULL
== WindowObject
)
241 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
242 MsgInfo
.HandledByKernel
= TRUE
;
247 if (WindowObject
->OwnerThread
!= PsGetCurrentThread())
249 IntReleaseWindowObject(WindowObject
);
250 DPRINT1("Window doesn't belong to the calling thread!\n");
251 MsgInfo
.HandledByKernel
= TRUE
;
256 /* FIXME: Call hook procedures. */
258 MsgInfo
.HandledByKernel
= FALSE
;
260 if (0xFFFF0000 != ((DWORD
) WindowObject
->WndProcW
& 0xFFFF0000))
262 if (0xFFFF0000 != ((DWORD
) WindowObject
->WndProcA
& 0xFFFF0000))
264 /* Both Unicode and Ansi winprocs are real, use whatever
266 MsgInfo
.Proc
= (MsgInfo
.Ansi
? WindowObject
->WndProcA
267 : WindowObject
->WndProcW
);
271 /* Real Unicode winproc */
272 MsgInfo
.Ansi
= FALSE
;
273 MsgInfo
.Proc
= WindowObject
->WndProcW
;
278 /* Must have real Ansi winproc */
280 MsgInfo
.Proc
= WindowObject
->WndProcA
;
283 IntReleaseWindowObject(WindowObject
);
286 Status
= MmCopyToCaller(UnsafeMsgInfo
, &MsgInfo
, sizeof(NTUSERDISPATCHMESSAGEINFO
));
287 if (! NT_SUCCESS(Status
))
289 SetLastNtError(Status
);
298 NtUserTranslateMessage(LPMSG lpMsg
,
304 Status
= MmCopyFromCaller(&SafeMsg
, lpMsg
, sizeof(MSG
));
305 if(!NT_SUCCESS(Status
))
307 SetLastNtError(Status
);
311 return IntTranslateKbdMessage(&SafeMsg
, dwhkl
);
316 IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
)
318 if(!Msg
->hwnd
|| ThreadQueue
->CaptureWindow
)
327 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
332 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
339 case WM_LBUTTONDBLCLK
:
340 case WM_MBUTTONDBLCLK
:
341 case WM_RBUTTONDBLCLK
:
342 case WM_XBUTTONDBLCLK
:
346 if(!IntGetWindowStationObject(InputWindowStation
))
350 wParam
= (WPARAM
)InputWindowStation
->SystemCursor
.ButtonsDown
;
351 ObDereferenceObject(InputWindowStation
);
353 IntSendMessage(Msg
->hwnd
, WM_MOUSEMOVE
, wParam
, Msg
->lParam
);
354 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
357 case WM_NCLBUTTONDOWN
:
358 case WM_NCMBUTTONDOWN
:
359 case WM_NCRBUTTONDOWN
:
360 case WM_NCXBUTTONDOWN
:
361 case WM_NCLBUTTONDBLCLK
:
362 case WM_NCMBUTTONDBLCLK
:
363 case WM_NCRBUTTONDBLCLK
:
364 case WM_NCXBUTTONDBLCLK
:
366 IntSendMessage(Msg
->hwnd
, WM_NCMOUSEMOVE
, (WPARAM
)Msg
->wParam
, Msg
->lParam
);
367 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
374 IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, PWINDOW_OBJECT MsgWindow
,
379 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
381 /* eat the message, search again! */
385 Result
= IntSendMessage(MsgWindow
->Self
, WM_MOUSEACTIVATE
, (WPARAM
)NtUserGetParent(MsgWindow
->Self
), (LPARAM
)MAKELONG(*HitTest
, Msg
->message
));
388 case MA_NOACTIVATEANDEAT
:
392 case MA_ACTIVATEANDEAT
:
393 IntMouseActivateWindow(MsgWindow
);
397 IntMouseActivateWindow(MsgWindow
);
405 IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, USHORT
*HitTest
, BOOL Remove
)
407 PWINDOW_OBJECT Window
;
409 if(!(Window
= IntGetWindowObject(Msg
->hwnd
)))
411 /* FIXME - change the mouse cursor to an arrow, maybe do this a better way */
412 IntLoadDefaultCursors(TRUE
);
413 /* let's just eat the message?! */
417 if(ThreadQueue
== Window
->MessageQueue
&&
418 ThreadQueue
->CaptureWindow
!= Window
->Self
)
420 /* only send WM_NCHITTEST messages if we're not capturing the window! */
421 *HitTest
= IntSendMessage(Window
->Self
, WM_NCHITTEST
, 0,
422 MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
));
424 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
426 PWINDOW_OBJECT DesktopWindow
;
427 HWND hDesktop
= IntGetDesktopWindow();
429 if((DesktopWindow
= IntGetWindowObject(hDesktop
)))
433 WinPosWindowFromPoint(DesktopWindow
, Window
->MessageQueue
, &Msg
->pt
, &Wnd
);
438 /* post the message to the other window */
439 Msg
->hwnd
= Wnd
->Self
;
440 MsqPostMessage(Wnd
->MessageQueue
, Msg
, FALSE
);
442 /* eat the message */
443 IntReleaseWindowObject(Wnd
);
444 IntReleaseWindowObject(Window
);
445 IntReleaseWindowObject(DesktopWindow
);
448 IntReleaseWindowObject(Wnd
);
451 IntReleaseWindowObject(DesktopWindow
);
460 if(IS_BTN_MESSAGE(Msg
->message
, DOWN
))
462 /* generate double click messages, if necessary */
463 if ((((*HitTest
) != HTCLIENT
) ||
464 (IntGetClassLong(Window
, GCL_STYLE
, FALSE
) & CS_DBLCLKS
)) &&
465 MsqIsDblClk(Msg
, Remove
))
467 Msg
->message
+= WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
;
471 if(Msg
->message
!= WM_MOUSEWHEEL
)
474 if ((*HitTest
) != HTCLIENT
)
476 Msg
->message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
477 if((Msg
->message
== WM_NCRBUTTONUP
) &&
478 (((*HitTest
) == HTCAPTION
) || ((*HitTest
) == HTSYSMENU
)))
480 Msg
->message
= WM_CONTEXTMENU
;
481 Msg
->wParam
= (WPARAM
)Window
->Self
;
485 Msg
->wParam
= *HitTest
;
487 Msg
->lParam
= MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
);
489 else if(ThreadQueue
->MoveSize
== NULL
&&
490 ThreadQueue
->MenuOwner
== NULL
)
492 Msg
->pt
.x
-= (WORD
)Window
->ClientRect
.left
;
493 Msg
->pt
.y
-= (WORD
)Window
->ClientRect
.top
;
494 Msg
->lParam
= MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
);
498 IntReleaseWindowObject(Window
);
504 * Internal version of PeekMessage() doing all the work
507 IntPeekMessage(PUSER_MESSAGE Msg
,
513 LARGE_INTEGER LargeTickCount
;
514 PUSER_MESSAGE_QUEUE ThreadQueue
;
515 PUSER_MESSAGE Message
;
516 BOOL Present
, RemoveMessages
;
518 /* The queues and order in which they are checked are documented in the MSDN
519 article on GetMessage() */
521 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
523 /* Inspect RemoveMsg flags */
524 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
525 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
531 KeQueryTickCount(&LargeTickCount
);
532 ThreadQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
534 /* Dispatch sent messages here. */
535 while (MsqDispatchOneSentMessage(ThreadQueue
));
537 /* Now look for a quit message. */
539 if (ThreadQueue
->QuitPosted
)
541 /* According to the PSDK, WM_QUIT messages are always returned, regardless
542 of the filter specified */
543 Msg
->Msg
.hwnd
= NULL
;
544 Msg
->Msg
.message
= WM_QUIT
;
545 Msg
->Msg
.wParam
= ThreadQueue
->QuitExitCode
;
547 Msg
->FreeLParam
= FALSE
;
550 ThreadQueue
->QuitPosted
= FALSE
;
555 /* Now check for normal messages. */
556 Present
= MsqFindMessage(ThreadQueue
,
565 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
568 MsqDestroyMessage(Message
);
573 /* Check for hardware events. */
574 Present
= MsqFindMessage(ThreadQueue
,
583 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
586 MsqDestroyMessage(Message
);
591 /* Check for sent messages again. */
592 while (MsqDispatchOneSentMessage(ThreadQueue
));
594 /* Check for paint messages. */
595 if (IntGetPaintMessage(Wnd
, MsgFilterMin
, MsgFilterMax
, PsGetWin32Thread(), &Msg
->Msg
, RemoveMessages
))
597 Msg
->FreeLParam
= FALSE
;
601 /* FIXME - get WM_(SYS)TIMER messages */
609 PWINDOW_OBJECT MsgWindow
= NULL
;;
611 if(Msg
->Msg
.hwnd
&& (MsgWindow
= IntGetWindowObject(Msg
->Msg
.hwnd
)) &&
612 Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
)
616 if(IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, TRUE
))
617 /* FIXME - check message filter again, if the message doesn't match anymore,
620 IntReleaseWindowObject(MsgWindow
);
621 /* eat the message, search again */
624 if(ThreadQueue
->CaptureWindow
== NULL
)
626 IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
627 if((Msg
->Msg
.message
!= WM_MOUSEMOVE
&& Msg
->Msg
.message
!= WM_NCMOUSEMOVE
) &&
628 IS_BTN_MESSAGE(Msg
->Msg
.message
, DOWN
) &&
629 IntActivateWindowMouse(ThreadQueue
, &Msg
->Msg
, MsgWindow
, &HitTest
))
631 IntReleaseWindowObject(MsgWindow
);
632 /* eat the message, search again */
639 IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
644 IntReleaseWindowObject(MsgWindow
);
651 if((Msg
->Msg
.hwnd
&& Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
) &&
652 IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, FALSE
))
653 /* FIXME - check message filter again, if the message doesn't match anymore,
656 /* eat the message, search again */
667 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
675 NTUSERGETMESSAGEINFO Info
;
676 PWINDOW_OBJECT Window
;
677 PMSGMEMORY MsgMemoryEntry
;
685 Window
= IntGetWindowObject(Wnd
);
692 IntReleaseWindowObject(Window
);
696 if (MsgFilterMax
< MsgFilterMin
)
702 Present
= IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
);
706 /* See if this message type is present in the table */
707 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
708 if (NULL
== MsgMemoryEntry
)
710 /* Not present, no copying needed */
715 /* Determine required size */
716 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
718 /* Allocate required amount of user-mode memory */
719 Info
.LParamSize
= Size
;
721 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
722 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
723 if (! NT_SUCCESS(Status
))
725 SetLastNtError(Status
);
728 /* Transfer lParam data to user-mode mem */
729 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
730 if (! NT_SUCCESS(Status
))
732 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
733 &Info
.LParamSize
, MEM_DECOMMIT
);
734 SetLastNtError(Status
);
737 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
739 if (Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
741 ExFreePool((void *) Msg
.Msg
.lParam
);
743 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
744 if (! NT_SUCCESS(Status
))
746 SetLastNtError(Status
);
755 IntWaitMessage(HWND Wnd
,
759 PUSER_MESSAGE_QUEUE ThreadQueue
;
763 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
767 if (IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_NOREMOVE
))
772 /* Nothing found. Wait for new messages. */
773 Status
= MsqWaitForNewMessages(ThreadQueue
);
775 while (STATUS_WAIT_0
<= STATUS_WAIT_0
&& Status
<= STATUS_WAIT_63
);
777 SetLastNtError(Status
);
783 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
788 * FUNCTION: Get a message from the calling thread's message queue.
790 * UnsafeMsg - Pointer to the structure which receives the returned message.
791 * Wnd - Window whose messages are to be retrieved.
792 * MsgFilterMin - Integer value of the lowest message value to be
794 * MsgFilterMax - Integer value of the highest message value to be
799 NTUSERGETMESSAGEINFO Info
;
801 PWINDOW_OBJECT Window
;
802 PMSGMEMORY MsgMemoryEntry
;
810 Window
= IntGetWindowObject(Wnd
);
814 IntReleaseWindowObject(Window
);
816 if (MsgFilterMax
< MsgFilterMin
)
824 GotMessage
= IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
);
828 /* See if this message type is present in the table */
829 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
830 if (NULL
== MsgMemoryEntry
)
832 /* Not present, no copying needed */
837 /* Determine required size */
838 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
840 /* Allocate required amount of user-mode memory */
841 Info
.LParamSize
= Size
;
843 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
844 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
846 if (! NT_SUCCESS(Status
))
848 SetLastNtError(Status
);
851 /* Transfer lParam data to user-mode mem */
852 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
853 if (! NT_SUCCESS(Status
))
855 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
856 &Info
.LParamSize
, MEM_DECOMMIT
);
857 SetLastNtError(Status
);
860 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
862 if (Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
864 ExFreePool((void *) Msg
.Msg
.lParam
);
866 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
867 if (! NT_SUCCESS(Status
))
869 SetLastNtError(Status
);
875 IntWaitMessage(Wnd
, MsgFilterMin
, MsgFilterMax
);
878 while (! GotMessage
);
880 return WM_QUIT
!= Info
.Msg
.message
;
899 static NTSTATUS FASTCALL
900 CopyMsgToKernelMem(MSG
*KernelModeMsg
, MSG
*UserModeMsg
, PMSGMEMORY MsgMemoryEntry
)
907 *KernelModeMsg
= *UserModeMsg
;
909 /* See if this message type is present in the table */
910 if (NULL
== MsgMemoryEntry
)
912 /* Not present, no copying needed */
913 return STATUS_SUCCESS
;
916 /* Determine required size */
917 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
921 /* Allocate kernel mem */
922 KernelMem
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
923 if (NULL
== KernelMem
)
925 DPRINT1("Not enough memory to copy message to kernel mem\n");
926 return STATUS_NO_MEMORY
;
928 KernelModeMsg
->lParam
= (LPARAM
) KernelMem
;
930 /* Copy data if required */
931 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_READ
))
933 Status
= MmCopyFromCaller(KernelMem
, (PVOID
) UserModeMsg
->lParam
, Size
);
934 if (! NT_SUCCESS(Status
))
936 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
937 ExFreePool(KernelMem
);
943 /* Make sure we don't pass any secrets to usermode */
944 RtlZeroMemory(KernelMem
, Size
);
949 KernelModeMsg
->lParam
= 0;
952 return STATUS_SUCCESS
;
955 static NTSTATUS FASTCALL
956 CopyMsgToUserMem(MSG
*UserModeMsg
, MSG
*KernelModeMsg
)
959 PMSGMEMORY MsgMemoryEntry
;
962 /* See if this message type is present in the table */
963 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
964 if (NULL
== MsgMemoryEntry
)
966 /* Not present, no copying needed */
967 return STATUS_SUCCESS
;
970 /* Determine required size */
971 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
975 /* Copy data if required */
976 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_WRITE
))
978 Status
= MmCopyToCaller((PVOID
) UserModeMsg
->lParam
, (PVOID
) KernelModeMsg
->lParam
, Size
);
979 if (! NT_SUCCESS(Status
))
981 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
982 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
987 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
990 return STATUS_SUCCESS
;
994 NtUserPostMessage(HWND Wnd
,
999 PWINDOW_OBJECT Window
;
1000 MSG UserModeMsg
, KernelModeMsg
;
1001 LARGE_INTEGER LargeTickCount
;
1003 PMSGMEMORY MsgMemoryEntry
;
1007 MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue
, wParam
);
1009 else if (Wnd
== HWND_BROADCAST
)
1012 PWINDOW_OBJECT DesktopWindow
;
1015 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
1016 List
= IntWinListChildren(DesktopWindow
);
1017 IntReleaseWindowObject(DesktopWindow
);
1020 for (i
= 0; List
[i
]; i
++)
1021 NtUserPostMessage(List
[i
], Msg
, wParam
, lParam
);
1027 Window
= IntGetWindowObject(Wnd
);
1030 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1034 UserModeMsg
.hwnd
= Wnd
;
1035 UserModeMsg
.message
= Msg
;
1036 UserModeMsg
.wParam
= wParam
;
1037 UserModeMsg
.lParam
= lParam
;
1038 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1039 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1040 if (! NT_SUCCESS(Status
))
1042 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1045 KernelModeMsg
.pt
.x
= PsGetWin32Process()->WindowStation
->SystemCursor
.x
;
1046 KernelModeMsg
.pt
.y
= PsGetWin32Process()->WindowStation
->SystemCursor
.y
;
1047 KeQueryTickCount(&LargeTickCount
);
1048 KernelModeMsg
.time
= LargeTickCount
.u
.LowPart
;
1049 MsqPostMessage(Window
->MessageQueue
, &KernelModeMsg
,
1050 NULL
!= MsgMemoryEntry
&& 0 != KernelModeMsg
.lParam
);
1051 IntReleaseWindowObject(Window
);
1058 NtUserPostThreadMessage(DWORD idThread
,
1063 MSG UserModeMsg
, KernelModeMsg
;
1067 PMSGMEMORY MsgMemoryEntry
;
1069 Status
= PsLookupThreadByThreadId((void *)idThread
,&peThread
);
1071 if( Status
== STATUS_SUCCESS
) {
1072 pThread
= peThread
->Win32Thread
;
1073 if( !pThread
|| !pThread
->MessageQueue
)
1075 ObDereferenceObject( peThread
);
1079 UserModeMsg
.hwnd
= NULL
;
1080 UserModeMsg
.message
= Msg
;
1081 UserModeMsg
.wParam
= wParam
;
1082 UserModeMsg
.lParam
= lParam
;
1083 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1084 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1085 if (! NT_SUCCESS(Status
))
1087 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1090 MsqPostMessage(pThread
->MessageQueue
, &KernelModeMsg
,
1091 NULL
!= MsgMemoryEntry
&& 0 != KernelModeMsg
.lParam
);
1092 ObDereferenceObject( peThread
);
1095 SetLastNtError( Status
);
1101 NtUserQuerySendMessage(DWORD Unknown0
)
1109 IntSendMessage(HWND hWnd
,
1115 if(IntSendMessageTimeout(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1122 static LRESULT FASTCALL
1123 IntSendMessageTimeoutSingle(HWND hWnd
,
1133 PWINDOW_OBJECT Window
;
1134 PMSGMEMORY MsgMemoryEntry
;
1135 INT lParamBufferSize
;
1136 LPARAM lParamPacked
;
1137 PW32THREAD Win32Thread
;
1139 /* FIXME: Call hooks. */
1140 Window
= IntGetWindowObject(hWnd
);
1143 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1147 Win32Thread
= PsGetWin32Thread();
1149 if (NULL
!= Win32Thread
&&
1150 Window
->MessageQueue
== Win32Thread
->MessageQueue
)
1152 if (Win32Thread
->IsExiting
)
1154 /* Never send messages to exiting threads */
1155 IntReleaseWindowObject(Window
);
1159 /* See if this message type is present in the table */
1160 MsgMemoryEntry
= FindMsgMemory(Msg
);
1161 if (NULL
== MsgMemoryEntry
)
1163 lParamBufferSize
= -1;
1167 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
1170 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
)))
1172 IntReleaseWindowObject(Window
);
1173 DPRINT1("Failed to pack message parameters\n");
1176 if (0xFFFF0000 != ((DWORD
) Window
->WndProcW
& 0xFFFF0000))
1178 Result
= IntCallWindowProc(Window
->WndProcW
, FALSE
, hWnd
, Msg
, wParam
,
1179 lParamPacked
,lParamBufferSize
);
1183 Result
= IntCallWindowProc(Window
->WndProcA
, TRUE
, hWnd
, Msg
, wParam
,
1184 lParamPacked
,lParamBufferSize
);
1186 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
)))
1188 IntReleaseWindowObject(Window
);
1189 DPRINT1("Failed to unpack message parameters\n");
1195 IntReleaseWindowObject(Window
);
1201 if(uFlags
& SMTO_ABORTIFHUNG
&& MsqIsHung(Window
->MessageQueue
))
1203 IntReleaseWindowObject(Window
);
1204 /* FIXME - Set a LastError? */
1208 Status
= MsqSendMessage(Window
->MessageQueue
, hWnd
, Msg
, wParam
, lParam
,
1209 uTimeout
, (uFlags
& SMTO_BLOCK
), &Result
);
1210 if(Status
== STATUS_TIMEOUT
)
1212 IntReleaseWindowObject(Window
);
1213 SetLastWin32Error(ERROR_TIMEOUT
);
1217 IntReleaseWindowObject(Window
);
1224 IntSendMessageTimeout(HWND hWnd
,
1232 PWINDOW_OBJECT DesktopWindow
;
1236 if (HWND_BROADCAST
!= hWnd
)
1238 return IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1241 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
1242 if (NULL
== DesktopWindow
)
1244 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1247 Children
= IntWinListChildren(DesktopWindow
);
1248 IntReleaseWindowObject(DesktopWindow
);
1249 if (NULL
== Children
)
1254 for (Child
= Children
; NULL
!= *Child
; Child
++)
1256 IntSendMessageTimeoutSingle(*Child
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1259 ExFreePool(Children
);
1261 return (LRESULT
) TRUE
;
1265 /* This function posts a message if the destination's message queue belongs to
1266 another thread, otherwise it sends the message. It does not support broadcast
1269 IntPostOrSendMessage(HWND hWnd
,
1275 PWINDOW_OBJECT Window
;
1277 if(hWnd
== HWND_BROADCAST
)
1282 Window
= IntGetWindowObject(hWnd
);
1285 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1289 if(Window
->MessageQueue
!= PsGetWin32Thread()->MessageQueue
)
1291 Result
= NtUserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1295 if(!IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1301 IntReleaseWindowObject(Window
);
1307 IntDoSendMessage(HWND Wnd
,
1312 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1316 PWINDOW_OBJECT Window
;
1317 NTUSERSENDMESSAGEINFO Info
;
1320 PMSGMEMORY MsgMemoryEntry
;
1322 RtlZeroMemory(&Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1324 /* FIXME: Call hooks. */
1325 if (HWND_BROADCAST
!= Wnd
)
1327 Window
= IntGetWindowObject(Wnd
);
1330 /* Tell usermode to not touch this one */
1331 Info
.HandledByKernel
= TRUE
;
1332 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1333 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1338 /* FIXME: Check for an exiting window. */
1340 /* See if the current thread can handle the message */
1341 if (HWND_BROADCAST
!= Wnd
&& NULL
!= PsGetWin32Thread() &&
1342 Window
->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
1344 /* Gather the information usermode needs to call the window proc directly */
1345 Info
.HandledByKernel
= FALSE
;
1346 if (0xFFFF0000 != ((DWORD
) Window
->WndProcW
& 0xFFFF0000))
1348 if (0xFFFF0000 != ((DWORD
) Window
->WndProcA
& 0xFFFF0000))
1350 /* Both Unicode and Ansi winprocs are real, see what usermode prefers */
1351 Status
= MmCopyFromCaller(&(Info
.Ansi
), &(UnsafeInfo
->Ansi
),
1353 if (! NT_SUCCESS(Status
))
1355 Info
.Ansi
= ! Window
->Unicode
;
1357 Info
.Proc
= (Info
.Ansi
? Window
->WndProcA
: Window
->WndProcW
);
1361 /* Real Unicode winproc */
1363 Info
.Proc
= Window
->WndProcW
;
1368 /* Must have real Ansi winproc */
1370 Info
.Proc
= Window
->WndProcA
;
1372 IntReleaseWindowObject(Window
);
1376 /* Must be handled by other thread */
1377 if (HWND_BROADCAST
!= Wnd
)
1379 IntReleaseWindowObject(Window
);
1381 Info
.HandledByKernel
= TRUE
;
1382 UserModeMsg
.hwnd
= Wnd
;
1383 UserModeMsg
.message
= Msg
;
1384 UserModeMsg
.wParam
= wParam
;
1385 UserModeMsg
.lParam
= lParam
;
1386 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1387 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1388 if (! NT_SUCCESS(Status
))
1390 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1391 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1392 return (dsm
? 0 : -1);
1396 Result
= IntSendMessage(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1397 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
);
1401 Result
= IntSendMessageTimeout(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1402 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
,
1403 dsm
->uFlags
, dsm
->uTimeout
, &dsm
->uResult
);
1405 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
1406 if (! NT_SUCCESS(Status
))
1408 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1409 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1410 return(dsm
? 0 : -1);
1414 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1415 if (! NT_SUCCESS(Status
))
1417 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1424 NtUserSendMessageTimeout(HWND hWnd
,
1431 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1436 dsm
.uFlags
= uFlags
;
1437 dsm
.uTimeout
= uTimeout
;
1438 Result
= IntDoSendMessage(hWnd
, Msg
, wParam
, lParam
, &dsm
, UnsafeInfo
);
1443 Status
= MmCopyToCaller(uResult
, &dsm
.uResult
, sizeof(ULONG_PTR
));
1444 if(!NT_SUCCESS(Status
))
1446 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1454 NtUserSendMessage(HWND Wnd
,
1458 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1460 return IntDoSendMessage(Wnd
, Msg
, wParam
, lParam
, NULL
, UnsafeInfo
);
1464 NtUserSendMessageCallback(HWND hWnd
,
1468 SENDASYNCPROC lpCallBack
,
1477 NtUserSendNotifyMessage(HWND hWnd
,
1488 NtUserWaitMessage(VOID
)
1491 return IntWaitMessage(NULL
, 0, 0);
1495 NtUserGetQueueStatus(BOOL ClearChanges
)
1497 PUSER_MESSAGE_QUEUE Queue
;
1500 Queue
= PsGetWin32Thread()->MessageQueue
;
1502 IntLockMessageQueue(Queue
);
1504 Result
= MAKELONG(Queue
->ChangedBits
, Queue
->WakeBits
);
1507 Queue
->ChangedBits
= 0;
1510 IntUnLockMessageQueue(Queue
);
1516 IntInitMessagePumpHook()
1518 PsGetCurrentThread()->Win32Thread
->MessagePumpHookValue
++;
1523 IntUninitMessagePumpHook()
1525 if (PsGetCurrentThread()->Win32Thread
->MessagePumpHookValue
<= 0)
1529 PsGetCurrentThread()->Win32Thread
->MessagePumpHookValue
--;