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.26 2003/08/02 16:53:08 gdalsnes 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 <internal/safe.h>
47 /* FUNCTIONS *****************************************************************/
50 W32kInitMessageImpl(VOID
)
52 return STATUS_SUCCESS
;
56 W32kCleanupMessageImpl(VOID
)
58 return STATUS_SUCCESS
;
63 NtUserDispatchMessage(CONST MSG
* UnsafeMsg
)
66 PWINDOW_OBJECT WindowObject
;
70 Status
= MmCopyFromCaller(&Msg
, (PVOID
) UnsafeMsg
, sizeof(MSG
));
71 if (! NT_SUCCESS(Status
))
73 SetLastNtError(Status
);
77 /* Process timer messages. */
78 if (Msg
.message
== WM_TIMER
)
82 /* FIXME: Call hooks. */
84 /* FIXME: Check for continuing validity of timer. */
86 return W32kCallWindowProc((WNDPROC
)Msg
.lParam
,
90 0 /* GetTickCount() */);
94 /* Get the window object. */
96 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
99 (PVOID
*)&WindowObject
);
100 if (!NT_SUCCESS(Status
))
102 SetLastNtError(Status
);
106 /* FIXME: Call hook procedures. */
108 /* Call the window procedure. */
109 Result
= W32kCallWindowProc(WindowObject
->WndProc
,
119 * Internal version of PeekMessage() doing all the work
122 W32kPeekMessage(LPMSG Msg
,
128 PUSER_MESSAGE_QUEUE ThreadQueue
;
130 PUSER_MESSAGE Message
;
131 BOOLEAN RemoveMessages
;
133 /* The queues and order in which they are checked are documented in the MSDN
134 article on GetMessage() */
136 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
138 /* Inspect RemoveMsg flags */
139 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
140 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
142 /* Dispatch sent messages here. */
143 while (MsqDispatchOneSentMessage(ThreadQueue
))
146 /* Now look for a quit message. */
147 /* FIXME: WINE checks the message number filter here. */
148 if (ThreadQueue
->QuitPosted
)
151 Msg
->message
= WM_QUIT
;
152 Msg
->wParam
= ThreadQueue
->QuitExitCode
;
156 ThreadQueue
->QuitPosted
= FALSE
;
161 /* Now check for normal messages. */
162 Present
= MsqFindMessage(ThreadQueue
,
171 RtlCopyMemory(Msg
, &Message
->Msg
, sizeof(MSG
));
174 MsqDestroyMessage(Message
);
179 /* Check for hardware events. */
180 Present
= MsqFindMessage(ThreadQueue
,
189 RtlCopyMemory(Msg
, &Message
->Msg
, sizeof(MSG
));
192 MsqDestroyMessage(Message
);
197 /* Check for sent messages again. */
198 while (MsqDispatchOneSentMessage(ThreadQueue
))
201 /* Check for paint messages. */
202 if (ThreadQueue
->PaintPosted
)
204 PWINDOW_OBJECT WindowObject
;
206 Msg
->hwnd
= PaintingFindWinToRepaint(Wnd
, PsGetWin32Thread());
207 Msg
->message
= WM_PAINT
;
208 Msg
->wParam
= Msg
->lParam
= 0;
210 WindowObject
= W32kGetWindowObject(Msg
->hwnd
);
211 if (WindowObject
!= NULL
)
213 if (WindowObject
->Style
& WS_MINIMIZE
&&
214 (HICON
)NtUserGetClassLong(Msg
->hwnd
, GCL_HICON
) != NULL
)
216 Msg
->message
= WM_PAINTICON
;
220 if (Msg
->hwnd
== NULL
|| Msg
->hwnd
== Wnd
||
221 W32kIsChildWindow(Wnd
, Msg
->hwnd
))
223 if (WindowObject
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
&&
224 WindowObject
->UpdateRegion
== NULL
)
226 WindowObject
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
229 MsqDecPaintCountQueue(WindowObject
->MessageQueue
);
233 W32kReleaseWindowObject(WindowObject
);
243 NtUserPeekMessage(LPMSG UnsafeMsg
,
252 PWINDOW_OBJECT Window
;
257 Status
= ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
258 Wnd
, otWindow
, (PVOID
*)&Window
);
259 if (!NT_SUCCESS(Status
))
265 ObmDereferenceObject(Window
);
268 if (MsgFilterMax
< MsgFilterMin
)
274 Present
= W32kPeekMessage(&SafeMsg
, Wnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
);
277 Status
= MmCopyToCaller(UnsafeMsg
, &SafeMsg
, sizeof(MSG
));
278 if (! NT_SUCCESS(Status
))
280 /* There is error return documented for PeekMessage().
281 Do the best we can */
282 SetLastNtError(Status
);
291 W32kWaitMessage(HWND Wnd
,
295 PUSER_MESSAGE_QUEUE ThreadQueue
;
299 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
303 if (W32kPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_NOREMOVE
))
308 /* Nothing found. Wait for new messages. */
309 Status
= MsqWaitForNewMessages(ThreadQueue
);
311 while (STATUS_WAIT_0
<= STATUS_WAIT_0
&& Status
<= STATUS_WAIT_63
);
313 SetLastNtError(Status
);
319 NtUserGetMessage(LPMSG UnsafeMsg
,
324 * FUNCTION: Get a message from the calling thread's message queue.
326 * UnsafeMsg - Pointer to the structure which receives the returned message.
327 * Wnd - Window whose messages are to be retrieved.
328 * MsgFilterMin - Integer value of the lowest message value to be
330 * MsgFilterMax - Integer value of the highest message value to be
337 PWINDOW_OBJECT Window
;
342 Status
= ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
343 Wnd
, otWindow
, (PVOID
*)&Window
);
344 if (!NT_SUCCESS(Status
))
350 ObmDereferenceObject(Window
);
353 if (MsgFilterMax
< MsgFilterMin
)
361 GotMessage
= W32kPeekMessage(&SafeMsg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
);
364 Status
= MmCopyToCaller(UnsafeMsg
, &SafeMsg
, sizeof(MSG
));
365 if (! NT_SUCCESS(Status
))
367 SetLastNtError(Status
);
373 W32kWaitMessage(Wnd
, MsgFilterMin
, MsgFilterMax
);
376 while (! GotMessage
);
378 return WM_QUIT
!= SafeMsg
.message
;
398 NtUserPostMessage(HWND hWnd
,
403 PWINDOW_OBJECT Window
;
405 PUSER_MESSAGE Message
;
410 MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue
, wParam
);
414 Status
= ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
415 hWnd
, otWindow
, (PVOID
*)&Window
);
416 if (!NT_SUCCESS(Status
))
418 SetLastNtError(Status
);
423 Mesg
.wParam
= wParam
;
424 Mesg
.lParam
= lParam
;
425 Message
= MsqCreateMessage(&Mesg
);
426 MsqPostMessage(Window
->MessageQueue
, Message
);
427 ObmDereferenceObject(Window
);
434 NtUserPostThreadMessage(DWORD idThread
,
441 PUSER_MESSAGE Message
;
446 Status
= PsLookupThreadByThreadId((void *)idThread
,&peThread
);
448 if( Status
== STATUS_SUCCESS
) {
449 pThread
= peThread
->Win32Thread
;
450 if( !pThread
|| !pThread
->MessageQueue
)
452 ObDereferenceObject( peThread
);
457 Mesg
.wParam
= wParam
;
458 Mesg
.lParam
= lParam
;
459 Message
= MsqCreateMessage(&Mesg
);
460 MsqPostMessage(pThread
->MessageQueue
, Message
);
461 ObDereferenceObject( peThread
);
464 SetLastNtError( Status
);
470 NtUserQuerySendMessage(DWORD Unknown0
)
478 W32kSendMessage(HWND hWnd
,
486 PWINDOW_OBJECT Window
;
488 /* FIXME: Check for a broadcast or topmost destination. */
490 /* FIXME: Call hooks. */
493 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
497 if (!NT_SUCCESS(Status
))
502 /* FIXME: Check for an exiting window. */
504 if (NULL
!= PsGetWin32Thread() &&
505 Window
->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
509 Result
= W32kCallTrampolineWindowProc(NULL
, hWnd
, Msg
, wParam
,
515 Result
= W32kCallWindowProc(Window
->WndProc
, hWnd
, Msg
, wParam
, lParam
);
521 PUSER_SENT_MESSAGE Message
;
522 PKEVENT CompletionEvent
;
524 CompletionEvent
= ExAllocatePool(NonPagedPool
, sizeof(KEVENT
));
525 KeInitializeEvent(CompletionEvent
, NotificationEvent
, FALSE
);
527 Message
= ExAllocatePool(NonPagedPool
, sizeof(USER_SENT_MESSAGE
));
528 Message
->Msg
.hwnd
= hWnd
;
529 Message
->Msg
.message
= Msg
;
530 Message
->Msg
.wParam
= wParam
;
531 Message
->Msg
.lParam
= lParam
;
532 Message
->CompletionEvent
= CompletionEvent
;
533 Message
->Result
= &Result
;
534 Message
->CompletionQueue
= NULL
;
535 Message
->CompletionCallback
= NULL
;
536 MsqSendMessage(Window
->MessageQueue
, Message
);
538 ObmDereferenceObject(Window
);
539 Status
= KeWaitForSingleObject(CompletionEvent
,
544 if (Status
== STATUS_WAIT_0
)
556 NtUserSendMessage(HWND Wnd
,
561 return W32kSendMessage(Wnd
, Msg
, wParam
, lParam
, FALSE
);
565 NtUserSendMessageCallback(HWND hWnd
,
569 SENDASYNCPROC lpCallBack
,
578 NtUserSendNotifyMessage(HWND hWnd
,
589 NtUserWaitMessage(VOID
)
592 return W32kWaitMessage(NULL
, 0, 0);
597 NtUserGetQueueStatus(BOOL ClearChanges
)
599 PUSER_MESSAGE_QUEUE Queue
;
602 Queue
= PsGetWin32Thread()->MessageQueue
;
604 ExAcquireFastMutex(&Queue
->Lock
);
606 Result
= MAKELONG(Queue
->ChangedBits
, Queue
->WakeBits
);
609 Queue
->ChangedBits
= 0;
612 ExReleaseFastMutex(&Queue
->Lock
);