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.21 2003/06/14 21:21:23 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/guicheck.h>
35 #include <include/msgqueue.h>
36 #include <include/window.h>
37 #include <include/class.h>
38 #include <include/error.h>
39 #include <include/object.h>
40 #include <include/winsta.h>
41 #include <include/callback.h>
42 #include <include/painting.h>
43 #include <internal/safe.h>
48 /* FUNCTIONS *****************************************************************/
51 W32kInitMessageImpl(VOID
)
53 return STATUS_SUCCESS
;
57 W32kCleanupMessageImpl(VOID
)
59 return STATUS_SUCCESS
;
64 NtUserDispatchMessage(CONST MSG
* UnsafeMsg
)
67 PWINDOW_OBJECT WindowObject
;
71 Status
= MmCopyFromCaller(&Msg
, (PVOID
) UnsafeMsg
, sizeof(MSG
));
72 if (! NT_SUCCESS(Status
))
74 SetLastNtError(Status
);
78 /* Process timer messages. */
79 if (Msg
.message
== WM_TIMER
)
83 /* FIXME: Call hooks. */
85 /* FIXME: Check for continuing validity of timer. */
87 return W32kCallWindowProc((WNDPROC
)Msg
.lParam
,
91 0 /* GetTickCount() */);
95 /* Get the window object. */
97 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
100 (PVOID
*)&WindowObject
);
101 if (!NT_SUCCESS(Status
))
103 SetLastNtError(Status
);
107 /* FIXME: Call hook procedures. */
109 /* Call the window procedure. */
110 Result
= W32kCallWindowProc(WindowObject
->WndProc
,
120 * Internal version of PeekMessage() doing all the work
123 W32kPeekMessage(LPMSG Msg
,
129 PUSER_MESSAGE_QUEUE ThreadQueue
;
131 PUSER_MESSAGE Message
;
132 BOOLEAN RemoveMessages
;
134 /* The queues and order in which they are checked are documented in the MSDN
135 article on GetMessage() */
137 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
139 /* Inspect RemoveMsg flags */
140 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
141 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
143 /* Dispatch sent messages here. */
144 while (MsqDispatchOneSentMessage(ThreadQueue
))
147 /* Now look for a quit message. */
148 /* FIXME: WINE checks the message number filter here. */
149 if (ThreadQueue
->QuitPosted
)
152 Msg
->message
= WM_QUIT
;
153 Msg
->wParam
= ThreadQueue
->QuitExitCode
;
157 ThreadQueue
->QuitPosted
= FALSE
;
162 /* Now check for normal messages. */
163 Present
= MsqFindMessage(ThreadQueue
,
172 RtlCopyMemory(Msg
, &Message
->Msg
, sizeof(MSG
));
180 /* Check for hardware events. */
181 Present
= MsqFindMessage(ThreadQueue
,
190 RtlCopyMemory(Msg
, &Message
->Msg
, sizeof(MSG
));
198 /* Check for sent messages again. */
199 while (MsqDispatchOneSentMessage(ThreadQueue
))
202 /* Check for paint messages. */
203 if (ThreadQueue
->PaintPosted
)
205 PWINDOW_OBJECT WindowObject
;
207 Msg
->hwnd
= PaintingFindWinToRepaint(Wnd
, PsGetWin32Thread());
208 Msg
->message
= WM_PAINT
;
209 Msg
->wParam
= Msg
->lParam
= 0;
211 WindowObject
= W32kGetWindowObject(Msg
->hwnd
);
212 if (WindowObject
!= NULL
)
214 if (WindowObject
->Style
& WS_MINIMIZE
&&
215 (HICON
)NtUserGetClassLong(Msg
->hwnd
, GCL_HICON
) != NULL
)
217 Msg
->message
= WM_PAINTICON
;
221 if (Msg
->hwnd
== NULL
|| Msg
->hwnd
== Wnd
||
222 W32kIsChildWindow(Wnd
, Msg
->hwnd
))
224 if (WindowObject
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
&&
225 WindowObject
->UpdateRegion
== NULL
)
227 WindowObject
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
230 MsqDecPaintCountQueue(WindowObject
->MessageQueue
);
234 W32kReleaseWindowObject(WindowObject
);
244 NtUserPeekMessage(LPMSG UnsafeMsg
,
253 PWINDOW_OBJECT Window
;
255 /* Initialize the thread's win32 state if necessary. */
261 Status
= ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
262 Wnd
, otWindow
, (PVOID
*)&Window
);
263 if (!NT_SUCCESS(Status
))
269 ObmDereferenceObject(Window
);
272 if (MsgFilterMax
< MsgFilterMin
)
278 Present
= W32kPeekMessage(&SafeMsg
, Wnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
);
281 Status
= MmCopyToCaller(UnsafeMsg
, &SafeMsg
, sizeof(MSG
));
282 if (! NT_SUCCESS(Status
))
284 /* There is error return documented for PeekMessage().
285 Do the best we can */
286 SetLastNtError(Status
);
295 W32kWaitMessage(HWND Wnd
,
299 PUSER_MESSAGE_QUEUE ThreadQueue
;
303 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
307 if (W32kPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_NOREMOVE
))
312 /* Nothing found. Wait for new messages. */
313 Status
= MsqWaitForNewMessages(ThreadQueue
);
315 while (STATUS_WAIT_0
<= STATUS_WAIT_0
&& Status
<= STATUS_WAIT_63
);
317 SetLastNtError(Status
);
323 NtUserGetMessage(LPMSG UnsafeMsg
,
328 * FUNCTION: Get a message from the calling thread's message queue.
330 * UnsafeMsg - Pointer to the structure which receives the returned message.
331 * Wnd - Window whose messages are to be retrieved.
332 * MsgFilterMin - Integer value of the lowest message value to be
334 * MsgFilterMax - Integer value of the highest message value to be
341 PWINDOW_OBJECT Window
;
343 /* Initialize the thread's win32 state if necessary. */
349 Status
= ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
350 Wnd
, otWindow
, (PVOID
*)&Window
);
351 if (!NT_SUCCESS(Status
))
357 ObmDereferenceObject(Window
);
360 if (MsgFilterMax
< MsgFilterMin
)
368 GotMessage
= W32kPeekMessage(&SafeMsg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
);
371 Status
= MmCopyToCaller(UnsafeMsg
, &SafeMsg
, sizeof(MSG
));
372 if (! NT_SUCCESS(Status
))
374 SetLastNtError(Status
);
380 W32kWaitMessage(Wnd
, MsgFilterMin
, MsgFilterMax
);
383 while (! GotMessage
);
385 return WM_QUIT
!= SafeMsg
.message
;
405 NtUserPostMessage(HWND hWnd
,
410 PWINDOW_OBJECT Window
;
412 PUSER_MESSAGE Message
;
415 /* Initialize the thread's win32 state if necessary. */
420 MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue
, wParam
);
424 Status
= ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
425 hWnd
, otWindow
, (PVOID
*)&Window
);
426 if (!NT_SUCCESS(Status
))
428 SetLastNtError(Status
);
433 Mesg
.wParam
= wParam
;
434 Mesg
.lParam
= lParam
;
435 Message
= MsqCreateMessage(&Mesg
);
436 MsqPostMessage(Window
->MessageQueue
, Message
);
437 ObmDereferenceObject(Window
);
444 NtUserPostThreadMessage(DWORD idThread
,
455 NtUserQuerySendMessage(DWORD Unknown0
)
463 W32kSendMessage(HWND hWnd
,
471 PWINDOW_OBJECT Window
;
473 /* FIXME: Check for a broadcast or topmost destination. */
475 /* FIXME: Call hooks. */
478 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
482 if (!NT_SUCCESS(Status
))
487 /* FIXME: Check for an exiting window. */
489 if (NULL
!= PsGetWin32Thread() &&
490 Window
->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
494 Result
= W32kCallTrampolineWindowProc(NULL
, hWnd
, Msg
, wParam
,
500 Result
= W32kCallWindowProc(Window
->WndProc
, hWnd
, Msg
, wParam
, lParam
);
506 PUSER_SENT_MESSAGE Message
;
507 PKEVENT CompletionEvent
;
509 CompletionEvent
= ExAllocatePool(NonPagedPool
, sizeof(KEVENT
));
510 KeInitializeEvent(CompletionEvent
, NotificationEvent
, FALSE
);
512 Message
= ExAllocatePool(NonPagedPool
, sizeof(USER_SENT_MESSAGE
));
513 Message
->Msg
.hwnd
= hWnd
;
514 Message
->Msg
.message
= Msg
;
515 Message
->Msg
.wParam
= wParam
;
516 Message
->Msg
.lParam
= lParam
;
517 Message
->CompletionEvent
= CompletionEvent
;
518 Message
->Result
= &Result
;
519 Message
->CompletionQueue
= NULL
;
520 Message
->CompletionCallback
= NULL
;
521 MsqSendMessage(Window
->MessageQueue
, Message
);
523 ObmDereferenceObject(Window
);
524 Status
= KeWaitForSingleObject(CompletionEvent
,
529 if (Status
== STATUS_WAIT_0
)
541 NtUserSendMessage(HWND Wnd
,
546 return W32kSendMessage(Wnd
, Msg
, wParam
, lParam
, FALSE
);
550 NtUserSendMessageCallback(HWND hWnd
,
554 SENDASYNCPROC lpCallBack
,
563 NtUserSendNotifyMessage(HWND hWnd
,
574 NtUserWaitMessage(VOID
)
576 /* Initialize the thread's win32 state if necessary. */
579 return W32kWaitMessage(NULL
, 0, 0);