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.60 2004/04/29 21:13:16 gvg 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 ******************************************************************/
32 #include <ddk/ntddk.h>
33 #include <win32k/win32k.h>
34 #include <include/msgqueue.h>
35 #include <include/window.h>
36 #include <include/winpos.h>
37 #include <include/focus.h>
38 #include <include/class.h>
39 #include <include/error.h>
40 #include <include/object.h>
41 #include <include/winsta.h>
42 #include <include/callback.h>
43 #include <include/painting.h>
44 #include <include/input.h>
45 #include <include/desktop.h>
46 #include <include/tags.h>
47 #include <internal/safe.h>
57 } DOSENDMESSAGE
, *PDOSENDMESSAGE
;
59 /* FUNCTIONS *****************************************************************/
62 IntInitMessageImpl(VOID
)
64 return STATUS_SUCCESS
;
68 IntCleanupMessageImpl(VOID
)
70 return STATUS_SUCCESS
;
73 #define MMS_SIZE_WPARAM -1
74 #define MMS_SIZE_WPARAMWCHAR -2
75 #define MMS_SIZE_LPARAMSZ -3
76 #define MMS_SIZE_SPECIAL -4
77 #define MMS_FLAG_READ 0x01
78 #define MMS_FLAG_WRITE 0x02
79 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
80 typedef struct tagMSGMEMORY
85 } MSGMEMORY
, *PMSGMEMORY
;
87 static MSGMEMORY MsgMemory
[] =
89 { WM_CREATE
, sizeof(CREATESTRUCTW
), MMS_FLAG_READWRITE
},
90 { WM_DDE_ACK
, sizeof(KMDDELPARAM
), MMS_FLAG_READ
},
91 { WM_DDE_EXECUTE
, MMS_SIZE_WPARAM
, MMS_FLAG_READ
},
92 { WM_GETMINMAXINFO
, sizeof(MINMAXINFO
), MMS_FLAG_READWRITE
},
93 { WM_GETTEXT
, MMS_SIZE_WPARAMWCHAR
, MMS_FLAG_WRITE
},
94 { WM_NCCALCSIZE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
95 { WM_NCCREATE
, sizeof(CREATESTRUCTW
), MMS_FLAG_READWRITE
},
96 { WM_SETTEXT
, MMS_SIZE_LPARAMSZ
, MMS_FLAG_READ
},
97 { WM_STYLECHANGED
, sizeof(STYLESTRUCT
), MMS_FLAG_READ
},
98 { WM_STYLECHANGING
, sizeof(STYLESTRUCT
), MMS_FLAG_READWRITE
},
99 { WM_WINDOWPOSCHANGED
, sizeof(WINDOWPOS
), MMS_FLAG_READ
},
100 { WM_WINDOWPOSCHANGING
, sizeof(WINDOWPOS
), MMS_FLAG_READWRITE
},
103 static PMSGMEMORY FASTCALL
104 FindMsgMemory(UINT Msg
)
106 PMSGMEMORY MsgMemoryEntry
;
108 /* See if this message type is present in the table */
109 for (MsgMemoryEntry
= MsgMemory
;
110 MsgMemoryEntry
< MsgMemory
+ sizeof(MsgMemory
) / sizeof(MSGMEMORY
);
113 if (Msg
== MsgMemoryEntry
->Message
)
115 return MsgMemoryEntry
;
123 MsgMemorySize(PMSGMEMORY MsgMemoryEntry
, WPARAM wParam
, LPARAM lParam
)
125 if (MMS_SIZE_WPARAM
== MsgMemoryEntry
->Size
)
127 return (UINT
) wParam
;
129 else if (MMS_SIZE_WPARAMWCHAR
== MsgMemoryEntry
->Size
)
131 return (UINT
) (wParam
* sizeof(WCHAR
));
133 else if (MMS_SIZE_LPARAMSZ
== MsgMemoryEntry
->Size
)
135 return (UINT
) ((wcslen((PWSTR
) lParam
) + 1) * sizeof(WCHAR
));
137 else if (MMS_SIZE_SPECIAL
== MsgMemoryEntry
->Size
)
139 switch(MsgMemoryEntry
->Message
)
142 return wParam
? sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
) : sizeof(RECT
);
152 return MsgMemoryEntry
->Size
;
156 static FASTCALL NTSTATUS
157 PackParam(LPARAM
*lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
159 NCCALCSIZE_PARAMS
*UnpackedParams
;
160 NCCALCSIZE_PARAMS
*PackedParams
;
162 *lParamPacked
= lParam
;
163 if (WM_NCCALCSIZE
== Msg
&& wParam
)
165 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
166 if (UnpackedParams
->lppos
!= (PWINDOWPOS
) (UnpackedParams
+ 1))
168 PackedParams
= ExAllocatePoolWithTag(PagedPool
,
169 sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
),
171 if (NULL
== PackedParams
)
173 DPRINT1("Not enough memory to pack lParam\n");
174 return STATUS_NO_MEMORY
;
176 RtlCopyMemory(PackedParams
, UnpackedParams
, sizeof(NCCALCSIZE_PARAMS
));
177 PackedParams
->lppos
= (PWINDOWPOS
) (PackedParams
+ 1);
178 RtlCopyMemory(PackedParams
->lppos
, UnpackedParams
->lppos
, sizeof(WINDOWPOS
));
179 *lParamPacked
= (LPARAM
) PackedParams
;
183 return STATUS_SUCCESS
;
186 static FASTCALL NTSTATUS
187 UnpackParam(LPARAM lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
189 NCCALCSIZE_PARAMS
*UnpackedParams
;
190 NCCALCSIZE_PARAMS
*PackedParams
;
191 PWINDOWPOS UnpackedWindowPos
;
193 if (lParamPacked
== lParam
)
195 return STATUS_SUCCESS
;
198 if (WM_NCCALCSIZE
== Msg
&& wParam
)
200 PackedParams
= (NCCALCSIZE_PARAMS
*) lParamPacked
;
201 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
202 UnpackedWindowPos
= UnpackedParams
->lppos
;
203 RtlCopyMemory(UnpackedParams
, PackedParams
, sizeof(NCCALCSIZE_PARAMS
));
204 UnpackedParams
->lppos
= UnpackedWindowPos
;
205 RtlCopyMemory(UnpackedWindowPos
, PackedParams
+ 1, sizeof(WINDOWPOS
));
206 ExFreePool((PVOID
) lParamPacked
);
208 return STATUS_SUCCESS
;
213 return STATUS_INVALID_PARAMETER
;
218 NtUserDispatchMessage(PNTUSERDISPATCHMESSAGEINFO UnsafeMsgInfo
)
221 NTUSERDISPATCHMESSAGEINFO MsgInfo
;
222 PWINDOW_OBJECT WindowObject
;
225 Status
= MmCopyFromCaller(&MsgInfo
, UnsafeMsgInfo
, sizeof(NTUSERDISPATCHMESSAGEINFO
));
226 if (! NT_SUCCESS(Status
))
228 SetLastNtError(Status
);
232 /* Process timer messages. */
233 if (WM_TIMER
== MsgInfo
.Msg
.message
&& 0 != MsgInfo
.Msg
.lParam
)
235 LARGE_INTEGER LargeTickCount
;
236 /* FIXME: Call hooks. */
238 /* FIXME: Check for continuing validity of timer. */
240 MsgInfo
.HandledByKernel
= FALSE
;
241 KeQueryTickCount(&LargeTickCount
);
242 MsgInfo
.Proc
= (WNDPROC
) MsgInfo
.Msg
.lParam
;
243 MsgInfo
.Msg
.lParam
= (LPARAM
)LargeTickCount
.u
.LowPart
;
245 else if (NULL
== MsgInfo
.Msg
.hwnd
)
247 MsgInfo
.HandledByKernel
= TRUE
;
252 /* Get the window object. */
253 WindowObject
= IntGetWindowObject(MsgInfo
.Msg
.hwnd
);
254 if (NULL
== WindowObject
)
256 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
257 MsgInfo
.HandledByKernel
= TRUE
;
262 if (WindowObject
->OwnerThread
!= PsGetCurrentThread())
264 IntReleaseWindowObject(WindowObject
);
265 DPRINT1("Window doesn't belong to the calling thread!\n");
266 MsgInfo
.HandledByKernel
= TRUE
;
271 /* FIXME: Call hook procedures. */
273 MsgInfo
.HandledByKernel
= FALSE
;
275 if (0xFFFF0000 != ((DWORD
) WindowObject
->WndProcW
& 0xFFFF0000))
277 if (0xFFFF0000 != ((DWORD
) WindowObject
->WndProcA
& 0xFFFF0000))
279 /* Both Unicode and Ansi winprocs are real, use whatever
281 MsgInfo
.Proc
= (MsgInfo
.Ansi
? WindowObject
->WndProcA
282 : WindowObject
->WndProcW
);
286 /* Real Unicode winproc */
287 MsgInfo
.Ansi
= FALSE
;
288 MsgInfo
.Proc
= WindowObject
->WndProcW
;
293 /* Must have real Ansi winproc */
295 MsgInfo
.Proc
= WindowObject
->WndProcA
;
298 IntReleaseWindowObject(WindowObject
);
301 Status
= MmCopyToCaller(UnsafeMsgInfo
, &MsgInfo
, sizeof(NTUSERDISPATCHMESSAGEINFO
));
302 if (! NT_SUCCESS(Status
))
304 SetLastNtError(Status
);
313 NtUserTranslateMessage(LPMSG lpMsg
,
319 Status
= MmCopyFromCaller(&SafeMsg
, lpMsg
, sizeof(MSG
));
320 if(!NT_SUCCESS(Status
))
322 SetLastNtError(Status
);
326 return IntTranslateKbdMessage(&SafeMsg
, dwhkl
);
331 IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
)
333 if(!Msg
->hwnd
|| ThreadQueue
->CaptureWindow
)
342 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
347 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
354 case WM_LBUTTONDBLCLK
:
355 case WM_MBUTTONDBLCLK
:
356 case WM_RBUTTONDBLCLK
:
357 case WM_XBUTTONDBLCLK
:
361 if(!IntGetWindowStationObject(InputWindowStation
))
365 wParam
= (WPARAM
)InputWindowStation
->SystemCursor
.ButtonsDown
;
366 ObDereferenceObject(InputWindowStation
);
368 IntSendMessage(Msg
->hwnd
, WM_MOUSEMOVE
, wParam
, Msg
->lParam
);
369 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
372 case WM_NCLBUTTONDOWN
:
373 case WM_NCMBUTTONDOWN
:
374 case WM_NCRBUTTONDOWN
:
375 case WM_NCXBUTTONDOWN
:
376 case WM_NCLBUTTONDBLCLK
:
377 case WM_NCMBUTTONDBLCLK
:
378 case WM_NCRBUTTONDBLCLK
:
379 case WM_NCXBUTTONDBLCLK
:
381 IntSendMessage(Msg
->hwnd
, WM_NCMOUSEMOVE
, (WPARAM
)Msg
->wParam
, Msg
->lParam
);
382 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
389 IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, PWINDOW_OBJECT MsgWindow
,
394 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
396 /* eat the message, search again! */
400 Result
= IntSendMessage(MsgWindow
->Self
, WM_MOUSEACTIVATE
, (WPARAM
)NtUserGetParent(MsgWindow
->Self
), (LPARAM
)MAKELONG(*HitTest
, Msg
->message
));
403 case MA_NOACTIVATEANDEAT
:
407 case MA_ACTIVATEANDEAT
:
408 IntMouseActivateWindow(MsgWindow
);
412 IntMouseActivateWindow(MsgWindow
);
420 IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, USHORT
*HitTest
, BOOL Remove
)
422 PWINDOW_OBJECT Window
;
424 if(!(Window
= IntGetWindowObject(Msg
->hwnd
)))
426 /* FIXME - change the mouse cursor to an arrow, maybe do this a better way */
427 IntLoadDefaultCursors(TRUE
);
428 /* let's just eat the message?! */
432 if(ThreadQueue
== Window
->MessageQueue
&&
433 ThreadQueue
->CaptureWindow
!= Window
->Self
)
435 /* only send WM_NCHITTEST messages if we're not capturing the window! */
436 *HitTest
= IntSendMessage(Window
->Self
, WM_NCHITTEST
, 0,
437 MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
));
444 if(IS_BTN_MESSAGE(Msg
->message
, DOWN
))
446 /* generate double click messages, if necessary */
447 if ((((*HitTest
) != HTCLIENT
) ||
448 (IntGetClassLong(Window
, GCL_STYLE
, FALSE
) & CS_DBLCLKS
)) &&
449 MsqIsDblClk(Msg
, Remove
))
451 Msg
->message
+= WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
;
455 if(Msg
->message
!= WM_MOUSEWHEEL
)
458 if ((*HitTest
) != HTCLIENT
)
460 Msg
->message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
461 if((Msg
->message
== WM_NCRBUTTONUP
) &&
462 (((*HitTest
) == HTCAPTION
) || ((*HitTest
) == HTSYSMENU
)))
464 Msg
->message
= WM_CONTEXTMENU
;
465 Msg
->wParam
= (WPARAM
)Window
->Self
;
469 Msg
->wParam
= *HitTest
;
472 else if(ThreadQueue
->MoveSize
== NULL
&&
473 ThreadQueue
->MenuOwner
== NULL
)
475 Msg
->pt
.x
-= Window
->ClientRect
.left
;
476 Msg
->pt
.y
-= Window
->ClientRect
.top
;
477 Msg
->lParam
= MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
);
481 IntReleaseWindowObject(Window
);
487 * Internal version of PeekMessage() doing all the work
490 IntPeekMessage(PUSER_MESSAGE Msg
,
496 LARGE_INTEGER LargeTickCount
;
497 PUSER_MESSAGE_QUEUE ThreadQueue
;
498 PUSER_MESSAGE Message
;
499 BOOL Present
, RemoveMessages
;
501 /* The queues and order in which they are checked are documented in the MSDN
502 article on GetMessage() */
504 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
506 /* Inspect RemoveMsg flags */
507 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
508 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
514 KeQueryTickCount(&LargeTickCount
);
515 ThreadQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
517 /* Dispatch sent messages here. */
518 while (MsqDispatchOneSentMessage(ThreadQueue
));
520 /* Now look for a quit message. */
522 if (ThreadQueue
->QuitPosted
)
524 /* According to the PSDK, WM_QUIT messages are always returned, regardless
525 of the filter specified */
526 Msg
->Msg
.hwnd
= NULL
;
527 Msg
->Msg
.message
= WM_QUIT
;
528 Msg
->Msg
.wParam
= ThreadQueue
->QuitExitCode
;
530 Msg
->FreeLParam
= FALSE
;
533 ThreadQueue
->QuitPosted
= FALSE
;
538 /* Now check for normal messages. */
539 Present
= MsqFindMessage(ThreadQueue
,
548 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
551 MsqDestroyMessage(Message
);
556 /* Check for hardware events. */
557 Present
= MsqFindMessage(ThreadQueue
,
566 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
569 MsqDestroyMessage(Message
);
574 /* Check for sent messages again. */
575 while (MsqDispatchOneSentMessage(ThreadQueue
));
577 /* Check for paint messages. */
578 if (IntGetPaintMessage(Wnd
, MsgFilterMin
, MsgFilterMax
, PsGetWin32Thread(), &Msg
->Msg
, RemoveMessages
))
580 Msg
->FreeLParam
= FALSE
;
584 /* FIXME - get WM_(SYS)TIMER messages */
592 PWINDOW_OBJECT MsgWindow
= NULL
;;
594 if(Msg
->Msg
.hwnd
&& (MsgWindow
= IntGetWindowObject(Msg
->Msg
.hwnd
)) &&
595 Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
)
599 if(IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, TRUE
))
600 /* FIXME - check message filter again, if the message doesn't match anymore,
603 IntReleaseWindowObject(MsgWindow
);
604 /* eat the message, search again */
607 if(ThreadQueue
->CaptureWindow
== NULL
)
609 IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
610 if((Msg
->Msg
.message
!= WM_MOUSEMOVE
&& Msg
->Msg
.message
!= WM_NCMOUSEMOVE
) &&
611 IS_BTN_MESSAGE(Msg
->Msg
.message
, DOWN
) &&
612 IntActivateWindowMouse(ThreadQueue
, &Msg
->Msg
, MsgWindow
, &HitTest
))
614 IntReleaseWindowObject(MsgWindow
);
615 /* eat the message, search again */
622 IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
627 IntReleaseWindowObject(MsgWindow
);
634 if((Msg
->Msg
.hwnd
&& Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
) &&
635 IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, FALSE
))
636 /* FIXME - check message filter again, if the message doesn't match anymore,
639 /* eat the message, search again */
650 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
658 NTUSERGETMESSAGEINFO Info
;
659 PWINDOW_OBJECT Window
;
660 PMSGMEMORY MsgMemoryEntry
;
668 Window
= IntGetWindowObject(Wnd
);
675 IntReleaseWindowObject(Window
);
679 if (MsgFilterMax
< MsgFilterMin
)
685 Present
= IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
);
689 /* See if this message type is present in the table */
690 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
691 if (NULL
== MsgMemoryEntry
)
693 /* Not present, no copying needed */
698 /* Determine required size */
699 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
701 /* Allocate required amount of user-mode memory */
702 Info
.LParamSize
= Size
;
704 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
705 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
706 if (! NT_SUCCESS(Status
))
708 SetLastNtError(Status
);
711 /* Transfer lParam data to user-mode mem */
712 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
713 if (! NT_SUCCESS(Status
))
715 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
716 &Info
.LParamSize
, MEM_DECOMMIT
);
717 SetLastNtError(Status
);
720 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
722 if (Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
724 ExFreePool((void *) Msg
.Msg
.lParam
);
726 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
727 if (! NT_SUCCESS(Status
))
729 SetLastNtError(Status
);
738 IntWaitMessage(HWND Wnd
,
742 PUSER_MESSAGE_QUEUE ThreadQueue
;
746 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
750 if (IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_NOREMOVE
))
755 /* Nothing found. Wait for new messages. */
756 Status
= MsqWaitForNewMessages(ThreadQueue
);
758 while (STATUS_WAIT_0
<= STATUS_WAIT_0
&& Status
<= STATUS_WAIT_63
);
760 SetLastNtError(Status
);
766 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
771 * FUNCTION: Get a message from the calling thread's message queue.
773 * UnsafeMsg - Pointer to the structure which receives the returned message.
774 * Wnd - Window whose messages are to be retrieved.
775 * MsgFilterMin - Integer value of the lowest message value to be
777 * MsgFilterMax - Integer value of the highest message value to be
782 NTUSERGETMESSAGEINFO Info
;
784 PWINDOW_OBJECT Window
;
785 PMSGMEMORY MsgMemoryEntry
;
793 Window
= IntGetWindowObject(Wnd
);
797 IntReleaseWindowObject(Window
);
799 if (MsgFilterMax
< MsgFilterMin
)
807 GotMessage
= IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
);
811 /* See if this message type is present in the table */
812 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
813 if (NULL
== MsgMemoryEntry
)
815 /* Not present, no copying needed */
820 /* Determine required size */
821 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
823 /* Allocate required amount of user-mode memory */
824 Info
.LParamSize
= Size
;
826 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
827 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
829 if (! NT_SUCCESS(Status
))
831 SetLastNtError(Status
);
834 /* Transfer lParam data to user-mode mem */
835 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
836 if (! NT_SUCCESS(Status
))
838 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
839 &Info
.LParamSize
, MEM_DECOMMIT
);
840 SetLastNtError(Status
);
843 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
845 if (Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
847 ExFreePool((void *) Msg
.Msg
.lParam
);
849 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
850 if (! NT_SUCCESS(Status
))
852 SetLastNtError(Status
);
858 IntWaitMessage(Wnd
, MsgFilterMin
, MsgFilterMax
);
861 while (! GotMessage
);
863 return WM_QUIT
!= Info
.Msg
.message
;
882 static NTSTATUS FASTCALL
883 CopyMsgToKernelMem(MSG
*KernelModeMsg
, MSG
*UserModeMsg
, PMSGMEMORY MsgMemoryEntry
)
890 *KernelModeMsg
= *UserModeMsg
;
892 /* See if this message type is present in the table */
893 if (NULL
== MsgMemoryEntry
)
895 /* Not present, no copying needed */
896 return STATUS_SUCCESS
;
899 /* Determine required size */
900 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
904 /* Allocate kernel mem */
905 KernelMem
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
906 if (NULL
== KernelMem
)
908 DPRINT1("Not enough memory to copy message to kernel mem\n");
909 return STATUS_NO_MEMORY
;
911 KernelModeMsg
->lParam
= (LPARAM
) KernelMem
;
913 /* Copy data if required */
914 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_READ
))
916 Status
= MmCopyFromCaller(KernelMem
, (PVOID
) UserModeMsg
->lParam
, Size
);
917 if (! NT_SUCCESS(Status
))
919 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
920 ExFreePool(KernelMem
);
926 /* Make sure we don't pass any secrets to usermode */
927 RtlZeroMemory(KernelMem
, Size
);
932 KernelModeMsg
->lParam
= 0;
935 return STATUS_SUCCESS
;
938 static NTSTATUS FASTCALL
939 CopyMsgToUserMem(MSG
*UserModeMsg
, MSG
*KernelModeMsg
)
942 PMSGMEMORY MsgMemoryEntry
;
945 /* See if this message type is present in the table */
946 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
947 if (NULL
== MsgMemoryEntry
)
949 /* Not present, no copying needed */
950 return STATUS_SUCCESS
;
953 /* Determine required size */
954 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
958 /* Copy data if required */
959 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_WRITE
))
961 Status
= MmCopyToCaller((PVOID
) UserModeMsg
->lParam
, (PVOID
) KernelModeMsg
->lParam
, Size
);
962 if (! NT_SUCCESS(Status
))
964 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
965 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
970 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
973 return STATUS_SUCCESS
;
977 NtUserPostMessage(HWND Wnd
,
982 PWINDOW_OBJECT Window
;
983 MSG UserModeMsg
, KernelModeMsg
;
984 LARGE_INTEGER LargeTickCount
;
986 PMSGMEMORY MsgMemoryEntry
;
990 MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue
, wParam
);
992 else if (Wnd
== HWND_BROADCAST
)
995 PWINDOW_OBJECT DesktopWindow
;
998 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
999 List
= IntWinListChildren(DesktopWindow
);
1000 IntReleaseWindowObject(DesktopWindow
);
1003 for (i
= 0; List
[i
]; i
++)
1004 NtUserPostMessage(List
[i
], Msg
, wParam
, lParam
);
1010 Window
= IntGetWindowObject(Wnd
);
1013 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1017 UserModeMsg
.hwnd
= Wnd
;
1018 UserModeMsg
.message
= Msg
;
1019 UserModeMsg
.wParam
= wParam
;
1020 UserModeMsg
.lParam
= lParam
;
1021 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1022 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1023 if (! NT_SUCCESS(Status
))
1025 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1028 KernelModeMsg
.pt
.x
= PsGetWin32Process()->WindowStation
->SystemCursor
.x
;
1029 KernelModeMsg
.pt
.y
= PsGetWin32Process()->WindowStation
->SystemCursor
.y
;
1030 KeQueryTickCount(&LargeTickCount
);
1031 KernelModeMsg
.time
= LargeTickCount
.u
.LowPart
;
1032 MsqPostMessage(Window
->MessageQueue
, &KernelModeMsg
,
1033 NULL
!= MsgMemoryEntry
&& 0 != KernelModeMsg
.lParam
);
1034 IntReleaseWindowObject(Window
);
1041 NtUserPostThreadMessage(DWORD idThread
,
1046 MSG UserModeMsg
, KernelModeMsg
;
1050 PMSGMEMORY MsgMemoryEntry
;
1052 Status
= PsLookupThreadByThreadId((void *)idThread
,&peThread
);
1054 if( Status
== STATUS_SUCCESS
) {
1055 pThread
= peThread
->Win32Thread
;
1056 if( !pThread
|| !pThread
->MessageQueue
)
1058 ObDereferenceObject( peThread
);
1062 UserModeMsg
.hwnd
= NULL
;
1063 UserModeMsg
.message
= Msg
;
1064 UserModeMsg
.wParam
= wParam
;
1065 UserModeMsg
.lParam
= lParam
;
1066 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1067 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1068 if (! NT_SUCCESS(Status
))
1070 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1073 MsqPostMessage(pThread
->MessageQueue
, &KernelModeMsg
,
1074 NULL
!= MsgMemoryEntry
&& 0 != KernelModeMsg
.lParam
);
1075 ObDereferenceObject( peThread
);
1078 SetLastNtError( Status
);
1084 NtUserQuerySendMessage(DWORD Unknown0
)
1092 IntSendMessage(HWND hWnd
,
1098 if(IntSendMessageTimeout(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1105 static LRESULT FASTCALL
1106 IntSendMessageTimeoutSingle(HWND hWnd
,
1116 PWINDOW_OBJECT Window
;
1117 PMSGMEMORY MsgMemoryEntry
;
1118 INT lParamBufferSize
;
1119 LPARAM lParamPacked
;
1120 PW32THREAD Win32Thread
;
1122 /* FIXME: Call hooks. */
1123 Window
= IntGetWindowObject(hWnd
);
1126 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1130 Win32Thread
= PsGetWin32Thread();
1132 if (NULL
!= Win32Thread
&&
1133 Window
->MessageQueue
== Win32Thread
->MessageQueue
)
1135 if (Win32Thread
->IsExiting
)
1137 /* Never send messages to exiting threads */
1138 IntReleaseWindowObject(Window
);
1142 /* See if this message type is present in the table */
1143 MsgMemoryEntry
= FindMsgMemory(Msg
);
1144 if (NULL
== MsgMemoryEntry
)
1146 lParamBufferSize
= -1;
1150 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
1153 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
)))
1155 IntReleaseWindowObject(Window
);
1156 DPRINT1("Failed to pack message parameters\n");
1159 if (0xFFFF0000 != ((DWORD
) Window
->WndProcW
& 0xFFFF0000))
1161 Result
= IntCallWindowProc(Window
->WndProcW
, FALSE
, hWnd
, Msg
, wParam
,
1162 lParamPacked
,lParamBufferSize
);
1166 Result
= IntCallWindowProc(Window
->WndProcA
, TRUE
, hWnd
, Msg
, wParam
,
1167 lParamPacked
,lParamBufferSize
);
1169 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
)))
1171 IntReleaseWindowObject(Window
);
1172 DPRINT1("Failed to unpack message parameters\n");
1178 IntReleaseWindowObject(Window
);
1184 if(uFlags
& SMTO_ABORTIFHUNG
&& MsqIsHung(Window
->MessageQueue
))
1186 IntReleaseWindowObject(Window
);
1187 /* FIXME - Set a LastError? */
1191 Status
= MsqSendMessage(Window
->MessageQueue
, hWnd
, Msg
, wParam
, lParam
,
1192 uTimeout
, (uFlags
& SMTO_BLOCK
), &Result
);
1193 if(Status
== STATUS_TIMEOUT
)
1195 IntReleaseWindowObject(Window
);
1196 SetLastWin32Error(ERROR_TIMEOUT
);
1200 IntReleaseWindowObject(Window
);
1207 IntSendMessageTimeout(HWND hWnd
,
1215 PWINDOW_OBJECT DesktopWindow
;
1219 if (HWND_BROADCAST
!= hWnd
)
1221 return IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1224 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
1225 if (NULL
== DesktopWindow
)
1227 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1230 Children
= IntWinListChildren(DesktopWindow
);
1231 IntReleaseWindowObject(DesktopWindow
);
1232 if (NULL
== Children
)
1237 for (Child
= Children
; NULL
!= *Child
; Child
++)
1239 IntSendMessageTimeoutSingle(*Child
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1242 ExFreePool(Children
);
1244 return (LRESULT
) TRUE
;
1248 /* This function posts a message if the destination's message queue belongs to
1249 another thread, otherwise it sends the message. It does not support broadcast
1252 IntPostOrSendMessage(HWND hWnd
,
1258 PWINDOW_OBJECT Window
;
1260 if(hWnd
== HWND_BROADCAST
)
1265 Window
= IntGetWindowObject(hWnd
);
1268 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1272 if(Window
->MessageQueue
!= PsGetWin32Thread()->MessageQueue
)
1274 Result
= NtUserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1278 if(!IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1284 IntReleaseWindowObject(Window
);
1290 IntDoSendMessage(HWND Wnd
,
1295 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1299 PWINDOW_OBJECT Window
;
1300 NTUSERSENDMESSAGEINFO Info
;
1303 PMSGMEMORY MsgMemoryEntry
;
1305 RtlZeroMemory(&Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1307 /* FIXME: Call hooks. */
1308 if (HWND_BROADCAST
!= Wnd
)
1310 Window
= IntGetWindowObject(Wnd
);
1313 /* Tell usermode to not touch this one */
1314 Info
.HandledByKernel
= TRUE
;
1315 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1316 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1321 /* FIXME: Check for an exiting window. */
1323 /* See if the current thread can handle the message */
1324 if (HWND_BROADCAST
!= Wnd
&& NULL
!= PsGetWin32Thread() &&
1325 Window
->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
1327 /* Gather the information usermode needs to call the window proc directly */
1328 Info
.HandledByKernel
= FALSE
;
1329 if (0xFFFF0000 != ((DWORD
) Window
->WndProcW
& 0xFFFF0000))
1331 if (0xFFFF0000 != ((DWORD
) Window
->WndProcA
& 0xFFFF0000))
1333 /* Both Unicode and Ansi winprocs are real, see what usermode prefers */
1334 Status
= MmCopyFromCaller(&(Info
.Ansi
), &(UnsafeInfo
->Ansi
),
1336 if (! NT_SUCCESS(Status
))
1338 Info
.Ansi
= ! Window
->Unicode
;
1340 Info
.Proc
= (Info
.Ansi
? Window
->WndProcA
: Window
->WndProcW
);
1344 /* Real Unicode winproc */
1346 Info
.Proc
= Window
->WndProcW
;
1351 /* Must have real Ansi winproc */
1353 Info
.Proc
= Window
->WndProcA
;
1355 IntReleaseWindowObject(Window
);
1359 /* Must be handled by other thread */
1360 if (HWND_BROADCAST
!= Wnd
)
1362 IntReleaseWindowObject(Window
);
1364 Info
.HandledByKernel
= TRUE
;
1365 UserModeMsg
.hwnd
= Wnd
;
1366 UserModeMsg
.message
= Msg
;
1367 UserModeMsg
.wParam
= wParam
;
1368 UserModeMsg
.lParam
= lParam
;
1369 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1370 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1371 if (! NT_SUCCESS(Status
))
1373 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1374 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1375 return (dsm
? 0 : -1);
1379 Result
= IntSendMessage(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1380 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
);
1384 Result
= IntSendMessageTimeout(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1385 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
,
1386 dsm
->uFlags
, dsm
->uTimeout
, &dsm
->uResult
);
1388 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
1389 if (! NT_SUCCESS(Status
))
1391 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1392 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1393 return(dsm
? 0 : -1);
1397 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1398 if (! NT_SUCCESS(Status
))
1400 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1407 NtUserSendMessageTimeout(HWND hWnd
,
1414 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1419 dsm
.uFlags
= uFlags
;
1420 dsm
.uTimeout
= uTimeout
;
1421 Result
= IntDoSendMessage(hWnd
, Msg
, wParam
, lParam
, &dsm
, UnsafeInfo
);
1426 Status
= MmCopyToCaller(uResult
, &dsm
.uResult
, sizeof(ULONG_PTR
));
1427 if(!NT_SUCCESS(Status
))
1429 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1437 NtUserSendMessage(HWND Wnd
,
1441 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1443 return IntDoSendMessage(Wnd
, Msg
, wParam
, lParam
, NULL
, UnsafeInfo
);
1447 NtUserSendMessageCallback(HWND hWnd
,
1451 SENDASYNCPROC lpCallBack
,
1460 NtUserSendNotifyMessage(HWND hWnd
,
1471 NtUserWaitMessage(VOID
)
1474 return IntWaitMessage(NULL
, 0, 0);
1478 NtUserGetQueueStatus(BOOL ClearChanges
)
1480 PUSER_MESSAGE_QUEUE Queue
;
1483 Queue
= PsGetWin32Thread()->MessageQueue
;
1485 IntLockMessageQueue(Queue
);
1487 Result
= MAKELONG(Queue
->ChangedBits
, Queue
->WakeBits
);
1490 Queue
->ChangedBits
= 0;
1493 IntUnLockMessageQueue(Queue
);
1499 IntInitMessagePumpHook()
1501 PsGetCurrentThread()->Win32Thread
->MessagePumpHookValue
++;
1506 IntUninitMessagePumpHook()
1508 if (PsGetCurrentThread()->Win32Thread
->MessagePumpHookValue
<= 0)
1512 PsGetCurrentThread()->Win32Thread
->MessagePumpHookValue
--;