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.76 2004/12/11 19:39: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
, MMS_SIZE_SPECIAL
, 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
, MMS_SIZE_SPECIAL
, 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
)
111 PUNICODE_STRING WindowName
;
112 PUNICODE_STRING ClassName
;
115 if (MMS_SIZE_WPARAM
== MsgMemoryEntry
->Size
)
117 return (UINT
) wParam
;
119 else if (MMS_SIZE_WPARAMWCHAR
== MsgMemoryEntry
->Size
)
121 return (UINT
) (wParam
* sizeof(WCHAR
));
123 else if (MMS_SIZE_LPARAMSZ
== MsgMemoryEntry
->Size
)
125 return (UINT
) ((wcslen((PWSTR
) lParam
) + 1) * sizeof(WCHAR
));
127 else if (MMS_SIZE_SPECIAL
== MsgMemoryEntry
->Size
)
129 switch(MsgMemoryEntry
->Message
)
133 Cs
= (CREATESTRUCTW
*) lParam
;
134 WindowName
= (PUNICODE_STRING
) Cs
->lpszName
;
135 ClassName
= (PUNICODE_STRING
) Cs
->lpszClass
;
136 Size
= sizeof(CREATESTRUCTW
) + WindowName
->Length
+ sizeof(WCHAR
);
137 if (IS_ATOM(ClassName
->Buffer
))
139 Size
+= sizeof(WCHAR
) + sizeof(ATOM
);
143 Size
+= sizeof(WCHAR
) + ClassName
->Length
+ sizeof(WCHAR
);
149 return wParam
? sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
) : sizeof(RECT
);
160 return MsgMemoryEntry
->Size
;
164 static FASTCALL NTSTATUS
165 PackParam(LPARAM
*lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
167 NCCALCSIZE_PARAMS
*UnpackedNcCalcsize
;
168 NCCALCSIZE_PARAMS
*PackedNcCalcsize
;
169 CREATESTRUCTW
*UnpackedCs
;
170 CREATESTRUCTW
*PackedCs
;
171 PUNICODE_STRING WindowName
;
172 PUNICODE_STRING ClassName
;
176 *lParamPacked
= lParam
;
177 if (WM_NCCALCSIZE
== Msg
&& wParam
)
179 UnpackedNcCalcsize
= (NCCALCSIZE_PARAMS
*) lParam
;
180 if (UnpackedNcCalcsize
->lppos
!= (PWINDOWPOS
) (UnpackedNcCalcsize
+ 1))
182 PackedNcCalcsize
= ExAllocatePoolWithTag(PagedPool
,
183 sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
),
185 if (NULL
== PackedNcCalcsize
)
187 DPRINT1("Not enough memory to pack lParam\n");
188 return STATUS_NO_MEMORY
;
190 RtlCopyMemory(PackedNcCalcsize
, UnpackedNcCalcsize
, sizeof(NCCALCSIZE_PARAMS
));
191 PackedNcCalcsize
->lppos
= (PWINDOWPOS
) (PackedNcCalcsize
+ 1);
192 RtlCopyMemory(PackedNcCalcsize
->lppos
, UnpackedNcCalcsize
->lppos
, sizeof(WINDOWPOS
));
193 *lParamPacked
= (LPARAM
) PackedNcCalcsize
;
196 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
198 UnpackedCs
= (CREATESTRUCTW
*) lParam
;
199 WindowName
= (PUNICODE_STRING
) UnpackedCs
->lpszName
;
200 ClassName
= (PUNICODE_STRING
) UnpackedCs
->lpszClass
;
201 Size
= sizeof(CREATESTRUCTW
) + WindowName
->Length
+ sizeof(WCHAR
);
202 if (IS_ATOM(ClassName
->Buffer
))
204 Size
+= sizeof(WCHAR
) + sizeof(ATOM
);
208 Size
+= sizeof(WCHAR
) + ClassName
->Length
+ sizeof(WCHAR
);
210 PackedCs
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
211 if (NULL
== PackedCs
)
213 DPRINT1("Not enough memory to pack lParam\n");
214 return STATUS_NO_MEMORY
;
216 RtlCopyMemory(PackedCs
, UnpackedCs
, sizeof(CREATESTRUCTW
));
217 CsData
= (PCHAR
) (PackedCs
+ 1);
218 PackedCs
->lpszName
= (LPCWSTR
) (CsData
- (PCHAR
) PackedCs
);
219 RtlCopyMemory(CsData
, WindowName
->Buffer
, WindowName
->Length
);
220 CsData
+= WindowName
->Length
;
221 *((WCHAR
*) CsData
) = L
'\0';
222 CsData
+= sizeof(WCHAR
);
223 PackedCs
->lpszClass
= (LPCWSTR
) (CsData
- (PCHAR
) PackedCs
);
224 if (IS_ATOM(ClassName
->Buffer
))
226 *((WCHAR
*) CsData
) = L
'A';
227 CsData
+= sizeof(WCHAR
);
228 *((ATOM
*) CsData
) = (ATOM
)(DWORD_PTR
) ClassName
->Buffer
;
229 CsData
+= sizeof(ATOM
);
233 *((WCHAR
*) CsData
) = L
'S';
234 CsData
+= sizeof(WCHAR
);
235 RtlCopyMemory(CsData
, ClassName
->Buffer
, ClassName
->Length
);
236 CsData
+= ClassName
->Length
;
237 *((WCHAR
*) CsData
) = L
'\0';
238 CsData
+= sizeof(WCHAR
);
240 ASSERT(CsData
== (PCHAR
) PackedCs
+ Size
);
241 *lParamPacked
= (LPARAM
) PackedCs
;
244 return STATUS_SUCCESS
;
247 static FASTCALL NTSTATUS
248 UnpackParam(LPARAM lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
250 NCCALCSIZE_PARAMS
*UnpackedParams
;
251 NCCALCSIZE_PARAMS
*PackedParams
;
252 PWINDOWPOS UnpackedWindowPos
;
254 if (lParamPacked
== lParam
)
256 return STATUS_SUCCESS
;
259 if (WM_NCCALCSIZE
== Msg
&& wParam
)
261 PackedParams
= (NCCALCSIZE_PARAMS
*) lParamPacked
;
262 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
263 UnpackedWindowPos
= UnpackedParams
->lppos
;
264 RtlCopyMemory(UnpackedParams
, PackedParams
, sizeof(NCCALCSIZE_PARAMS
));
265 UnpackedParams
->lppos
= UnpackedWindowPos
;
266 RtlCopyMemory(UnpackedWindowPos
, PackedParams
+ 1, sizeof(WINDOWPOS
));
267 ExFreePool((PVOID
) lParamPacked
);
269 return STATUS_SUCCESS
;
271 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
273 ExFreePool((PVOID
) lParamPacked
);
275 return STATUS_SUCCESS
;
280 return STATUS_INVALID_PARAMETER
;
285 NtUserDispatchMessage(PNTUSERDISPATCHMESSAGEINFO UnsafeMsgInfo
)
288 NTUSERDISPATCHMESSAGEINFO MsgInfo
;
289 PWINDOW_OBJECT WindowObject
;
290 LRESULT Result
= TRUE
;
292 Status
= MmCopyFromCaller(&MsgInfo
, UnsafeMsgInfo
, sizeof(NTUSERDISPATCHMESSAGEINFO
));
293 if (! NT_SUCCESS(Status
))
295 SetLastNtError(Status
);
299 /* Process timer messages. */
300 if (WM_TIMER
== MsgInfo
.Msg
.message
&& 0 != MsgInfo
.Msg
.lParam
)
302 LARGE_INTEGER LargeTickCount
;
303 /* FIXME: Call hooks. */
305 /* FIXME: Check for continuing validity of timer. */
307 MsgInfo
.HandledByKernel
= FALSE
;
308 KeQueryTickCount(&LargeTickCount
);
309 MsgInfo
.Proc
= (WNDPROC
) MsgInfo
.Msg
.lParam
;
310 MsgInfo
.Msg
.lParam
= (LPARAM
)LargeTickCount
.u
.LowPart
;
312 else if (NULL
== MsgInfo
.Msg
.hwnd
)
314 MsgInfo
.HandledByKernel
= TRUE
;
319 /* Get the window object. */
320 WindowObject
= IntGetWindowObject(MsgInfo
.Msg
.hwnd
);
321 if (NULL
== WindowObject
)
323 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
324 MsgInfo
.HandledByKernel
= TRUE
;
329 if (WindowObject
->OwnerThread
!= PsGetCurrentThread())
331 IntReleaseWindowObject(WindowObject
);
332 DPRINT1("Window doesn't belong to the calling thread!\n");
333 MsgInfo
.HandledByKernel
= TRUE
;
338 /* FIXME: Call hook procedures. */
340 MsgInfo
.HandledByKernel
= FALSE
;
342 if (0xFFFF0000 != ((DWORD
) WindowObject
->WndProcW
& 0xFFFF0000))
344 if (0xFFFF0000 != ((DWORD
) WindowObject
->WndProcA
& 0xFFFF0000))
346 /* Both Unicode and Ansi winprocs are real, use whatever
348 MsgInfo
.Proc
= (MsgInfo
.Ansi
? WindowObject
->WndProcA
349 : WindowObject
->WndProcW
);
353 /* Real Unicode winproc */
354 MsgInfo
.Ansi
= FALSE
;
355 MsgInfo
.Proc
= WindowObject
->WndProcW
;
360 /* Must have real Ansi winproc */
362 MsgInfo
.Proc
= WindowObject
->WndProcA
;
365 IntReleaseWindowObject(WindowObject
);
368 Status
= MmCopyToCaller(UnsafeMsgInfo
, &MsgInfo
, sizeof(NTUSERDISPATCHMESSAGEINFO
));
369 if (! NT_SUCCESS(Status
))
371 SetLastNtError(Status
);
380 NtUserTranslateMessage(LPMSG lpMsg
,
386 Status
= MmCopyFromCaller(&SafeMsg
, lpMsg
, sizeof(MSG
));
387 if(!NT_SUCCESS(Status
))
389 SetLastNtError(Status
);
393 return IntTranslateKbdMessage(&SafeMsg
, dwhkl
);
398 IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
)
400 if(!Msg
->hwnd
|| ThreadQueue
->CaptureWindow
)
409 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
414 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
421 case WM_LBUTTONDBLCLK
:
422 case WM_MBUTTONDBLCLK
:
423 case WM_RBUTTONDBLCLK
:
424 case WM_XBUTTONDBLCLK
:
427 PSYSTEM_CURSORINFO CurInfo
;
429 if(!IntGetWindowStationObject(InputWindowStation
))
433 CurInfo
= IntGetSysCursorInfo(InputWindowStation
);
434 wParam
= (WPARAM
)(CurInfo
->ButtonsDown
);
435 ObDereferenceObject(InputWindowStation
);
437 IntSendMessage(Msg
->hwnd
, WM_MOUSEMOVE
, wParam
, Msg
->lParam
);
438 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
441 case WM_NCLBUTTONDOWN
:
442 case WM_NCMBUTTONDOWN
:
443 case WM_NCRBUTTONDOWN
:
444 case WM_NCXBUTTONDOWN
:
445 case WM_NCLBUTTONDBLCLK
:
446 case WM_NCMBUTTONDBLCLK
:
447 case WM_NCRBUTTONDBLCLK
:
448 case WM_NCXBUTTONDBLCLK
:
450 IntSendMessage(Msg
->hwnd
, WM_NCMOUSEMOVE
, (WPARAM
)Msg
->wParam
, Msg
->lParam
);
451 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
458 IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, PWINDOW_OBJECT MsgWindow
,
463 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
465 /* eat the message, search again! */
469 Result
= IntSendMessage(MsgWindow
->Self
, WM_MOUSEACTIVATE
, (WPARAM
)NtUserGetParent(MsgWindow
->Self
), (LPARAM
)MAKELONG(*HitTest
, Msg
->message
));
472 case MA_NOACTIVATEANDEAT
:
476 case MA_ACTIVATEANDEAT
:
477 IntMouseActivateWindow(MsgWindow
);
481 IntMouseActivateWindow(MsgWindow
);
489 IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, USHORT
*HitTest
, BOOL Remove
)
491 PWINDOW_OBJECT Window
;
493 if(!(Window
= IntGetWindowObject(Msg
->hwnd
)))
495 /* let's just eat the message?! */
499 if(ThreadQueue
== Window
->MessageQueue
&&
500 ThreadQueue
->CaptureWindow
!= Window
->Self
)
502 /* only send WM_NCHITTEST messages if we're not capturing the window! */
503 *HitTest
= IntSendMessage(Window
->Self
, WM_NCHITTEST
, 0,
504 MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
));
506 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
508 PWINDOW_OBJECT DesktopWindow
;
509 HWND hDesktop
= IntGetDesktopWindow();
511 if((DesktopWindow
= IntGetWindowObject(hDesktop
)))
515 WinPosWindowFromPoint(DesktopWindow
, Window
->MessageQueue
, &Msg
->pt
, &Wnd
);
520 /* post the message to the other window */
521 Msg
->hwnd
= Wnd
->Self
;
522 if(!(Wnd
->Status
& WINDOWSTATUS_DESTROYING
))
524 MsqPostMessage(Wnd
->MessageQueue
, Msg
, FALSE
);
527 /* eat the message */
528 IntReleaseWindowObject(Wnd
);
529 IntReleaseWindowObject(Window
);
530 IntReleaseWindowObject(DesktopWindow
);
533 IntReleaseWindowObject(Wnd
);
536 IntReleaseWindowObject(DesktopWindow
);
545 if(IS_BTN_MESSAGE(Msg
->message
, DOWN
))
547 /* generate double click messages, if necessary */
548 if ((((*HitTest
) != HTCLIENT
) ||
549 (IntGetClassLong(Window
, GCL_STYLE
, FALSE
) & CS_DBLCLKS
)) &&
550 MsqIsDblClk(Msg
, Remove
))
552 Msg
->message
+= WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
;
556 if(Msg
->message
!= WM_MOUSEWHEEL
)
559 if ((*HitTest
) != HTCLIENT
)
561 Msg
->message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
562 if((Msg
->message
== WM_NCRBUTTONUP
) &&
563 (((*HitTest
) == HTCAPTION
) || ((*HitTest
) == HTSYSMENU
)))
565 Msg
->message
= WM_CONTEXTMENU
;
566 Msg
->wParam
= (WPARAM
)Window
->Self
;
570 Msg
->wParam
= *HitTest
;
572 Msg
->lParam
= MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
);
574 else if(ThreadQueue
->MoveSize
== NULL
&&
575 ThreadQueue
->MenuOwner
== NULL
)
577 /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
578 Msg
->lParam
= MAKELONG(
579 Msg
->pt
.x
- (WORD
)Window
->ClientRect
.left
,
580 Msg
->pt
.y
- (WORD
)Window
->ClientRect
.top
);
584 IntReleaseWindowObject(Window
);
590 * Internal version of PeekMessage() doing all the work
593 IntPeekMessage(PUSER_MESSAGE Msg
,
599 LARGE_INTEGER LargeTickCount
;
600 PUSER_MESSAGE_QUEUE ThreadQueue
;
601 PUSER_MESSAGE Message
;
602 BOOL Present
, RemoveMessages
;
604 /* The queues and order in which they are checked are documented in the MSDN
605 article on GetMessage() */
607 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
609 /* Inspect RemoveMsg flags */
610 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
611 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
617 KeQueryTickCount(&LargeTickCount
);
618 ThreadQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
620 /* Dispatch sent messages here. */
621 while (MsqDispatchOneSentMessage(ThreadQueue
));
623 /* Now look for a quit message. */
625 if (ThreadQueue
->QuitPosted
)
627 /* According to the PSDK, WM_QUIT messages are always returned, regardless
628 of the filter specified */
629 Msg
->Msg
.hwnd
= NULL
;
630 Msg
->Msg
.message
= WM_QUIT
;
631 Msg
->Msg
.wParam
= ThreadQueue
->QuitExitCode
;
633 Msg
->FreeLParam
= FALSE
;
636 ThreadQueue
->QuitPosted
= FALSE
;
641 /* Now check for normal messages. */
642 Present
= MsqFindMessage(ThreadQueue
,
651 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
654 MsqDestroyMessage(Message
);
659 /* Check for hardware events. */
660 Present
= MsqFindMessage(ThreadQueue
,
669 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
672 MsqDestroyMessage(Message
);
677 /* Check for sent messages again. */
678 while (MsqDispatchOneSentMessage(ThreadQueue
));
680 /* Check for paint messages. */
681 if (IntGetPaintMessage(Wnd
, MsgFilterMin
, MsgFilterMax
, PsGetWin32Thread(), &Msg
->Msg
, RemoveMessages
))
683 Msg
->FreeLParam
= FALSE
;
687 /* FIXME - get WM_(SYS)TIMER messages */
695 PWINDOW_OBJECT MsgWindow
= NULL
;;
697 if(Msg
->Msg
.hwnd
&& (MsgWindow
= IntGetWindowObject(Msg
->Msg
.hwnd
)) &&
698 Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
)
702 if(IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, TRUE
))
703 /* FIXME - check message filter again, if the message doesn't match anymore,
706 IntReleaseWindowObject(MsgWindow
);
707 /* eat the message, search again */
710 if(ThreadQueue
->CaptureWindow
== NULL
)
712 IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
713 if((Msg
->Msg
.message
!= WM_MOUSEMOVE
&& Msg
->Msg
.message
!= WM_NCMOUSEMOVE
) &&
714 IS_BTN_MESSAGE(Msg
->Msg
.message
, DOWN
) &&
715 IntActivateWindowMouse(ThreadQueue
, &Msg
->Msg
, MsgWindow
, &HitTest
))
717 IntReleaseWindowObject(MsgWindow
);
718 /* eat the message, search again */
725 IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
730 IntReleaseWindowObject(MsgWindow
);
737 if((Msg
->Msg
.hwnd
&& Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
) &&
738 IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, FALSE
))
739 /* FIXME - check message filter again, if the message doesn't match anymore,
742 /* eat the message, search again */
753 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
761 NTUSERGETMESSAGEINFO Info
;
762 PWINDOW_OBJECT Window
;
763 PMSGMEMORY MsgMemoryEntry
;
771 Window
= IntGetWindowObject(Wnd
);
778 IntReleaseWindowObject(Window
);
782 if (MsgFilterMax
< MsgFilterMin
)
788 Present
= IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
);
792 /* See if this message type is present in the table */
793 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
794 if (NULL
== MsgMemoryEntry
)
796 /* Not present, no copying needed */
801 /* Determine required size */
802 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
804 /* Allocate required amount of user-mode memory */
805 Info
.LParamSize
= Size
;
807 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
808 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
809 if (! NT_SUCCESS(Status
))
811 SetLastNtError(Status
);
814 /* Transfer lParam data to user-mode mem */
815 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
816 if (! NT_SUCCESS(Status
))
818 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
819 &Info
.LParamSize
, MEM_DECOMMIT
);
820 SetLastNtError(Status
);
823 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
825 if (Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
827 ExFreePool((void *) Msg
.Msg
.lParam
);
829 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
830 if (! NT_SUCCESS(Status
))
832 SetLastNtError(Status
);
841 IntWaitMessage(HWND Wnd
,
845 PUSER_MESSAGE_QUEUE ThreadQueue
;
849 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
853 if (IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_NOREMOVE
))
858 /* Nothing found. Wait for new messages. */
859 Status
= MsqWaitForNewMessages(ThreadQueue
);
861 while (STATUS_WAIT_0
<= Status
&& Status
<= STATUS_WAIT_63
);
863 SetLastNtError(Status
);
869 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
874 * FUNCTION: Get a message from the calling thread's message queue.
876 * UnsafeMsg - Pointer to the structure which receives the returned message.
877 * Wnd - Window whose messages are to be retrieved.
878 * MsgFilterMin - Integer value of the lowest message value to be
880 * MsgFilterMax - Integer value of the highest message value to be
885 NTUSERGETMESSAGEINFO Info
;
887 PWINDOW_OBJECT Window
;
888 PMSGMEMORY MsgMemoryEntry
;
896 Window
= IntGetWindowObject(Wnd
);
900 IntReleaseWindowObject(Window
);
902 if (MsgFilterMax
< MsgFilterMin
)
910 GotMessage
= IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
);
914 /* See if this message type is present in the table */
915 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
916 if (NULL
== MsgMemoryEntry
)
918 /* Not present, no copying needed */
923 /* Determine required size */
924 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
926 /* Allocate required amount of user-mode memory */
927 Info
.LParamSize
= Size
;
929 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
930 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
932 if (! NT_SUCCESS(Status
))
934 SetLastNtError(Status
);
937 /* Transfer lParam data to user-mode mem */
938 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
939 if (! NT_SUCCESS(Status
))
941 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
942 &Info
.LParamSize
, MEM_DECOMMIT
);
943 SetLastNtError(Status
);
946 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
948 if (Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
950 ExFreePool((void *) Msg
.Msg
.lParam
);
952 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
953 if (! NT_SUCCESS(Status
))
955 SetLastNtError(Status
);
959 else if (! IntWaitMessage(Wnd
, MsgFilterMin
, MsgFilterMax
))
964 while (! GotMessage
);
966 return WM_QUIT
!= Info
.Msg
.message
;
985 static NTSTATUS FASTCALL
986 CopyMsgToKernelMem(MSG
*KernelModeMsg
, MSG
*UserModeMsg
, PMSGMEMORY MsgMemoryEntry
)
993 *KernelModeMsg
= *UserModeMsg
;
995 /* See if this message type is present in the table */
996 if (NULL
== MsgMemoryEntry
)
998 /* Not present, no copying needed */
999 return STATUS_SUCCESS
;
1002 /* Determine required size */
1003 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1007 /* Allocate kernel mem */
1008 KernelMem
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
1009 if (NULL
== KernelMem
)
1011 DPRINT1("Not enough memory to copy message to kernel mem\n");
1012 return STATUS_NO_MEMORY
;
1014 KernelModeMsg
->lParam
= (LPARAM
) KernelMem
;
1016 /* Copy data if required */
1017 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_READ
))
1019 Status
= MmCopyFromCaller(KernelMem
, (PVOID
) UserModeMsg
->lParam
, Size
);
1020 if (! NT_SUCCESS(Status
))
1022 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
1023 ExFreePool(KernelMem
);
1029 /* Make sure we don't pass any secrets to usermode */
1030 RtlZeroMemory(KernelMem
, Size
);
1035 KernelModeMsg
->lParam
= 0;
1038 return STATUS_SUCCESS
;
1041 static NTSTATUS FASTCALL
1042 CopyMsgToUserMem(MSG
*UserModeMsg
, MSG
*KernelModeMsg
)
1045 PMSGMEMORY MsgMemoryEntry
;
1048 /* See if this message type is present in the table */
1049 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
1050 if (NULL
== MsgMemoryEntry
)
1052 /* Not present, no copying needed */
1053 return STATUS_SUCCESS
;
1056 /* Determine required size */
1057 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1061 /* Copy data if required */
1062 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_WRITE
))
1064 Status
= MmCopyToCaller((PVOID
) UserModeMsg
->lParam
, (PVOID
) KernelModeMsg
->lParam
, Size
);
1065 if (! NT_SUCCESS(Status
))
1067 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1068 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1073 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1076 return STATUS_SUCCESS
;
1080 NtUserPostMessage(HWND Wnd
,
1085 PWINDOW_OBJECT Window
;
1086 MSG UserModeMsg
, KernelModeMsg
;
1087 LARGE_INTEGER LargeTickCount
;
1089 PMSGMEMORY MsgMemoryEntry
;
1093 MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue
, wParam
);
1095 else if (Wnd
== HWND_BROADCAST
)
1098 PWINDOW_OBJECT DesktopWindow
;
1101 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
1102 List
= IntWinListChildren(DesktopWindow
);
1103 IntReleaseWindowObject(DesktopWindow
);
1106 for (i
= 0; List
[i
]; i
++)
1107 NtUserPostMessage(List
[i
], Msg
, wParam
, lParam
);
1113 PSYSTEM_CURSORINFO CurInfo
;
1114 Window
= IntGetWindowObject(Wnd
);
1117 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1120 if(Window
->Status
& WINDOWSTATUS_DESTROYING
)
1122 IntReleaseWindowObject(Window
);
1123 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd
);
1124 /* FIXME - last error code? */
1128 UserModeMsg
.hwnd
= Wnd
;
1129 UserModeMsg
.message
= Msg
;
1130 UserModeMsg
.wParam
= wParam
;
1131 UserModeMsg
.lParam
= lParam
;
1132 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1133 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1134 if (! NT_SUCCESS(Status
))
1136 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1139 CurInfo
= IntGetSysCursorInfo(PsGetWin32Thread()->Desktop
->WindowStation
);
1140 KernelModeMsg
.pt
.x
= CurInfo
->x
;
1141 KernelModeMsg
.pt
.y
= CurInfo
->y
;
1142 KeQueryTickCount(&LargeTickCount
);
1143 KernelModeMsg
.time
= LargeTickCount
.u
.LowPart
;
1144 MsqPostMessage(Window
->MessageQueue
, &KernelModeMsg
,
1145 NULL
!= MsgMemoryEntry
&& 0 != KernelModeMsg
.lParam
);
1146 IntReleaseWindowObject(Window
);
1153 NtUserPostThreadMessage(DWORD idThread
,
1158 MSG UserModeMsg
, KernelModeMsg
;
1162 PMSGMEMORY MsgMemoryEntry
;
1164 Status
= PsLookupThreadByThreadId((void *)idThread
,&peThread
);
1166 if( Status
== STATUS_SUCCESS
) {
1167 pThread
= peThread
->Tcb
.Win32Thread
;
1168 if( !pThread
|| !pThread
->MessageQueue
)
1170 ObDereferenceObject( peThread
);
1174 UserModeMsg
.hwnd
= NULL
;
1175 UserModeMsg
.message
= Msg
;
1176 UserModeMsg
.wParam
= wParam
;
1177 UserModeMsg
.lParam
= lParam
;
1178 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1179 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1180 if (! NT_SUCCESS(Status
))
1182 ObDereferenceObject( peThread
);
1183 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1186 MsqPostMessage(pThread
->MessageQueue
, &KernelModeMsg
,
1187 NULL
!= MsgMemoryEntry
&& 0 != KernelModeMsg
.lParam
);
1188 ObDereferenceObject( peThread
);
1191 SetLastNtError( Status
);
1197 NtUserQuerySendMessage(DWORD Unknown0
)
1205 IntSendMessage(HWND hWnd
,
1210 ULONG_PTR Result
= 0;
1211 if(IntSendMessageTimeout(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1213 return (LRESULT
)Result
;
1218 static LRESULT FASTCALL
1219 IntSendMessageTimeoutSingle(HWND hWnd
,
1229 PWINDOW_OBJECT Window
;
1230 PMSGMEMORY MsgMemoryEntry
;
1231 INT lParamBufferSize
;
1232 LPARAM lParamPacked
;
1233 PW32THREAD Win32Thread
;
1235 /* FIXME: Call hooks. */
1236 Window
= IntGetWindowObject(hWnd
);
1239 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1243 Win32Thread
= PsGetWin32Thread();
1245 if (NULL
!= Win32Thread
&&
1246 Window
->MessageQueue
== Win32Thread
->MessageQueue
)
1248 if (Win32Thread
->IsExiting
)
1250 /* Never send messages to exiting threads */
1251 IntReleaseWindowObject(Window
);
1255 /* See if this message type is present in the table */
1256 MsgMemoryEntry
= FindMsgMemory(Msg
);
1257 if (NULL
== MsgMemoryEntry
)
1259 lParamBufferSize
= -1;
1263 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
1266 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
)))
1268 IntReleaseWindowObject(Window
);
1269 DPRINT1("Failed to pack message parameters\n");
1272 if (0xFFFF0000 != ((DWORD
) Window
->WndProcW
& 0xFFFF0000))
1274 Result
= (ULONG_PTR
)IntCallWindowProc(Window
->WndProcW
, FALSE
, hWnd
, Msg
, wParam
,
1275 lParamPacked
,lParamBufferSize
);
1279 Result
= (ULONG_PTR
)IntCallWindowProc(Window
->WndProcA
, TRUE
, hWnd
, Msg
, wParam
,
1280 lParamPacked
,lParamBufferSize
);
1288 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
)))
1290 IntReleaseWindowObject(Window
);
1291 DPRINT1("Failed to unpack message parameters\n");
1295 IntReleaseWindowObject(Window
);
1299 if(uFlags
& SMTO_ABORTIFHUNG
&& MsqIsHung(Window
->MessageQueue
))
1301 IntReleaseWindowObject(Window
);
1302 /* FIXME - Set a LastError? */
1306 if(Window
->Status
& WINDOWSTATUS_DESTROYING
)
1308 IntReleaseWindowObject(Window
);
1309 /* FIXME - last error? */
1310 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd
);
1314 Status
= MsqSendMessage(Window
->MessageQueue
, hWnd
, Msg
, wParam
, lParam
,
1315 uTimeout
, (uFlags
& SMTO_BLOCK
), uResult
);
1316 IntReleaseWindowObject(Window
);
1317 if (STATUS_TIMEOUT
== Status
)
1319 /* MSDN says GetLastError() should return 0 after timeout */
1320 SetLastWin32Error(0);
1323 else if (! NT_SUCCESS(Status
))
1325 SetLastNtError(Status
);
1333 IntSendMessageTimeout(HWND hWnd
,
1341 PWINDOW_OBJECT DesktopWindow
;
1345 if (HWND_BROADCAST
!= hWnd
)
1347 return IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1350 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
1351 if (NULL
== DesktopWindow
)
1353 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1356 Children
= IntWinListChildren(DesktopWindow
);
1357 IntReleaseWindowObject(DesktopWindow
);
1358 if (NULL
== Children
)
1363 for (Child
= Children
; NULL
!= *Child
; Child
++)
1365 IntSendMessageTimeoutSingle(*Child
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1368 ExFreePool(Children
);
1370 return (LRESULT
) TRUE
;
1374 /* This function posts a message if the destination's message queue belongs to
1375 another thread, otherwise it sends the message. It does not support broadcast
1378 IntPostOrSendMessage(HWND hWnd
,
1384 PWINDOW_OBJECT Window
;
1386 if(hWnd
== HWND_BROADCAST
)
1391 Window
= IntGetWindowObject(hWnd
);
1394 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1398 if(Window
->MessageQueue
!= PsGetWin32Thread()->MessageQueue
)
1400 Result
= NtUserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1404 if(!IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1410 IntReleaseWindowObject(Window
);
1412 return (LRESULT
)Result
;
1416 IntDoSendMessage(HWND Wnd
,
1421 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1423 LRESULT Result
= TRUE
;
1425 PWINDOW_OBJECT Window
;
1426 NTUSERSENDMESSAGEINFO Info
;
1429 PMSGMEMORY MsgMemoryEntry
;
1431 RtlZeroMemory(&Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1433 /* FIXME: Call hooks. */
1434 if (HWND_BROADCAST
!= Wnd
)
1436 Window
= IntGetWindowObject(Wnd
);
1439 /* Tell usermode to not touch this one */
1440 Info
.HandledByKernel
= TRUE
;
1441 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1442 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1447 /* FIXME: Check for an exiting window. */
1449 /* See if the current thread can handle the message */
1450 if (HWND_BROADCAST
!= Wnd
&& NULL
!= PsGetWin32Thread() &&
1451 Window
->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
1453 /* Gather the information usermode needs to call the window proc directly */
1454 Info
.HandledByKernel
= FALSE
;
1455 if (0xFFFF0000 != ((DWORD
) Window
->WndProcW
& 0xFFFF0000))
1457 if (0xFFFF0000 != ((DWORD
) Window
->WndProcA
& 0xFFFF0000))
1459 /* Both Unicode and Ansi winprocs are real, see what usermode prefers */
1460 Status
= MmCopyFromCaller(&(Info
.Ansi
), &(UnsafeInfo
->Ansi
),
1462 if (! NT_SUCCESS(Status
))
1464 Info
.Ansi
= ! Window
->Unicode
;
1466 Info
.Proc
= (Info
.Ansi
? Window
->WndProcA
: Window
->WndProcW
);
1470 /* Real Unicode winproc */
1472 Info
.Proc
= Window
->WndProcW
;
1477 /* Must have real Ansi winproc */
1479 Info
.Proc
= Window
->WndProcA
;
1481 IntReleaseWindowObject(Window
);
1485 /* Must be handled by other thread */
1486 if (HWND_BROADCAST
!= Wnd
)
1488 IntReleaseWindowObject(Window
);
1490 Info
.HandledByKernel
= TRUE
;
1491 UserModeMsg
.hwnd
= Wnd
;
1492 UserModeMsg
.message
= Msg
;
1493 UserModeMsg
.wParam
= wParam
;
1494 UserModeMsg
.lParam
= lParam
;
1495 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1496 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1497 if (! NT_SUCCESS(Status
))
1499 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1500 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1501 return (dsm
? 0 : -1);
1505 Result
= IntSendMessage(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1506 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
);
1510 Result
= IntSendMessageTimeout(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1511 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
,
1512 dsm
->uFlags
, dsm
->uTimeout
, &dsm
->Result
);
1514 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
1515 if (! NT_SUCCESS(Status
))
1517 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1518 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1519 return(dsm
? 0 : -1);
1523 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1524 if (! NT_SUCCESS(Status
))
1526 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1529 return (LRESULT
)Result
;
1533 NtUserSendMessageTimeout(HWND hWnd
,
1540 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1545 dsm
.uFlags
= uFlags
;
1546 dsm
.uTimeout
= uTimeout
;
1547 Result
= IntDoSendMessage(hWnd
, Msg
, wParam
, lParam
, &dsm
, UnsafeInfo
);
1548 if(uResult
!= NULL
&& Result
!= 0)
1552 Status
= MmCopyToCaller(uResult
, &dsm
.Result
, sizeof(ULONG_PTR
));
1553 if(!NT_SUCCESS(Status
))
1555 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1563 NtUserSendMessage(HWND Wnd
,
1567 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1569 return IntDoSendMessage(Wnd
, Msg
, wParam
, lParam
, NULL
, UnsafeInfo
);
1573 NtUserSendMessageCallback(HWND hWnd
,
1577 SENDASYNCPROC lpCallBack
,
1586 NtUserSendNotifyMessage(HWND hWnd
,
1597 NtUserWaitMessage(VOID
)
1600 return IntWaitMessage(NULL
, 0, 0);
1604 NtUserGetQueueStatus(BOOL ClearChanges
)
1606 PUSER_MESSAGE_QUEUE Queue
;
1609 Queue
= PsGetWin32Thread()->MessageQueue
;
1611 IntLockMessageQueue(Queue
);
1613 Result
= MAKELONG(Queue
->ChangedBits
, Queue
->WakeBits
);
1616 Queue
->ChangedBits
= 0;
1619 IntUnLockMessageQueue(Queue
);
1625 IntInitMessagePumpHook()
1627 PsGetCurrentThread()->Tcb
.Win32Thread
->MessagePumpHookValue
++;
1632 IntUninitMessagePumpHook()
1634 if (PsGetCurrentThread()->Tcb
.Win32Thread
->MessagePumpHookValue
<= 0)
1638 PsGetCurrentThread()->Tcb
.Win32Thread
->MessagePumpHookValue
--;