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.53 2004/03/11 14:47:44 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 ******************************************************************/
32 #include <ddk/ntddk.h>
33 #include <win32k/win32k.h>
34 #include <include/msgqueue.h>
35 #include <include/window.h>
36 #include <include/class.h>
37 #include <include/error.h>
38 #include <include/object.h>
39 #include <include/winsta.h>
40 #include <include/callback.h>
41 #include <include/painting.h>
42 #include <include/input.h>
43 #include <include/desktop.h>
44 #include <include/tags.h>
45 #include <internal/safe.h>
55 } DOSENDMESSAGE
, *PDOSENDMESSAGE
;
57 /* FUNCTIONS *****************************************************************/
60 IntInitMessageImpl(VOID
)
62 return STATUS_SUCCESS
;
66 IntCleanupMessageImpl(VOID
)
68 return STATUS_SUCCESS
;
72 IntDispatchMessage(MSG
* Msg
)
75 PWINDOW_OBJECT WindowObject
;
76 /* Process timer messages. */
77 if (Msg
->message
== WM_TIMER
)
81 LARGE_INTEGER LargeTickCount
;
82 /* FIXME: Call hooks. */
84 /* FIXME: Check for continuing validity of timer. */
86 KeQueryTickCount(&LargeTickCount
);
87 return IntCallWindowProc((WNDPROC
)Msg
->lParam
,
92 (LPARAM
)LargeTickCount
.u
.LowPart
,
97 if( Msg
->hwnd
== 0 ) return 0;
99 /* Get the window object. */
100 WindowObject
= IntGetWindowObject(Msg
->hwnd
);
103 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
106 if(WindowObject
->OwnerThread
!= PsGetCurrentThread())
108 IntReleaseWindowObject(WindowObject
);
109 DPRINT("Window doesn't belong to the calling thread!\n");
112 /* FIXME: Call hook procedures. */
114 /* Call the window procedure. */
115 if (0xFFFF0000 != ((DWORD
) WindowObject
->WndProcW
& 0xFFFF0000))
117 Result
= IntCallWindowProc(WindowObject
->WndProcW
,
127 Result
= IntCallWindowProc(WindowObject
->WndProcA
,
136 IntReleaseWindowObject(WindowObject
);
143 NtUserDispatchMessage(CONST MSG
* UnsafeMsg
)
148 Status
= MmCopyFromCaller(&Msg
, (PVOID
) UnsafeMsg
, sizeof(MSG
));
149 if (! NT_SUCCESS(Status
))
151 SetLastNtError(Status
);
155 return IntDispatchMessage(&Msg
);
160 NtUserTranslateMessage(LPMSG lpMsg
,
166 Status
= MmCopyFromCaller(&SafeMsg
, lpMsg
, sizeof(MSG
));
167 if(!NT_SUCCESS(Status
))
169 SetLastNtError(Status
);
173 return IntTranslateKbdMessage(&SafeMsg
, dwhkl
);
178 IntSendSpecialMessages(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
)
180 if(!Msg
->hwnd
|| ThreadQueue
->CaptureWindow
)
189 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
194 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
201 case WM_LBUTTONDBLCLK
:
202 case WM_MBUTTONDBLCLK
:
203 case WM_RBUTTONDBLCLK
:
204 case WM_XBUTTONDBLCLK
:
208 if(!IntGetWindowStationObject(InputWindowStation
))
212 wParam
= (WPARAM
)InputWindowStation
->SystemCursor
.ButtonsDown
;
213 ObDereferenceObject(InputWindowStation
);
215 IntSendMessage(Msg
->hwnd
, WM_MOUSEMOVE
, wParam
, Msg
->lParam
);
216 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
219 case WM_NCLBUTTONDOWN
:
220 case WM_NCMBUTTONDOWN
:
221 case WM_NCRBUTTONDOWN
:
222 case WM_NCXBUTTONDOWN
:
223 case WM_NCLBUTTONDBLCLK
:
224 case WM_NCMBUTTONDBLCLK
:
225 case WM_NCRBUTTONDBLCLK
:
226 case WM_NCXBUTTONDBLCLK
:
228 IntSendMessage(Msg
->hwnd
, WM_NCMOUSEMOVE
, (WPARAM
)Msg
->wParam
, Msg
->lParam
);
229 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
236 * Internal version of PeekMessage() doing all the work
239 IntPeekMessage(LPMSG Msg
,
245 LARGE_INTEGER LargeTickCount
;
246 PUSER_MESSAGE_QUEUE ThreadQueue
;
248 PUSER_MESSAGE Message
;
249 BOOLEAN RemoveMessages
;
251 /* The queues and order in which they are checked are documented in the MSDN
252 article on GetMessage() */
254 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
256 KeQueryTickCount(&LargeTickCount
);
257 ThreadQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
259 /* Inspect RemoveMsg flags */
260 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
261 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
263 /* Dispatch sent messages here. */
264 while (MsqDispatchOneSentMessage(ThreadQueue
))
267 /* Now look for a quit message. */
268 /* FIXME: WINE checks the message number filter here. */
269 if (ThreadQueue
->QuitPosted
)
272 Msg
->message
= WM_QUIT
;
273 Msg
->wParam
= ThreadQueue
->QuitExitCode
;
277 ThreadQueue
->QuitPosted
= FALSE
;
282 /* Now check for normal messages. */
283 Present
= MsqFindMessage(ThreadQueue
,
292 RtlCopyMemory(Msg
, &Message
->Msg
, sizeof(MSG
));
295 MsqDestroyMessage(Message
);
296 IntSendSpecialMessages(ThreadQueue
, Msg
);
301 /* Check for hardware events. */
302 Present
= MsqFindMessage(ThreadQueue
,
311 RtlCopyMemory(Msg
, &Message
->Msg
, sizeof(MSG
));
314 MsqDestroyMessage(Message
);
315 IntSendSpecialMessages(ThreadQueue
, Msg
);
320 /* Check for sent messages again. */
321 while (MsqDispatchOneSentMessage(ThreadQueue
))
324 /* Check for paint messages. */
325 if (IntGetPaintMessage(Wnd
, PsGetWin32Thread(), Msg
, RemoveMessages
))
334 NtUserPeekMessage(LPMSG UnsafeMsg
,
343 PWINDOW_OBJECT Window
;
348 Window
= IntGetWindowObject(Wnd
);
352 IntReleaseWindowObject(Window
);
354 if (MsgFilterMax
< MsgFilterMin
)
360 Present
= IntPeekMessage(&SafeMsg
, Wnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
);
363 Status
= MmCopyToCaller(UnsafeMsg
, &SafeMsg
, sizeof(MSG
));
364 if (! NT_SUCCESS(Status
))
366 /* There is error return documented for PeekMessage().
367 Do the best we can */
368 SetLastNtError(Status
);
377 IntWaitMessage(HWND Wnd
,
381 PUSER_MESSAGE_QUEUE ThreadQueue
;
385 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
389 if (IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_NOREMOVE
))
394 /* Nothing found. Wait for new messages. */
395 Status
= MsqWaitForNewMessages(ThreadQueue
);
397 while (STATUS_WAIT_0
<= STATUS_WAIT_0
&& Status
<= STATUS_WAIT_63
);
399 SetLastNtError(Status
);
405 NtUserGetMessage(LPMSG UnsafeMsg
,
410 * FUNCTION: Get a message from the calling thread's message queue.
412 * UnsafeMsg - Pointer to the structure which receives the returned message.
413 * Wnd - Window whose messages are to be retrieved.
414 * MsgFilterMin - Integer value of the lowest message value to be
416 * MsgFilterMax - Integer value of the highest message value to be
423 PWINDOW_OBJECT Window
;
428 Window
= IntGetWindowObject(Wnd
);
432 IntReleaseWindowObject(Window
);
434 if (MsgFilterMax
< MsgFilterMin
)
442 GotMessage
= IntPeekMessage(&SafeMsg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
);
445 Status
= MmCopyToCaller(UnsafeMsg
, &SafeMsg
, sizeof(MSG
));
446 if (! NT_SUCCESS(Status
))
448 SetLastNtError(Status
);
454 IntWaitMessage(Wnd
, MsgFilterMin
, MsgFilterMax
);
457 while (! GotMessage
);
459 return WM_QUIT
!= SafeMsg
.message
;
479 NtUserPostMessage(HWND hWnd
,
484 PWINDOW_OBJECT Window
;
486 PUSER_MESSAGE Message
;
487 LARGE_INTEGER LargeTickCount
;
491 MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue
, wParam
);
493 else if (hWnd
== HWND_BROADCAST
)
496 PWINDOW_OBJECT DesktopWindow
;
499 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
500 List
= IntWinListChildren(DesktopWindow
);
501 IntReleaseWindowObject(DesktopWindow
);
504 for (i
= 0; List
[i
]; i
++)
505 NtUserPostMessage(List
[i
], Msg
, wParam
, lParam
);
511 Window
= IntGetWindowObject(hWnd
);
514 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
519 Mesg
.wParam
= wParam
;
520 Mesg
.lParam
= lParam
;
521 Mesg
.pt
.x
= PsGetWin32Process()->WindowStation
->SystemCursor
.x
;
522 Mesg
.pt
.y
= PsGetWin32Process()->WindowStation
->SystemCursor
.y
;
523 KeQueryTickCount(&LargeTickCount
);
524 Mesg
.time
= LargeTickCount
.u
.LowPart
;
525 Message
= MsqCreateMessage(&Mesg
);
526 MsqPostMessage(Window
->MessageQueue
, Message
);
527 IntReleaseWindowObject(Window
);
534 NtUserPostThreadMessage(DWORD idThread
,
541 PUSER_MESSAGE Message
;
546 Status
= PsLookupThreadByThreadId((void *)idThread
,&peThread
);
548 if( Status
== STATUS_SUCCESS
) {
549 pThread
= peThread
->Win32Thread
;
550 if( !pThread
|| !pThread
->MessageQueue
)
552 ObDereferenceObject( peThread
);
557 Mesg
.wParam
= wParam
;
558 Mesg
.lParam
= lParam
;
559 Message
= MsqCreateMessage(&Mesg
);
560 MsqPostMessage(pThread
->MessageQueue
, Message
);
561 ObDereferenceObject( peThread
);
564 SetLastNtError( Status
);
570 NtUserQuerySendMessage(DWORD Unknown0
)
577 #define MMS_SIZE_WPARAM -1
578 #define MMS_SIZE_WPARAMWCHAR -2
579 #define MMS_SIZE_LPARAMSZ -3
580 #define MMS_SIZE_SPECIAL -4
581 #define MMS_FLAG_READ 0x01
582 #define MMS_FLAG_WRITE 0x02
583 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
584 typedef struct tagMSGMEMORY
589 } MSGMEMORY
, *PMSGMEMORY
;
591 static MSGMEMORY MsgMemory
[] =
593 { WM_CREATE
, sizeof(CREATESTRUCTW
), MMS_FLAG_READWRITE
},
594 { WM_GETMINMAXINFO
, sizeof(MINMAXINFO
), MMS_FLAG_READWRITE
},
595 { WM_GETTEXT
, MMS_SIZE_WPARAMWCHAR
, MMS_FLAG_WRITE
},
596 { WM_NCCALCSIZE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
597 { WM_NCCREATE
, sizeof(CREATESTRUCTW
), MMS_FLAG_READWRITE
},
598 { WM_SETTEXT
, MMS_SIZE_LPARAMSZ
, MMS_FLAG_READ
},
599 { WM_STYLECHANGED
, sizeof(STYLESTRUCT
), MMS_FLAG_READ
},
600 { WM_STYLECHANGING
, sizeof(STYLESTRUCT
), MMS_FLAG_READWRITE
},
601 { WM_WINDOWPOSCHANGED
, sizeof(WINDOWPOS
), MMS_FLAG_READ
},
602 { WM_WINDOWPOSCHANGING
, sizeof(WINDOWPOS
), MMS_FLAG_READWRITE
},
605 static PMSGMEMORY FASTCALL
606 FindMsgMemory(UINT Msg
)
608 PMSGMEMORY MsgMemoryEntry
;
610 /* See if this message type is present in the table */
611 for (MsgMemoryEntry
= MsgMemory
;
612 MsgMemoryEntry
< MsgMemory
+ sizeof(MsgMemory
) / sizeof(MSGMEMORY
);
615 if (Msg
== MsgMemoryEntry
->Message
)
617 return MsgMemoryEntry
;
625 MsgMemorySize(PMSGMEMORY MsgMemoryEntry
, WPARAM wParam
, LPARAM lParam
)
627 if (MMS_SIZE_WPARAM
== MsgMemoryEntry
->Size
)
629 return (UINT
) wParam
;
631 else if (MMS_SIZE_WPARAMWCHAR
== MsgMemoryEntry
->Size
)
633 return (UINT
) (wParam
* sizeof(WCHAR
));
635 else if (MMS_SIZE_LPARAMSZ
== MsgMemoryEntry
->Size
)
637 return (UINT
) ((wcslen((PWSTR
) lParam
) + 1) * sizeof(WCHAR
));
639 else if (MMS_SIZE_SPECIAL
== MsgMemoryEntry
->Size
)
641 switch(MsgMemoryEntry
->Message
)
644 return wParam
? sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
) : sizeof(RECT
);
654 return MsgMemoryEntry
->Size
;
658 static FASTCALL NTSTATUS
659 PackParam(LPARAM
*lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
661 NCCALCSIZE_PARAMS
*UnpackedParams
;
662 NCCALCSIZE_PARAMS
*PackedParams
;
664 *lParamPacked
= lParam
;
665 if (WM_NCCALCSIZE
== Msg
&& wParam
)
667 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
668 if (UnpackedParams
->lppos
!= (PWINDOWPOS
) (UnpackedParams
+ 1))
670 PackedParams
= ExAllocatePoolWithTag(PagedPool
,
671 sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
),
673 if (NULL
== PackedParams
)
675 DPRINT1("Not enough memory to pack lParam\n");
676 return STATUS_NO_MEMORY
;
678 RtlCopyMemory(PackedParams
, UnpackedParams
, sizeof(NCCALCSIZE_PARAMS
));
679 PackedParams
->lppos
= (PWINDOWPOS
) (PackedParams
+ 1);
680 RtlCopyMemory(PackedParams
->lppos
, UnpackedParams
->lppos
, sizeof(WINDOWPOS
));
681 *lParamPacked
= (LPARAM
) PackedParams
;
685 return STATUS_SUCCESS
;
688 static FASTCALL NTSTATUS
689 UnpackParam(LPARAM lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
691 NCCALCSIZE_PARAMS
*UnpackedParams
;
692 NCCALCSIZE_PARAMS
*PackedParams
;
693 PWINDOWPOS UnpackedWindowPos
;
695 if (lParamPacked
== lParam
)
697 return STATUS_SUCCESS
;
700 if (WM_NCCALCSIZE
== Msg
&& wParam
)
702 PackedParams
= (NCCALCSIZE_PARAMS
*) lParamPacked
;
703 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
704 UnpackedWindowPos
= UnpackedParams
->lppos
;
705 RtlCopyMemory(UnpackedParams
, PackedParams
, sizeof(NCCALCSIZE_PARAMS
));
706 UnpackedParams
->lppos
= UnpackedWindowPos
;
707 RtlCopyMemory(UnpackedWindowPos
, PackedParams
+ 1, sizeof(WINDOWPOS
));
708 ExFreePool((PVOID
) lParamPacked
);
710 return STATUS_SUCCESS
;
715 return STATUS_INVALID_PARAMETER
;
719 IntSendMessage(HWND hWnd
,
725 if(IntSendMessageTimeout(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
733 IntSendMessageTimeout(HWND hWnd
,
743 PWINDOW_OBJECT Window
;
744 PMSGMEMORY MsgMemoryEntry
;
745 INT lParamBufferSize
;
747 PW32THREAD Win32Thread
;
749 /* FIXME: Check for a broadcast or topmost destination. */
751 /* FIXME: Call hooks. */
752 Window
= IntGetWindowObject(hWnd
);
755 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
759 Win32Thread
= PsGetWin32Thread();
761 if (NULL
!= Win32Thread
&&
762 Window
->MessageQueue
== Win32Thread
->MessageQueue
)
764 if (Win32Thread
->IsExiting
)
766 /* Never send messages to exiting threads */
767 IntReleaseWindowObject(Window
);
771 /* See if this message type is present in the table */
772 MsgMemoryEntry
= FindMsgMemory(Msg
);
773 if (NULL
== MsgMemoryEntry
)
775 lParamBufferSize
= -1;
779 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
782 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
)))
784 IntReleaseWindowObject(Window
);
785 DPRINT1("Failed to pack message parameters\n");
788 if (0xFFFF0000 != ((DWORD
) Window
->WndProcW
& 0xFFFF0000))
790 Result
= IntCallWindowProc(Window
->WndProcW
, FALSE
, hWnd
, Msg
, wParam
,
791 lParamPacked
,lParamBufferSize
);
795 Result
= IntCallWindowProc(Window
->WndProcA
, TRUE
, hWnd
, Msg
, wParam
,
796 lParamPacked
,lParamBufferSize
);
798 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
)))
800 IntReleaseWindowObject(Window
);
801 DPRINT1("Failed to unpack message parameters\n");
807 IntReleaseWindowObject(Window
);
813 if(uFlags
& SMTO_ABORTIFHUNG
&& MsqIsHung(Window
->MessageQueue
))
815 IntReleaseWindowObject(Window
);
816 /* FIXME - Set a LastError? */
820 Status
= MsqSendMessage(Window
->MessageQueue
, hWnd
, Msg
, wParam
, lParam
,
821 (uFlags
& SMTO_BLOCK
), uTimeout
, &Result
);
822 if(Status
== STATUS_TIMEOUT
)
824 IntReleaseWindowObject(Window
);
825 SetLastWin32Error(ERROR_TIMEOUT
);
829 IntReleaseWindowObject(Window
);
835 static NTSTATUS FASTCALL
836 CopyMsgToKernelMem(MSG
*KernelModeMsg
, MSG
*UserModeMsg
)
839 PMSGMEMORY MsgMemoryEntry
;
843 *KernelModeMsg
= *UserModeMsg
;
845 /* See if this message type is present in the table */
846 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
847 if (NULL
== MsgMemoryEntry
)
849 /* Not present, no copying needed */
850 return STATUS_SUCCESS
;
853 /* Determine required size */
854 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
858 /* Allocate kernel mem */
859 KernelMem
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
860 if (NULL
== KernelMem
)
862 DPRINT1("Not enough memory to copy message to kernel mem\n");
863 return STATUS_NO_MEMORY
;
865 KernelModeMsg
->lParam
= (LPARAM
) KernelMem
;
867 /* Copy data if required */
868 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_READ
))
870 Status
= MmCopyFromCaller(KernelMem
, (PVOID
) UserModeMsg
->lParam
, Size
);
871 if (! NT_SUCCESS(Status
))
873 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
874 ExFreePool(KernelMem
);
880 /* Make sure we don't pass any secrets to usermode */
881 RtlZeroMemory(KernelMem
, Size
);
886 KernelModeMsg
->lParam
= 0;
889 return STATUS_SUCCESS
;
892 static NTSTATUS FASTCALL
893 CopyMsgToUserMem(MSG
*UserModeMsg
, MSG
*KernelModeMsg
)
896 PMSGMEMORY MsgMemoryEntry
;
899 /* See if this message type is present in the table */
900 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
901 if (NULL
== MsgMemoryEntry
)
903 /* Not present, no copying needed */
904 return STATUS_SUCCESS
;
907 /* Determine required size */
908 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
912 /* Copy data if required */
913 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_WRITE
))
915 Status
= MmCopyToCaller((PVOID
) UserModeMsg
->lParam
, (PVOID
) KernelModeMsg
->lParam
, Size
);
916 if (! NT_SUCCESS(Status
))
918 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
919 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
924 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
927 return STATUS_SUCCESS
;
931 IntDoSendMessage(HWND Wnd
,
936 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
940 PWINDOW_OBJECT Window
;
941 NTUSERSENDMESSAGEINFO Info
;
945 /* FIXME: Check for a broadcast or topmost destination. */
947 RtlZeroMemory(&Info
, sizeof(NTUSERSENDMESSAGEINFO
));
949 /* FIXME: Call hooks. */
950 Window
= IntGetWindowObject(Wnd
);
953 /* Tell usermode to not touch this one */
954 Info
.HandledByKernel
= TRUE
;
955 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
956 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
960 /* FIXME: Check for an exiting window. */
962 /* See if the current thread can handle the message */
963 if (NULL
!= PsGetWin32Thread() &&
964 Window
->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
966 /* Gather the information usermode needs to call the window proc directly */
967 Info
.HandledByKernel
= FALSE
;
968 if (0xFFFF0000 != ((DWORD
) Window
->WndProcW
& 0xFFFF0000))
970 if (0xFFFF0000 != ((DWORD
) Window
->WndProcA
& 0xFFFF0000))
972 /* Both Unicode and Ansi winprocs are real, see what usermode prefers */
973 Status
= MmCopyFromCaller(&(Info
.Ansi
), &(UnsafeInfo
->Ansi
),
975 if (! NT_SUCCESS(Status
))
977 Info
.Ansi
= ! Window
->Unicode
;
979 Info
.Proc
= (Info
.Ansi
? Window
->WndProcA
: Window
->WndProcW
);
983 /* Real Unicode winproc */
985 Info
.Proc
= Window
->WndProcW
;
990 /* Must have real Ansi winproc */
992 Info
.Proc
= Window
->WndProcA
;
994 IntReleaseWindowObject(Window
);
998 /* Must be handled by other thread */
999 IntReleaseWindowObject(Window
);
1000 Info
.HandledByKernel
= TRUE
;
1001 UserModeMsg
.hwnd
= Wnd
;
1002 UserModeMsg
.message
= Msg
;
1003 UserModeMsg
.wParam
= wParam
;
1004 UserModeMsg
.lParam
= lParam
;
1005 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
);
1006 if (! NT_SUCCESS(Status
))
1008 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1009 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1010 return (dsm
? 0 : -1);
1014 Result
= IntSendMessage(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1015 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
);
1019 Result
= IntSendMessageTimeout(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1020 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
,
1021 dsm
->uFlags
, dsm
->uTimeout
, &dsm
->uResult
);
1023 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
1024 if (! NT_SUCCESS(Status
))
1026 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1027 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1028 return(dsm
? 0 : -1);
1032 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1033 if (! NT_SUCCESS(Status
))
1035 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1042 NtUserSendMessageTimeout(HWND hWnd
,
1049 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1054 dsm
.uFlags
= uFlags
;
1055 dsm
.uTimeout
= uTimeout
;
1056 Result
= IntDoSendMessage(hWnd
, Msg
, wParam
, lParam
, &dsm
, UnsafeInfo
);
1061 Status
= MmCopyToCaller(uResult
, &dsm
.uResult
, sizeof(ULONG_PTR
));
1062 if(!NT_SUCCESS(Status
))
1064 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1072 NtUserSendMessage(HWND Wnd
,
1076 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1078 return IntDoSendMessage(Wnd
, Msg
, wParam
, lParam
, NULL
, UnsafeInfo
);
1082 NtUserSendMessageCallback(HWND hWnd
,
1086 SENDASYNCPROC lpCallBack
,
1095 NtUserSendNotifyMessage(HWND hWnd
,
1106 NtUserWaitMessage(VOID
)
1109 return IntWaitMessage(NULL
, 0, 0);
1113 NtUserGetQueueStatus(BOOL ClearChanges
)
1115 PUSER_MESSAGE_QUEUE Queue
;
1118 Queue
= PsGetWin32Thread()->MessageQueue
;
1120 IntLockMessageQueue(Queue
);
1122 Result
= MAKELONG(Queue
->ChangedBits
, Queue
->WakeBits
);
1125 Queue
->ChangedBits
= 0;
1128 IntUnLockMessageQueue(Queue
);
1134 IntInitMessagePumpHook()
1136 PsGetCurrentThread()->Win32Thread
->MessagePumpHookValue
++;
1141 IntUninitMessagePumpHook()
1143 if (PsGetCurrentThread()->Win32Thread
->MessagePumpHookValue
<= 0)
1147 PsGetCurrentThread()->Win32Thread
->MessagePumpHookValue
--;