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.
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 IntInitMessageImpl(VOID)
52 return STATUS_SUCCESS;
56 IntCleanupMessageImpl(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 IntCallWindowProc((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 if (WindowObject->Unicode == TRUE)
111 Result = IntCallWindowProc(WindowObject->WndProcW,
119 Result = IntCallWindowProc(WindowObject->WndProcA,
130 * Internal version of PeekMessage() doing all the work
133 IntPeekMessage(LPMSG Msg,
139 PUSER_MESSAGE_QUEUE ThreadQueue;
141 PUSER_MESSAGE Message;
142 BOOLEAN RemoveMessages;
144 /* The queues and order in which they are checked are documented in the MSDN
145 article on GetMessage() */
147 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
149 /* Inspect RemoveMsg flags */
150 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
151 RemoveMessages = RemoveMsg & PM_REMOVE;
153 /* Dispatch sent messages here. */
154 while (MsqDispatchOneSentMessage(ThreadQueue))
157 /* Now look for a quit message. */
158 /* FIXME: WINE checks the message number filter here. */
159 if (ThreadQueue->QuitPosted)
162 Msg->message = WM_QUIT;
163 Msg->wParam = ThreadQueue->QuitExitCode;
167 ThreadQueue->QuitPosted = FALSE;
172 /* Now check for normal messages. */
173 Present = MsqFindMessage(ThreadQueue,
182 RtlCopyMemory(Msg, &Message->Msg, sizeof(MSG));
185 MsqDestroyMessage(Message);
190 /* Check for hardware events. */
191 Present = MsqFindMessage(ThreadQueue,
200 RtlCopyMemory(Msg, &Message->Msg, sizeof(MSG));
203 MsqDestroyMessage(Message);
208 /* Check for sent messages again. */
209 while (MsqDispatchOneSentMessage(ThreadQueue))
212 /* Check for paint messages. */
213 if (ThreadQueue->PaintPosted)
215 PWINDOW_OBJECT WindowObject;
217 Msg->hwnd = PaintingFindWinToRepaint(Wnd, PsGetWin32Thread());
218 Msg->message = WM_PAINT;
219 Msg->wParam = Msg->lParam = 0;
221 WindowObject = IntGetWindowObject(Msg->hwnd);
222 if (WindowObject != NULL)
224 if (WindowObject->Style & WS_MINIMIZE &&
225 (HICON)NtUserGetClassLong(Msg->hwnd, GCL_HICON, FALSE) != NULL)
227 Msg->message = WM_PAINTICON;
231 if (Msg->hwnd == NULL || Msg->hwnd == Wnd ||
232 IntIsChildWindow(Wnd, Msg->hwnd))
234 if (WindowObject->Flags & WINDOWOBJECT_NEED_INTERNALPAINT &&
235 WindowObject->UpdateRegion == NULL)
237 WindowObject->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
240 MsqDecPaintCountQueue(WindowObject->MessageQueue);
244 IntReleaseWindowObject(WindowObject);
254 NtUserPeekMessage(LPMSG UnsafeMsg,
263 PWINDOW_OBJECT Window;
268 Status = ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
269 Wnd, otWindow, (PVOID*)&Window);
270 if (!NT_SUCCESS(Status))
276 ObmDereferenceObject(Window);
279 if (MsgFilterMax < MsgFilterMin)
285 Present = IntPeekMessage(&SafeMsg, Wnd, MsgFilterMin, MsgFilterMax, RemoveMsg);
288 Status = MmCopyToCaller(UnsafeMsg, &SafeMsg, sizeof(MSG));
289 if (! NT_SUCCESS(Status))
291 /* There is error return documented for PeekMessage().
292 Do the best we can */
293 SetLastNtError(Status);
302 IntWaitMessage(HWND Wnd,
306 PUSER_MESSAGE_QUEUE ThreadQueue;
310 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
314 if (IntPeekMessage(&Msg, Wnd, MsgFilterMin, MsgFilterMax, PM_NOREMOVE))
319 /* Nothing found. Wait for new messages. */
320 Status = MsqWaitForNewMessages(ThreadQueue);
322 while (STATUS_WAIT_0 <= STATUS_WAIT_0 && Status <= STATUS_WAIT_63);
324 SetLastNtError(Status);
330 NtUserGetMessage(LPMSG UnsafeMsg,
335 * FUNCTION: Get a message from the calling thread's message queue.
337 * UnsafeMsg - Pointer to the structure which receives the returned message.
338 * Wnd - Window whose messages are to be retrieved.
339 * MsgFilterMin - Integer value of the lowest message value to be
341 * MsgFilterMax - Integer value of the highest message value to be
348 PWINDOW_OBJECT Window;
353 Status = ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
354 Wnd, otWindow, (PVOID*)&Window);
355 if (!NT_SUCCESS(Status))
361 ObmDereferenceObject(Window);
364 if (MsgFilterMax < MsgFilterMin)
372 GotMessage = IntPeekMessage(&SafeMsg, Wnd, MsgFilterMin, MsgFilterMax, PM_REMOVE);
375 Status = MmCopyToCaller(UnsafeMsg, &SafeMsg, sizeof(MSG));
376 if (! NT_SUCCESS(Status))
378 SetLastNtError(Status);
384 IntWaitMessage(Wnd, MsgFilterMin, MsgFilterMax);
387 while (! GotMessage);
389 return WM_QUIT != SafeMsg.message;
409 NtUserPostMessage(HWND hWnd,
414 PWINDOW_OBJECT Window;
416 PUSER_MESSAGE Message;
421 MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue, wParam);
425 Status = ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
426 hWnd, otWindow, (PVOID*)&Window);
427 if (!NT_SUCCESS(Status))
429 SetLastNtError(Status);
434 Mesg.wParam = wParam;
435 Mesg.lParam = lParam;
436 Message = MsqCreateMessage(&Mesg);
437 MsqPostMessage(Window->MessageQueue, Message);
438 ObmDereferenceObject(Window);
445 NtUserPostThreadMessage(DWORD idThread,
452 PUSER_MESSAGE Message;
457 Status = PsLookupThreadByThreadId((void *)idThread,&peThread);
459 if( Status == STATUS_SUCCESS ) {
460 pThread = peThread->Win32Thread;
461 if( !pThread || !pThread->MessageQueue )
463 ObDereferenceObject( peThread );
468 Mesg.wParam = wParam;
469 Mesg.lParam = lParam;
470 Message = MsqCreateMessage(&Mesg);
471 MsqPostMessage(pThread->MessageQueue, Message);
472 ObDereferenceObject( peThread );
475 SetLastNtError( Status );
481 NtUserQuerySendMessage(DWORD Unknown0)
489 IntSendMessage(HWND hWnd,
497 PWINDOW_OBJECT Window;
499 /* FIXME: Check for a broadcast or topmost destination. */
501 /* FIXME: Call hooks. */
504 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
508 if (!NT_SUCCESS(Status))
513 /* FIXME: Check for an exiting window. */
515 if (NULL != PsGetWin32Thread() &&
516 Window->MessageQueue == PsGetWin32Thread()->MessageQueue)
520 Result = IntCallTrampolineWindowProc(NULL, hWnd, Msg, wParam,
526 if (Window->Unicode == TRUE)
528 Result = IntCallWindowProc(Window->WndProcW, hWnd, Msg, wParam, lParam);
532 Result = IntCallWindowProc(Window->WndProcA, hWnd, Msg, wParam, lParam);
539 PUSER_SENT_MESSAGE Message;
540 PKEVENT CompletionEvent;
542 CompletionEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
543 KeInitializeEvent(CompletionEvent, NotificationEvent, FALSE);
545 Message = ExAllocatePool(NonPagedPool, sizeof(USER_SENT_MESSAGE));
546 Message->Msg.hwnd = hWnd;
547 Message->Msg.message = Msg;
548 Message->Msg.wParam = wParam;
549 Message->Msg.lParam = lParam;
550 Message->CompletionEvent = CompletionEvent;
551 Message->Result = &Result;
552 Message->CompletionQueue = NULL;
553 Message->CompletionCallback = NULL;
554 MsqSendMessage(Window->MessageQueue, Message);
556 ObmDereferenceObject(Window);
557 Status = KeWaitForSingleObject(CompletionEvent,
562 if (Status == STATUS_WAIT_0)
574 NtUserSendMessage(HWND Wnd,
579 return IntSendMessage(Wnd, Msg, wParam, lParam, FALSE);
583 NtUserSendMessageCallback(HWND hWnd,
587 SENDASYNCPROC lpCallBack,
596 NtUserSendNotifyMessage(HWND hWnd,
607 NtUserWaitMessage(VOID)
610 return IntWaitMessage(NULL, 0, 0);
615 NtUserGetQueueStatus(BOOL ClearChanges)
617 PUSER_MESSAGE_QUEUE Queue;
620 Queue = PsGetWin32Thread()->MessageQueue;
622 ExAcquireFastMutex(&Queue->Lock);
624 Result = MAKELONG(Queue->ChangedBits, Queue->WakeBits);
627 Queue->ChangedBits = 0;
630 ExReleaseFastMutex(&Queue->Lock);