+/*
+ * ReactOS W32 Subsystem
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
#include <ddk/ntddk.h>
#include <win32k/win32k.h>
-#include <include/guicheck.h>
#include <include/msgqueue.h>
#include <include/window.h>
#include <include/class.h>
#include <include/winsta.h>
#include <include/callback.h>
#include <include/painting.h>
+#include <internal/safe.h>
-//#define NDEBUG
+#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
-NTSTATUS
-W32kInitMessageImpl(VOID)
+NTSTATUS FASTCALL
+IntInitMessageImpl(VOID)
{
- return(STATUS_SUCCESS);
+ return STATUS_SUCCESS;
}
-NTSTATUS
-W32kCleanupMessageImpl(VOID)
+NTSTATUS FASTCALL
+IntCleanupMessageImpl(VOID)
{
- return(STATUS_SUCCESS);
+ return STATUS_SUCCESS;
}
LRESULT STDCALL
-NtUserDispatchMessage(CONST MSG* lpMsg)
+NtUserDispatchMessage(CONST MSG* UnsafeMsg)
{
LRESULT Result;
- ULONG PaintingFlag;
PWINDOW_OBJECT WindowObject;
NTSTATUS Status;
+ MSG Msg;
+
+ Status = MmCopyFromCaller(&Msg, (PVOID) UnsafeMsg, sizeof(MSG));
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ return 0;
+ }
/* Process timer messages. */
- if (lpMsg->message == WM_TIMER)
+ if (Msg.message == WM_TIMER)
{
- if (lpMsg->lParam)
+ if (Msg.lParam)
{
/* FIXME: Call hooks. */
/* FIXME: Check for continuing validity of timer. */
- return(W32kCallWindowProc((WNDPROC)lpMsg->lParam,
- lpMsg->hwnd,
- lpMsg->message,
- lpMsg->wParam,
- 0 /* GetTickCount() */));
+ return IntCallWindowProc((WNDPROC)Msg.lParam,
+ Msg.hwnd,
+ Msg.message,
+ Msg.wParam,
+ 0 /* GetTickCount() */);
}
}
/* Get the window object. */
Status =
ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
- lpMsg->hwnd,
+ Msg.hwnd,
otWindow,
(PVOID*)&WindowObject);
if (!NT_SUCCESS(Status))
{
- return(0);
- }
-
- /* FIXME: Check for paint message. */
- PaintingFlag = (lpMsg->message == WM_PAINT);
- if (PaintingFlag)
- {
- WindowObject->Flags |= WINDOWOBJECT_NEED_BEGINPAINT;
+ SetLastNtError(Status);
+ return 0;
}
/* FIXME: Call hook procedures. */
/* Call the window procedure. */
- Result = W32kCallWindowProc(NULL /* WndProc */,
- lpMsg->hwnd,
- lpMsg->message,
- lpMsg->wParam,
- lpMsg->lParam);
-
- if (PaintingFlag && WindowObject->Flags & WINDOWOBJECT_NEED_BEGINPAINT &&
- WindowObject->UpdateRegion)
- {
- DbgBreakPoint();
- }
+ if (WindowObject->Unicode == TRUE)
+ {
+ Result = IntCallWindowProc(WindowObject->WndProcW,
+ Msg.hwnd,
+ Msg.message,
+ Msg.wParam,
+ Msg.lParam);
+ }
+ else
+ {
+ Result = IntCallWindowProc(WindowObject->WndProcA,
+ Msg.hwnd,
+ Msg.message,
+ Msg.wParam,
+ Msg.lParam);
+ }
- return(Result);
+ return Result;
}
-BOOL STDCALL
-NtUserGetMessage(LPMSG lpMsg,
- HWND hWnd,
- UINT wMsgFilterMin,
- UINT wMsgFilterMax)
/*
- * FUNCTION: Get a message from the calling thread's message queue.
- * ARGUMENTS:
- * lpMsg - Pointer to the structure which receives the returned message.
- * hWnd - Window whose messages are to be retrieved.
- * wMsgFilterMin - Integer value of the lowest message value to be
- * retrieved.
- * wMsgFilterMax - Integer value of the highest message value to be
- * retrieved.
+ * Internal version of PeekMessage() doing all the work
*/
+BOOL STDCALL
+IntPeekMessage(LPMSG Msg,
+ HWND Wnd,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax,
+ UINT RemoveMsg)
{
PUSER_MESSAGE_QUEUE ThreadQueue;
BOOLEAN Present;
PUSER_MESSAGE Message;
- NTSTATUS Status;
+ BOOLEAN RemoveMessages;
- /* Initialize the thread's win32 state if necessary. */
- W32kGuiCheck();
+ /* The queues and order in which they are checked are documented in the MSDN
+ article on GetMessage() */
ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
- do
- {
- /* Dispatch sent messages here. */
- while (MsqDispatchOneSentMessage(ThreadQueue));
+ /* Inspect RemoveMsg flags */
+ /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
+ RemoveMessages = RemoveMsg & PM_REMOVE;
+
+ /* Dispatch sent messages here. */
+ while (MsqDispatchOneSentMessage(ThreadQueue))
+ ;
- /* Now look for a quit message. */
- /* FIXME: WINE checks the message number filter here. */
- if (ThreadQueue->QuitPosted)
- {
- lpMsg->hwnd = hWnd;
- lpMsg->message = WM_QUIT;
- lpMsg->wParam = ThreadQueue->QuitExitCode;
- lpMsg->lParam = 0;
- ThreadQueue->QuitPosted = FALSE;
- return(FALSE);
- }
+ /* Now look for a quit message. */
+ /* FIXME: WINE checks the message number filter here. */
+ if (ThreadQueue->QuitPosted)
+ {
+ Msg->hwnd = Wnd;
+ Msg->message = WM_QUIT;
+ Msg->wParam = ThreadQueue->QuitExitCode;
+ Msg->lParam = 0;
+ if (RemoveMessages)
+ {
+ ThreadQueue->QuitPosted = FALSE;
+ }
+ return TRUE;
+ }
- /* Now check for normal messages. */
- Present = MsqFindMessage(ThreadQueue,
- FALSE,
- TRUE,
- hWnd,
- wMsgFilterMin,
- wMsgFilterMax,
- &Message);
- if (Present)
+ /* Now check for normal messages. */
+ Present = MsqFindMessage(ThreadQueue,
+ FALSE,
+ RemoveMessages,
+ Wnd,
+ MsgFilterMin,
+ MsgFilterMax,
+ &Message);
+ if (Present)
+ {
+ RtlCopyMemory(Msg, &Message->Msg, sizeof(MSG));
+ if (RemoveMessages)
{
- RtlCopyMemory(lpMsg, &Message->Msg, sizeof(MSG));
- ExFreePool(Message);
- return(TRUE);
+ MsqDestroyMessage(Message);
}
+ return TRUE;
+ }
- /* Check for hardware events. */
- Present = MsqFindMessage(ThreadQueue,
- TRUE,
- TRUE,
- hWnd,
- wMsgFilterMin,
- wMsgFilterMax,
- &Message);
- if (Present)
+ /* Check for hardware events. */
+ Present = MsqFindMessage(ThreadQueue,
+ TRUE,
+ RemoveMessages,
+ Wnd,
+ MsgFilterMin,
+ MsgFilterMax,
+ &Message);
+ if (Present)
+ {
+ RtlCopyMemory(Msg, &Message->Msg, sizeof(MSG));
+ if (RemoveMessages)
{
- RtlCopyMemory(lpMsg, &Message->Msg, sizeof(MSG));
- ExFreePool(Message);
- return(TRUE);
+ MsqDestroyMessage(Message);
}
+ return TRUE;
+ }
- /* Check for sent messages again. */
- while (MsqDispatchOneSentMessage(ThreadQueue));
+ /* Check for sent messages again. */
+ while (MsqDispatchOneSentMessage(ThreadQueue))
+ ;
- /* Check for paint messages. */
- if (ThreadQueue->PaintPosted)
- {
- PWINDOW_OBJECT WindowObject;
+ /* Check for paint messages. */
+ if (ThreadQueue->PaintPosted)
+ {
+ PWINDOW_OBJECT WindowObject;
- lpMsg->hwnd = PaintingFindWinToRepaint(hWnd, PsGetWin32Thread());
- lpMsg->message = WM_PAINT;
- lpMsg->wParam = lpMsg->lParam = 0;
+ Msg->hwnd = PaintingFindWinToRepaint(Wnd, PsGetWin32Thread());
+ Msg->message = WM_PAINT;
+ Msg->wParam = Msg->lParam = 0;
- WindowObject = W32kGetWindowObject(lpMsg->hwnd);
- if (WindowObject != NULL)
+ WindowObject = IntGetWindowObject(Msg->hwnd);
+ if (WindowObject != NULL)
+ {
+ if (WindowObject->Style & WS_MINIMIZE &&
+ (HICON)NtUserGetClassLong(Msg->hwnd, GCL_HICON, FALSE) != NULL)
{
- if (WindowObject->Style & WS_MINIMIZE &&
- (HICON)NtUserGetClassLong(lpMsg->hwnd, GCL_HICON) != NULL)
- {
- lpMsg->message = WM_PAINTICON;
- lpMsg->wParam = 1;
- }
+ Msg->message = WM_PAINTICON;
+ Msg->wParam = 1;
+ }
- if (lpMsg->hwnd == NULL || lpMsg->hwnd == hWnd ||
- W32kIsChildWindow(hWnd, lpMsg->hwnd))
+ if (Msg->hwnd == NULL || Msg->hwnd == Wnd ||
+ IntIsChildWindow(Wnd, Msg->hwnd))
+ {
+ if (WindowObject->Flags & WINDOWOBJECT_NEED_INTERNALPAINT &&
+ WindowObject->UpdateRegion == NULL)
{
- if (WindowObject->Flags & WINDOWOBJECT_NEED_INTERNALPAINT &&
- WindowObject->UpdateRegion == NULL)
+ WindowObject->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
+ if (RemoveMessages)
{
- WindowObject->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
MsqDecPaintCountQueue(WindowObject->MessageQueue);
}
}
- W32kReleaseWindowObject(WindowObject);
}
+ IntReleaseWindowObject(WindowObject);
+ }
+
+ return TRUE;
+ }
- return(TRUE);
+ return FALSE;
+}
+
+BOOL STDCALL
+NtUserPeekMessage(LPMSG UnsafeMsg,
+ HWND Wnd,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax,
+ UINT RemoveMsg)
+{
+ MSG SafeMsg;
+ NTSTATUS Status;
+ BOOL Present;
+ PWINDOW_OBJECT Window;
+
+ /* Validate input */
+ if (NULL != Wnd)
+ {
+ Status = ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
+ Wnd, otWindow, (PVOID*)&Window);
+ if (!NT_SUCCESS(Status))
+ {
+ Wnd = NULL;
+ }
+ else
+ {
+ ObmDereferenceObject(Window);
}
+ }
+ if (MsgFilterMax < MsgFilterMin)
+ {
+ MsgFilterMin = 0;
+ MsgFilterMax = 0;
+ }
- /* Nothing found so far. Wait for new messages. */
- Status = MsqWaitForNewMessages(ThreadQueue);
+ Present = IntPeekMessage(&SafeMsg, Wnd, MsgFilterMin, MsgFilterMax, RemoveMsg);
+ if (Present)
+ {
+ Status = MmCopyToCaller(UnsafeMsg, &SafeMsg, sizeof(MSG));
+ if (! NT_SUCCESS(Status))
+ {
+ /* There is error return documented for PeekMessage().
+ Do the best we can */
+ SetLastNtError(Status);
+ return FALSE;
+ }
}
- while (Status >= STATUS_WAIT_0 && Status <= STATUS_WAIT_63);
- return((BOOLEAN)(-1));
+
+ return Present;
}
-DWORD
-STDCALL
-NtUserMessageCall(
- DWORD Unknown0,
- DWORD Unknown1,
- DWORD Unknown2,
- DWORD Unknown3,
- DWORD Unknown4,
- DWORD Unknown5,
- DWORD Unknown6)
+static BOOL STDCALL
+IntWaitMessage(HWND Wnd,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax)
{
- UNIMPLEMENTED
+ PUSER_MESSAGE_QUEUE ThreadQueue;
+ NTSTATUS Status;
+ MSG Msg;
- return 0;
+ ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
+
+ do
+ {
+ if (IntPeekMessage(&Msg, Wnd, MsgFilterMin, MsgFilterMax, PM_NOREMOVE))
+ {
+ return TRUE;
+ }
+
+ /* Nothing found. Wait for new messages. */
+ Status = MsqWaitForNewMessages(ThreadQueue);
+ }
+ while (STATUS_WAIT_0 <= STATUS_WAIT_0 && Status <= STATUS_WAIT_63);
+
+ SetLastNtError(Status);
+
+ return FALSE;
}
BOOL STDCALL
-NtUserPeekMessage(LPMSG lpMsg,
- HWND hWnd,
- UINT wMsgFilterMin,
- UINT wMsgFilterMax,
- UINT wRemoveMsg)
+NtUserGetMessage(LPMSG UnsafeMsg,
+ HWND Wnd,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax)
/*
* FUNCTION: Get a message from the calling thread's message queue.
* ARGUMENTS:
- * lpMsg - Pointer to the structure which receives the returned message.
- * hWnd - Window whose messages are to be retrieved.
- * wMsgFilterMin - Integer value of the lowest message value to be
- * retrieved.
- * wMsgFilterMax - Integer value of the highest message value to be
- * retrieved.
- * wRemoveMsg - Specificies whether or not to remove messages from the queue after processing
+ * UnsafeMsg - Pointer to the structure which receives the returned message.
+ * Wnd - Window whose messages are to be retrieved.
+ * MsgFilterMin - Integer value of the lowest message value to be
+ * retrieved.
+ * MsgFilterMax - Integer value of the highest message value to be
+ * retrieved.
*/
{
- PUSER_MESSAGE_QUEUE ThreadQueue;
- BOOLEAN Present;
- PUSER_MESSAGE Message;
- BOOLEAN RemoveMessages;
-
- /* Initialize the thread's win32 state if necessary. */
- W32kGuiCheck();
-
- ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
-
- /* Inspect wRemoveMsg flags */
- /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
- RemoveMessages = wRemoveMsg & PM_REMOVE;
-
- /* FIXME: Dispatch sent messages here. */
-
- /* Now look for a quit message. */
- /* FIXME: WINE checks the message number filter here. */
- if (ThreadQueue->QuitPosted)
- {
- lpMsg->hwnd = hWnd;
- lpMsg->message = WM_QUIT;
- lpMsg->wParam = ThreadQueue->QuitExitCode;
- lpMsg->lParam = 0;
- ThreadQueue->QuitPosted = FALSE;
- return(FALSE);
- }
+ BOOL GotMessage;
+ MSG SafeMsg;
+ NTSTATUS Status;
+ PWINDOW_OBJECT Window;
- /* Now check for normal messages. */
- Present = MsqFindMessage(ThreadQueue,
- FALSE,
- RemoveMessages,
- hWnd,
- wMsgFilterMin,
- wMsgFilterMax,
- &Message);
- if (Present)
- {
- RtlCopyMemory(lpMsg, &Message->Msg, sizeof(MSG));
- ExFreePool(Message);
- return(TRUE);
- }
+ /* Validate input */
+ if (NULL != Wnd)
+ {
+ Status = ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
+ Wnd, otWindow, (PVOID*)&Window);
+ if (!NT_SUCCESS(Status))
+ {
+ Wnd = NULL;
+ }
+ else
+ {
+ ObmDereferenceObject(Window);
+ }
+ }
+ if (MsgFilterMax < MsgFilterMin)
+ {
+ MsgFilterMin = 0;
+ MsgFilterMax = 0;
+ }
- /* Check for hardware events. */
- Present = MsqFindMessage(ThreadQueue,
- TRUE,
- RemoveMessages,
- hWnd,
- wMsgFilterMin,
- wMsgFilterMax,
- &Message);
- if (Present)
- {
- RtlCopyMemory(lpMsg, &Message->Msg, sizeof(MSG));
- ExFreePool(Message);
- return(TRUE);
- }
+ do
+ {
+ GotMessage = IntPeekMessage(&SafeMsg, Wnd, MsgFilterMin, MsgFilterMax, PM_REMOVE);
+ if (GotMessage)
+ {
+ Status = MmCopyToCaller(UnsafeMsg, &SafeMsg, sizeof(MSG));
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ return (BOOL) -1;
+ }
+ }
+ else
+ {
+ IntWaitMessage(Wnd, MsgFilterMin, MsgFilterMax);
+ }
+ }
+ while (! GotMessage);
- /* FIXME: Check for sent messages again. */
+ return WM_QUIT != SafeMsg.message;
+}
- /* FIXME: Check for paint messages. */
+DWORD
+STDCALL
+NtUserMessageCall(
+ DWORD Unknown0,
+ DWORD Unknown1,
+ DWORD Unknown2,
+ DWORD Unknown3,
+ DWORD Unknown4,
+ DWORD Unknown5,
+ DWORD Unknown6)
+{
+ UNIMPLEMENTED
- return((BOOLEAN)(-1));
+ return 0;
}
BOOL STDCALL
WPARAM wParam,
LPARAM lParam)
{
- UNIMPLEMENTED;
-
- return 0;
+ PWINDOW_OBJECT Window;
+ MSG Mesg;
+ PUSER_MESSAGE Message;
+ NTSTATUS Status;
+
+ if (WM_QUIT == Msg)
+ {
+ MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue, wParam);
+ }
+ else
+ {
+ Status = ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
+ hWnd, otWindow, (PVOID*)&Window);
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ return FALSE;
+ }
+ Mesg.hwnd = hWnd;
+ Mesg.message = Msg;
+ Mesg.wParam = wParam;
+ Mesg.lParam = lParam;
+ Message = MsqCreateMessage(&Mesg);
+ MsqPostMessage(Window->MessageQueue, Message);
+ ObmDereferenceObject(Window);
+ }
+
+ return TRUE;
}
BOOL STDCALL
WPARAM wParam,
LPARAM lParam)
{
- UNIMPLEMENTED;
+ MSG Mesg;
- return 0;
+ PUSER_MESSAGE Message;
+ PETHREAD peThread;
+ PW32THREAD pThread;
+ NTSTATUS Status;
+
+ Status = PsLookupThreadByThreadId((void *)idThread,&peThread);
+
+ if( Status == STATUS_SUCCESS ) {
+ pThread = peThread->Win32Thread;
+ if( !pThread || !pThread->MessageQueue )
+ {
+ ObDereferenceObject( peThread );
+ return FALSE;
+ }
+ Mesg.hwnd = 0;
+ Mesg.message = Msg;
+ Mesg.wParam = wParam;
+ Mesg.lParam = lParam;
+ Message = MsqCreateMessage(&Mesg);
+ MsqPostMessage(pThread->MessageQueue, Message);
+ ObDereferenceObject( peThread );
+ return TRUE;
+ } else {
+ SetLastNtError( Status );
+ return FALSE;
+ }
}
DWORD STDCALL
}
LRESULT STDCALL
-W32kSendMessage(HWND hWnd,
+IntSendMessage(HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam,
(PVOID*)&Window);
if (!NT_SUCCESS(Status))
{
- return(FALSE);
+ return 0;
}
/* FIXME: Check for an exiting window. */
- if (Window->MessageQueue == PsGetWin32Thread()->MessageQueue)
+ if (NULL != PsGetWin32Thread() &&
+ Window->MessageQueue == PsGetWin32Thread()->MessageQueue)
{
if (KernelMessage)
{
- Result = W32kCallTrampolineWindowProc(NULL, hWnd, Msg, wParam,
+ Result = IntCallTrampolineWindowProc(NULL, hWnd, Msg, wParam,
lParam);
- return(Result);
+ return Result;
}
else
{
- Result = W32kCallWindowProc(NULL, hWnd, Msg, wParam, lParam);
- return(Result);
+ if (Window->Unicode == TRUE)
+ {
+ Result = IntCallWindowProc(Window->WndProcW, hWnd, Msg, wParam, lParam);
+ }
+ else
+ {
+ Result = IntCallWindowProc(Window->WndProcA, hWnd, Msg, wParam, lParam);
+ }
+ return Result;
}
}
else
{
PUSER_SENT_MESSAGE Message;
PKEVENT CompletionEvent;
-
+
CompletionEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
KeInitializeEvent(CompletionEvent, NotificationEvent, FALSE);
NULL);
if (Status == STATUS_WAIT_0)
{
- return(Result);
+ return Result;
}
else
{
- return(FALSE);
+ return FALSE;
}
}
}
LRESULT STDCALL
-NtUserSendMessage(HWND hWnd,
+NtUserSendMessage(HWND Wnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam)
{
- return(W32kSendMessage(hWnd, Msg, wParam, lParam, FALSE));
+ return IntSendMessage(Wnd, Msg, wParam, lParam, FALSE);
}
BOOL STDCALL
SENDASYNCPROC lpCallBack,
ULONG_PTR dwData)
{
- return(0);
+ UNIMPLEMENTED;
+
+ return 0;
}
BOOL STDCALL
BOOL STDCALL
NtUserWaitMessage(VOID)
{
- UNIMPLEMENTED;
- return 0;
+ return IntWaitMessage(NULL, 0, 0);
+}
+
+
+DWORD STDCALL
+NtUserGetQueueStatus(BOOL ClearChanges)
+{
+ PUSER_MESSAGE_QUEUE Queue;
+ DWORD Result;
+
+ Queue = PsGetWin32Thread()->MessageQueue;
+
+ ExAcquireFastMutex(&Queue->Lock);
+
+ Result = MAKELONG(Queue->ChangedBits, Queue->WakeBits);
+ if (ClearChanges)
+ {
+ Queue->ChangedBits = 0;
+ }
+
+ ExReleaseFastMutex(&Queue->Lock);
+
+ return Result;
}
/* EOF */