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.50 2004/02/19 21:12:09 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>
50 /* FUNCTIONS *****************************************************************/
53 IntInitMessageImpl(VOID
)
55 return STATUS_SUCCESS
;
59 IntCleanupMessageImpl(VOID
)
61 return STATUS_SUCCESS
;
65 IntDispatchMessage(MSG
* Msg
)
68 PWINDOW_OBJECT WindowObject
;
69 /* Process timer messages. */
70 if (Msg
->message
== WM_TIMER
)
74 LARGE_INTEGER LargeTickCount
;
75 /* FIXME: Call hooks. */
77 /* FIXME: Check for continuing validity of timer. */
79 KeQueryTickCount(&LargeTickCount
);
80 return IntCallWindowProc((WNDPROC
)Msg
->lParam
,
85 (LPARAM
)LargeTickCount
.u
.LowPart
,
90 if( Msg
->hwnd
== 0 ) return 0;
92 /* Get the window object. */
93 WindowObject
= IntGetWindowObject(Msg
->hwnd
);
96 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
99 if(WindowObject
->OwnerThread
!= PsGetCurrentThread())
101 IntReleaseWindowObject(WindowObject
);
102 DPRINT("Window doesn't belong to the calling thread!\n");
105 /* FIXME: Call hook procedures. */
107 /* Call the window procedure. */
108 if (0xFFFF0000 != ((DWORD
) WindowObject
->WndProcW
& 0xFFFF0000))
110 Result
= IntCallWindowProc(WindowObject
->WndProcW
,
120 Result
= IntCallWindowProc(WindowObject
->WndProcA
,
129 IntReleaseWindowObject(WindowObject
);
136 NtUserDispatchMessage(CONST MSG
* UnsafeMsg
)
141 Status
= MmCopyFromCaller(&Msg
, (PVOID
) UnsafeMsg
, sizeof(MSG
));
142 if (! NT_SUCCESS(Status
))
144 SetLastNtError(Status
);
148 return IntDispatchMessage(&Msg
);
153 NtUserTranslateMessage(LPMSG lpMsg
,
159 Status
= MmCopyFromCaller(&SafeMsg
, lpMsg
, sizeof(MSG
));
160 if(!NT_SUCCESS(Status
))
162 SetLastNtError(Status
);
166 return IntTranslateKbdMessage(&SafeMsg
, dwhkl
);
171 IntSendSpecialMessages(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
)
173 if(!Msg
->hwnd
|| ThreadQueue
->CaptureWindow
)
182 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
187 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
194 case WM_LBUTTONDBLCLK
:
195 case WM_MBUTTONDBLCLK
:
196 case WM_RBUTTONDBLCLK
:
197 case WM_XBUTTONDBLCLK
:
201 if(!IntGetWindowStationObject(InputWindowStation
))
205 wParam
= (WPARAM
)InputWindowStation
->SystemCursor
.ButtonsDown
;
206 ObDereferenceObject(InputWindowStation
);
208 IntSendMessage(Msg
->hwnd
, WM_MOUSEMOVE
, wParam
, Msg
->lParam
);
209 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
212 case WM_NCLBUTTONDOWN
:
213 case WM_NCMBUTTONDOWN
:
214 case WM_NCRBUTTONDOWN
:
215 case WM_NCXBUTTONDOWN
:
216 case WM_NCLBUTTONDBLCLK
:
217 case WM_NCMBUTTONDBLCLK
:
218 case WM_NCRBUTTONDBLCLK
:
219 case WM_NCXBUTTONDBLCLK
:
221 IntSendMessage(Msg
->hwnd
, WM_NCMOUSEMOVE
, (WPARAM
)Msg
->wParam
, Msg
->lParam
);
222 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
229 * Internal version of PeekMessage() doing all the work
232 IntPeekMessage(LPMSG Msg
,
238 PUSER_MESSAGE_QUEUE ThreadQueue
;
240 PUSER_MESSAGE Message
;
241 BOOLEAN RemoveMessages
;
243 /* The queues and order in which they are checked are documented in the MSDN
244 article on GetMessage() */
246 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
248 /* Inspect RemoveMsg flags */
249 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
250 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
252 /* Dispatch sent messages here. */
253 while (MsqDispatchOneSentMessage(ThreadQueue
))
256 /* Now look for a quit message. */
257 /* FIXME: WINE checks the message number filter here. */
258 if (ThreadQueue
->QuitPosted
)
261 Msg
->message
= WM_QUIT
;
262 Msg
->wParam
= ThreadQueue
->QuitExitCode
;
266 ThreadQueue
->QuitPosted
= FALSE
;
271 /* Now check for normal messages. */
272 Present
= MsqFindMessage(ThreadQueue
,
281 RtlCopyMemory(Msg
, &Message
->Msg
, sizeof(MSG
));
284 MsqDestroyMessage(Message
);
285 IntSendSpecialMessages(ThreadQueue
, Msg
);
290 /* Check for hardware events. */
291 Present
= MsqFindMessage(ThreadQueue
,
300 RtlCopyMemory(Msg
, &Message
->Msg
, sizeof(MSG
));
303 MsqDestroyMessage(Message
);
304 IntSendSpecialMessages(ThreadQueue
, Msg
);
309 /* Check for sent messages again. */
310 while (MsqDispatchOneSentMessage(ThreadQueue
))
313 /* Check for paint messages. */
314 if (IntGetPaintMessage(Wnd
, PsGetWin32Thread(), Msg
, RemoveMessages
))
323 NtUserPeekMessage(LPMSG UnsafeMsg
,
332 PWINDOW_OBJECT Window
;
337 Window
= IntGetWindowObject(Wnd
);
341 IntReleaseWindowObject(Window
);
343 if (MsgFilterMax
< MsgFilterMin
)
349 Present
= IntPeekMessage(&SafeMsg
, Wnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
);
352 Status
= MmCopyToCaller(UnsafeMsg
, &SafeMsg
, sizeof(MSG
));
353 if (! NT_SUCCESS(Status
))
355 /* There is error return documented for PeekMessage().
356 Do the best we can */
357 SetLastNtError(Status
);
366 IntWaitMessage(HWND Wnd
,
370 PUSER_MESSAGE_QUEUE ThreadQueue
;
374 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
378 if (IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_NOREMOVE
))
383 /* Nothing found. Wait for new messages. */
384 Status
= MsqWaitForNewMessages(ThreadQueue
);
386 while (STATUS_WAIT_0
<= STATUS_WAIT_0
&& Status
<= STATUS_WAIT_63
);
388 SetLastNtError(Status
);
394 NtUserGetMessage(LPMSG UnsafeMsg
,
399 * FUNCTION: Get a message from the calling thread's message queue.
401 * UnsafeMsg - Pointer to the structure which receives the returned message.
402 * Wnd - Window whose messages are to be retrieved.
403 * MsgFilterMin - Integer value of the lowest message value to be
405 * MsgFilterMax - Integer value of the highest message value to be
412 PWINDOW_OBJECT Window
;
417 Window
= IntGetWindowObject(Wnd
);
421 IntReleaseWindowObject(Window
);
423 if (MsgFilterMax
< MsgFilterMin
)
431 GotMessage
= IntPeekMessage(&SafeMsg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
);
434 Status
= MmCopyToCaller(UnsafeMsg
, &SafeMsg
, sizeof(MSG
));
435 if (! NT_SUCCESS(Status
))
437 SetLastNtError(Status
);
443 IntWaitMessage(Wnd
, MsgFilterMin
, MsgFilterMax
);
446 while (! GotMessage
);
448 return WM_QUIT
!= SafeMsg
.message
;
468 NtUserPostMessage(HWND hWnd
,
473 PWINDOW_OBJECT Window
;
475 PUSER_MESSAGE Message
;
476 LARGE_INTEGER LargeTickCount
;
480 MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue
, wParam
);
482 else if (hWnd
== HWND_BROADCAST
)
485 PWINDOW_OBJECT DesktopWindow
;
488 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
489 List
= IntWinListChildren(DesktopWindow
);
490 IntReleaseWindowObject(DesktopWindow
);
493 for (i
= 0; List
[i
]; i
++)
494 NtUserPostMessage(List
[i
], Msg
, wParam
, lParam
);
500 Window
= IntGetWindowObject(hWnd
);
503 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
508 Mesg
.wParam
= wParam
;
509 Mesg
.lParam
= lParam
;
510 Mesg
.pt
.x
= PsGetWin32Process()->WindowStation
->SystemCursor
.x
;
511 Mesg
.pt
.y
= PsGetWin32Process()->WindowStation
->SystemCursor
.y
;
512 KeQueryTickCount(&LargeTickCount
);
513 Mesg
.time
= LargeTickCount
.u
.LowPart
;
514 Message
= MsqCreateMessage(&Mesg
);
515 MsqPostMessage(Window
->MessageQueue
, Message
);
516 IntReleaseWindowObject(Window
);
523 NtUserPostThreadMessage(DWORD idThread
,
530 PUSER_MESSAGE Message
;
535 Status
= PsLookupThreadByThreadId((void *)idThread
,&peThread
);
537 if( Status
== STATUS_SUCCESS
) {
538 pThread
= peThread
->Win32Thread
;
539 if( !pThread
|| !pThread
->MessageQueue
)
541 ObDereferenceObject( peThread
);
546 Mesg
.wParam
= wParam
;
547 Mesg
.lParam
= lParam
;
548 Message
= MsqCreateMessage(&Mesg
);
549 MsqPostMessage(pThread
->MessageQueue
, Message
);
550 ObDereferenceObject( peThread
);
553 SetLastNtError( Status
);
559 NtUserQuerySendMessage(DWORD Unknown0
)
566 #define MMS_SIZE_WPARAM -1
567 #define MMS_SIZE_WPARAMWCHAR -2
568 #define MMS_SIZE_LPARAMSZ -3
569 #define MMS_SIZE_SPECIAL -4
570 #define MMS_FLAG_READ 0x01
571 #define MMS_FLAG_WRITE 0x02
572 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
573 typedef struct tagMSGMEMORY
578 } MSGMEMORY
, *PMSGMEMORY
;
580 static MSGMEMORY MsgMemory
[] =
582 { WM_CREATE
, sizeof(CREATESTRUCTW
), MMS_FLAG_READWRITE
},
583 { WM_GETMINMAXINFO
, sizeof(MINMAXINFO
), MMS_FLAG_READWRITE
},
584 { WM_GETTEXT
, MMS_SIZE_WPARAMWCHAR
, MMS_FLAG_WRITE
},
585 { WM_NCCALCSIZE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
586 { WM_NCCREATE
, sizeof(CREATESTRUCTW
), MMS_FLAG_READWRITE
},
587 { WM_SETTEXT
, MMS_SIZE_LPARAMSZ
, MMS_FLAG_READ
},
588 { WM_STYLECHANGED
, sizeof(STYLESTRUCT
), MMS_FLAG_READ
},
589 { WM_STYLECHANGING
, sizeof(STYLESTRUCT
), MMS_FLAG_READWRITE
},
590 { WM_WINDOWPOSCHANGED
, sizeof(WINDOWPOS
), MMS_FLAG_READ
},
591 { WM_WINDOWPOSCHANGING
, sizeof(WINDOWPOS
), MMS_FLAG_READWRITE
},
594 static PMSGMEMORY FASTCALL
595 FindMsgMemory(UINT Msg
)
597 PMSGMEMORY MsgMemoryEntry
;
599 /* See if this message type is present in the table */
600 for (MsgMemoryEntry
= MsgMemory
;
601 MsgMemoryEntry
< MsgMemory
+ sizeof(MsgMemory
) / sizeof(MSGMEMORY
);
604 if (Msg
== MsgMemoryEntry
->Message
)
606 return MsgMemoryEntry
;
614 MsgMemorySize(PMSGMEMORY MsgMemoryEntry
, WPARAM wParam
, LPARAM lParam
)
616 if (MMS_SIZE_WPARAM
== MsgMemoryEntry
->Size
)
618 return (UINT
) wParam
;
620 else if (MMS_SIZE_WPARAMWCHAR
== MsgMemoryEntry
->Size
)
622 return (UINT
) (wParam
* sizeof(WCHAR
));
624 else if (MMS_SIZE_LPARAMSZ
== MsgMemoryEntry
->Size
)
626 return (UINT
) ((wcslen((PWSTR
) lParam
) + 1) * sizeof(WCHAR
));
628 else if (MMS_SIZE_SPECIAL
== MsgMemoryEntry
->Size
)
630 switch(MsgMemoryEntry
->Message
)
633 return wParam
? sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
) : sizeof(RECT
);
643 return MsgMemoryEntry
->Size
;
647 static FASTCALL NTSTATUS
648 PackParam(LPARAM
*lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
650 NCCALCSIZE_PARAMS
*UnpackedParams
;
651 NCCALCSIZE_PARAMS
*PackedParams
;
653 *lParamPacked
= lParam
;
654 if (WM_NCCALCSIZE
== Msg
&& wParam
)
656 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
657 if (UnpackedParams
->lppos
!= (PWINDOWPOS
) (UnpackedParams
+ 1))
659 PackedParams
= ExAllocatePoolWithTag(PagedPool
,
660 sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
),
662 if (NULL
== PackedParams
)
664 DPRINT1("Not enough memory to pack lParam\n");
665 return STATUS_NO_MEMORY
;
667 RtlCopyMemory(PackedParams
, UnpackedParams
, sizeof(NCCALCSIZE_PARAMS
));
668 PackedParams
->lppos
= (PWINDOWPOS
) (PackedParams
+ 1);
669 RtlCopyMemory(PackedParams
->lppos
, UnpackedParams
->lppos
, sizeof(WINDOWPOS
));
670 *lParamPacked
= (LPARAM
) PackedParams
;
674 return STATUS_SUCCESS
;
677 static FASTCALL NTSTATUS
678 UnpackParam(LPARAM lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
680 NCCALCSIZE_PARAMS
*UnpackedParams
;
681 NCCALCSIZE_PARAMS
*PackedParams
;
682 PWINDOWPOS UnpackedWindowPos
;
684 if (lParamPacked
== lParam
)
686 return STATUS_SUCCESS
;
689 if (WM_NCCALCSIZE
== Msg
&& wParam
)
691 PackedParams
= (NCCALCSIZE_PARAMS
*) lParamPacked
;
692 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
693 UnpackedWindowPos
= UnpackedParams
->lppos
;
694 RtlCopyMemory(UnpackedParams
, PackedParams
, sizeof(NCCALCSIZE_PARAMS
));
695 UnpackedParams
->lppos
= UnpackedWindowPos
;
696 RtlCopyMemory(UnpackedWindowPos
, PackedParams
+ 1, sizeof(WINDOWPOS
));
697 ExFreePool((PVOID
) lParamPacked
);
699 return STATUS_SUCCESS
;
704 return STATUS_INVALID_PARAMETER
;
708 IntSendMessage(HWND hWnd
,
714 PWINDOW_OBJECT Window
;
715 PMSGMEMORY MsgMemoryEntry
;
716 INT lParamBufferSize
;
718 PW32THREAD Win32Thread
;
720 /* FIXME: Check for a broadcast or topmost destination. */
722 /* FIXME: Call hooks. */
723 Window
= IntGetWindowObject(hWnd
);
726 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
730 Win32Thread
= PsGetWin32Thread();
732 if (NULL
!= Win32Thread
&&
733 Window
->MessageQueue
== Win32Thread
->MessageQueue
)
735 if (Win32Thread
->IsExiting
)
737 /* Never send messages to exiting threads */
738 IntReleaseWindowObject(Window
);
742 /* See if this message type is present in the table */
743 MsgMemoryEntry
= FindMsgMemory(Msg
);
744 if (NULL
== MsgMemoryEntry
)
746 lParamBufferSize
= -1;
750 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
753 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
)))
755 IntReleaseWindowObject(Window
);
756 DPRINT1("Failed to pack message parameters\n");
759 if (0xFFFF0000 != ((DWORD
) Window
->WndProcW
& 0xFFFF0000))
761 Result
= IntCallWindowProc(Window
->WndProcW
, FALSE
, hWnd
, Msg
, wParam
,
762 lParamPacked
,lParamBufferSize
);
766 Result
= IntCallWindowProc(Window
->WndProcA
, TRUE
, hWnd
, Msg
, wParam
,
767 lParamPacked
,lParamBufferSize
);
769 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
)))
771 IntReleaseWindowObject(Window
);
772 DPRINT1("Failed to unpack message parameters\n");
776 IntReleaseWindowObject(Window
);
781 Result
= MsqSendMessage(Window
->MessageQueue
, hWnd
, Msg
, wParam
, lParam
);
783 IntReleaseWindowObject(Window
);
788 static NTSTATUS FASTCALL
789 CopyMsgToKernelMem(MSG
*KernelModeMsg
, MSG
*UserModeMsg
)
792 PMSGMEMORY MsgMemoryEntry
;
796 *KernelModeMsg
= *UserModeMsg
;
798 /* See if this message type is present in the table */
799 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
800 if (NULL
== MsgMemoryEntry
)
802 /* Not present, no copying needed */
803 return STATUS_SUCCESS
;
806 /* Determine required size */
807 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
811 /* Allocate kernel mem */
812 KernelMem
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
813 if (NULL
== KernelMem
)
815 DPRINT1("Not enough memory to copy message to kernel mem\n");
816 return STATUS_NO_MEMORY
;
818 KernelModeMsg
->lParam
= (LPARAM
) KernelMem
;
820 /* Copy data if required */
821 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_READ
))
823 Status
= MmCopyFromCaller(KernelMem
, (PVOID
) UserModeMsg
->lParam
, Size
);
824 if (! NT_SUCCESS(Status
))
826 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
827 ExFreePool(KernelMem
);
833 /* Make sure we don't pass any secrets to usermode */
834 RtlZeroMemory(KernelMem
, Size
);
839 KernelModeMsg
->lParam
= 0;
842 return STATUS_SUCCESS
;
845 static NTSTATUS FASTCALL
846 CopyMsgToUserMem(MSG
*UserModeMsg
, MSG
*KernelModeMsg
)
849 PMSGMEMORY MsgMemoryEntry
;
852 /* See if this message type is present in the table */
853 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
854 if (NULL
== MsgMemoryEntry
)
856 /* Not present, no copying needed */
857 return STATUS_SUCCESS
;
860 /* Determine required size */
861 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
865 /* Copy data if required */
866 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_WRITE
))
868 Status
= MmCopyToCaller((PVOID
) UserModeMsg
->lParam
, (PVOID
) KernelModeMsg
->lParam
, Size
);
869 if (! NT_SUCCESS(Status
))
871 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
872 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
877 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
880 return STATUS_SUCCESS
;
884 NtUserSendMessage(HWND Wnd
,
888 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
892 PWINDOW_OBJECT Window
;
893 NTUSERSENDMESSAGEINFO Info
;
897 /* FIXME: Check for a broadcast or topmost destination. */
899 RtlZeroMemory(&Info
, sizeof(NTUSERSENDMESSAGEINFO
));
901 /* FIXME: Call hooks. */
902 Window
= IntGetWindowObject(Wnd
);
905 /* Tell usermode to not touch this one */
906 Info
.HandledByKernel
= TRUE
;
907 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
908 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
912 /* FIXME: Check for an exiting window. */
914 /* See if the current thread can handle the message */
915 if (NULL
!= PsGetWin32Thread() &&
916 Window
->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
918 /* Gather the information usermode needs to call the window proc directly */
919 Info
.HandledByKernel
= FALSE
;
920 if (0xFFFF0000 != ((DWORD
) Window
->WndProcW
& 0xFFFF0000))
922 if (0xFFFF0000 != ((DWORD
) Window
->WndProcA
& 0xFFFF0000))
924 /* Both Unicode and Ansi winprocs are real, see what usermode prefers */
925 Status
= MmCopyFromCaller(&(Info
.Ansi
), &(UnsafeInfo
->Ansi
),
927 if (! NT_SUCCESS(Status
))
929 Info
.Ansi
= ! Window
->Unicode
;
931 Info
.Proc
= (Info
.Ansi
? Window
->WndProcA
: Window
->WndProcW
);
935 /* Real Unicode winproc */
937 Info
.Proc
= Window
->WndProcW
;
942 /* Must have real Ansi winproc */
944 Info
.Proc
= Window
->WndProcA
;
946 IntReleaseWindowObject(Window
);
950 /* Must be handled by other thread */
951 IntReleaseWindowObject(Window
);
952 Info
.HandledByKernel
= TRUE
;
953 UserModeMsg
.hwnd
= Wnd
;
954 UserModeMsg
.message
= Msg
;
955 UserModeMsg
.wParam
= wParam
;
956 UserModeMsg
.lParam
= lParam
;
957 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
);
958 if (! NT_SUCCESS(Status
))
960 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
961 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
964 Result
= IntSendMessage(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
965 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
);
966 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
967 if (! NT_SUCCESS(Status
))
969 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
970 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
975 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
976 if (! NT_SUCCESS(Status
))
978 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
985 NtUserSendMessageCallback(HWND hWnd
,
989 SENDASYNCPROC lpCallBack
,
998 NtUserSendNotifyMessage(HWND hWnd
,
1009 NtUserWaitMessage(VOID
)
1012 return IntWaitMessage(NULL
, 0, 0);
1016 NtUserGetQueueStatus(BOOL ClearChanges
)
1018 PUSER_MESSAGE_QUEUE Queue
;
1021 Queue
= PsGetWin32Thread()->MessageQueue
;
1023 ExAcquireFastMutex(&Queue
->Lock
);
1025 Result
= MAKELONG(Queue
->ChangedBits
, Queue
->WakeBits
);
1028 Queue
->ChangedBits
= 0;
1031 ExReleaseFastMutex(&Queue
->Lock
);
1037 IntInitMessagePumpHook()
1039 PsGetCurrentThread()->Win32Thread
->MessagePumpHookValue
++;
1044 IntUninitMessagePumpHook()
1046 if (PsGetCurrentThread()->Win32Thread
->MessagePumpHookValue
<= 0)
1050 PsGetCurrentThread()->Win32Thread
->MessagePumpHookValue
--;