From 951d604b0c2b77ef5429df0c019e74f1367c4486 Mon Sep 17 00:00:00 2001 From: James Tabor Date: Thu, 31 Mar 2011 21:20:06 +0000 Subject: [PATCH] [Win32k] - Fix wine post message test, corrected the peek message window selection. - Add a check for dead windows and new message queue flags. - Other miscellaneous fix ups. svn path=/trunk/; revision=51216 --- .../win32/win32k/include/msgqueue.h | 34 ++++++++-- .../subsystems/win32/win32k/ntuser/message.c | 49 +++++++++------ .../subsystems/win32/win32k/ntuser/msgqueue.c | 62 +++++++++++++------ 3 files changed, 103 insertions(+), 42 deletions(-) diff --git a/reactos/subsystems/win32/win32k/include/msgqueue.h b/reactos/subsystems/win32/win32k/include/msgqueue.h index f078a16f23d..5af589ee0a8 100644 --- a/reactos/subsystems/win32/win32k/include/msgqueue.h +++ b/reactos/subsystems/win32/win32k/include/msgqueue.h @@ -78,12 +78,16 @@ typedef struct _USER_MESSAGE_QUEUE HANDLE NewMessagesHandle; /* Last time PeekMessage() was called. */ ULONG LastMsgRead; - /* Current window with focus (ie. receives keyboard input) for this queue. */ - HWND FocusWindow; - /* Current active window for this queue. */ - HWND ActiveWindow; /* Current capture window for this queue. */ HWND CaptureWindow; + PWND spwndCapture; + /* Current window with focus (ie. receives keyboard input) for this queue. */ + HWND FocusWindow; + PWND spwndFocus; + /* Current active window for this queue. */ + HWND ActiveWindow; + PWND spwndActive; + PWND spwndActivePrev; /* Current move/size window for this queue */ HWND MoveSize; /* Current menu owner window for this queue */ @@ -92,6 +96,8 @@ typedef struct _USER_MESSAGE_QUEUE BYTE MenuState; /* Caret information for this queue */ PTHRDCARETINFO CaretInfo; + /* Message Queue Flags */ + DWORD QF_flags; /* queue state tracking */ // Send list QS_SENDMESSAGE @@ -112,8 +118,28 @@ typedef struct _USER_MESSAGE_QUEUE struct _DESKTOP *Desktop; } USER_MESSAGE_QUEUE, *PUSER_MESSAGE_QUEUE; +#define QF_UPDATEKEYSTATE 0x00000001 +#define QF_FMENUSTATUSBREAK 0x00000004 +#define QF_FMENUSTATUS 0x00000008 +#define QF_FF10STATUS 0x00000010 +#define QF_MOUSEMOVED 0x00000020 // See MouseMoved. +#define QF_ACTIVATIONCHANGE 0x00000040 +#define QF_TABSWITCHING 0x00000080 +#define QF_KEYSTATERESET 0x00000100 +#define QF_INDESTROY 0x00000200 +#define QF_LOCKNOREMOVE 0x00000400 +#define QF_FOCUSNULLSINCEACTIVE 0x00000800 +#define QF_DIALOGACTIVE 0x00004000 +#define QF_EVENTDEACTIVATEREMOVED 0x00008000 +#define QF_TRACKMOUSELEAVE 0x00020000 +#define QF_TRACKMOUSEHOVER 0x00040000 +#define QF_TRACKMOUSEFIRING 0x00080000 +#define QF_CAPTURELOCKED 0x00100000 +#define QF_ACTIVEWNDTRACKING 0x00200000 + BOOL FASTCALL MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue); +VOID CALLBACK HungAppSysTimerProc(HWND,UINT,UINT_PTR,DWORD); NTSTATUS FASTCALL co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, diff --git a/reactos/subsystems/win32/win32k/ntuser/message.c b/reactos/subsystems/win32/win32k/ntuser/message.c index 0822009f541..f14ec4745ed 100644 --- a/reactos/subsystems/win32/win32k/ntuser/message.c +++ b/reactos/subsystems/win32/win32k/ntuser/message.c @@ -1233,6 +1233,7 @@ co_IntSendMessageTimeoutSingle( HWND hWnd, if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->head.pti->MessageQueue)) { + // FIXME - Set window hung and add to a list. /* FIXME - Set a LastError? */ RETURN( FALSE); } @@ -1258,7 +1259,7 @@ co_IntSendMessageTimeoutSingle( HWND hWnd, } while ((STATUS_TIMEOUT == Status) && (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) && - !MsqIsHung(Window->head.pti->MessageQueue)); + !MsqIsHung(Window->head.pti->MessageQueue)); // FIXME - Set window hung and add to a list. IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult); @@ -1348,7 +1349,13 @@ co_IntSendMessageNoWait(HWND hWnd, &Result); return Result; } - +/* MSDN: + If you send a message in the range below WM_USER to the asynchronous message + functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its + message parameters cannot include pointers. Otherwise, the operation will fail. + The functions will return before the receiving thread has had a chance to + process the message and the sender will free the memory before it is used. +*/ LRESULT FASTCALL co_IntSendMessageWithCallBack( HWND hWnd, UINT Msg, @@ -2014,24 +2021,23 @@ NtUserMessageCall( HWND hWnd, UserEnterExclusive(); - /* Validate input */ - if (hWnd && (hWnd != INVALID_HANDLE_VALUE)) - { - Window = UserGetWindowObject(hWnd); - if (!Window) - { - UserLeave(); - return FALSE; - } - } - switch(dwType) { case FNID_DEFWINDOWPROC: - if (Window) UserRefObjectCo(Window, &Ref); + /* Validate input */ + if (hWnd && (hWnd != INVALID_HANDLE_VALUE)) + { + Window = UserGetWindowObject(hWnd); + if (!Window) + { + UserLeave(); + return FALSE; + } + } + UserRefObjectCo(Window, &Ref); lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi); Ret = TRUE; - if (Window) UserDerefObjectCo(Window); + UserDerefObjectCo(Window); break; case FNID_SENDNOTIFYMESSAGE: Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam); @@ -2050,7 +2056,6 @@ NtUserMessageCall( HWND hWnd, } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - Ret = FALSE; _SEH2_YIELD(break); } _SEH2_END; @@ -2121,13 +2126,18 @@ NtUserMessageCall( HWND hWnd, } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - Ret = FALSE; _SEH2_YIELD(break); } _SEH2_END; - if (!co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam, - CallBackInfo.CallBack, CallBackInfo.Context, &uResult)) + if (is_pointer_message(Msg)) + { + EngSetLastError(ERROR_MESSAGE_SYNC_ONLY ); + break; + } + + if (!(Ret = co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam, + CallBackInfo.CallBack, CallBackInfo.Context, &uResult))) { DPRINT1("Callback failure!\n"); } @@ -2165,7 +2175,6 @@ NtUserMessageCall( HWND hWnd, } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - Ret = FALSE; _SEH2_YIELD(break); } _SEH2_END; diff --git a/reactos/subsystems/win32/win32k/ntuser/msgqueue.c b/reactos/subsystems/win32/win32k/ntuser/msgqueue.c index f225950dfd6..9f0706706af 100644 --- a/reactos/subsystems/win32/win32k/ntuser/msgqueue.c +++ b/reactos/subsystems/win32/win32k/ntuser/msgqueue.c @@ -121,7 +121,7 @@ ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue, UINT MessageBits) pti = Queue->Thread->Tcb.Win32Thread; if (MessageBits & QS_KEY) - { + { if (--Queue->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY; } if (MessageBits & QS_MOUSEMOVE) // ReactOS hard coded. @@ -244,7 +244,13 @@ co_MsqInsertMouseMessage(MSG* Msg) pwnd != NULL; pwnd = pwnd->spwndNext ) { - if((pwnd->style & WS_VISIBLE) && + if ( pwnd->state2 & WNDS2_INDESTROY || pwnd->state & WNDS_DESTROYED ) + { + DPRINT("The Window is in DESTROY!\n"); + continue; + } + + if((pwnd->style & WS_VISIBLE) && IntPtInWindow(pwnd, Msg->pt.x, Msg->pt.y)) { Msg->hwnd = pwnd->head.h; @@ -623,7 +629,7 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, UINT uTimeout, BOOL Block, INT HookMessage, ULONG_PTR *uResult) { - PTHREADINFO pti; + PTHREADINFO pti, ptirec; PUSER_SENT_MESSAGE Message; KEVENT CompletionEvent; NTSTATUS WaitStatus; @@ -642,8 +648,10 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, pti = PsGetCurrentThreadWin32Thread(); ThreadQueue = pti->MessageQueue; + ptirec = MessageQueue->Thread->Tcb.Win32Thread; ASSERT(ThreadQueue != MessageQueue); - + ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!! + Timeout.QuadPart = (LONGLONG) uTimeout * (LONGLONG) -10000; /* FIXME - increase reference counter of sender's message queue here */ @@ -727,7 +735,7 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, Entry = Entry->Flink; } - DPRINT("MsqSendMessage (blocked) timed out\n"); + DPRINT("MsqSendMessage (blocked) timed out 1\n"); } while (co_MsqDispatchOneSentMessage(ThreadQueue)) ; @@ -787,7 +795,7 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, Entry = Entry->Flink; } - DPRINT("MsqSendMessage timed out\n"); + DPRINT("MsqSendMessage timed out 2\n"); break; } while (co_MsqDispatchOneSentMessage(ThreadQueue)) @@ -860,7 +868,7 @@ static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt ) if (pwndParent == pwndDesktop) break; pt.x += pwnd->rcClient.left - pwndParent->rcClient.left; pt.y += pwnd->rcClient.top - pwndParent->rcClient.top; - + pwnd = pwndParent; co_IntSendMessage( UserHMGetHandle(pwnd), WM_PARENTNOTIFY, MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) ); @@ -902,7 +910,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT } DPRINT("Got mouse message for 0x%x, hittest: 0x%x\n", msg->hwnd, hittest ); - + if (pwndMsg == NULL || pwndMsg->head.pti != pti) { /* Remove and ignore the message */ @@ -972,7 +980,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT } } - if (!((first == 0 && last == 0) || (message >= first || message <= last))) + if (!((first == 0 && last == 0) || (message >= first || message <= last))) { DPRINT("Message out of range!!!\n"); RETURN(FALSE); @@ -1095,8 +1103,8 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT if (pwndTop && pwndTop != pwndDesktop) { - LONG ret = co_IntSendMessage( msg->hwnd, - WM_MOUSEACTIVATE, + LONG ret = co_IntSendMessage( msg->hwnd, + WM_MOUSEACTIVATE, (WPARAM)UserHMGetHandle(pwndTop), MAKELONG( hittest, msg->message)); switch(ret) @@ -1250,7 +1258,7 @@ co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry); - do + do { if (IsListEmpty(CurrentEntry)) break; if (!CurrentMessage) break; @@ -1296,7 +1304,7 @@ MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, PLIST_ENTRY CurrentEntry; PUSER_MESSAGE CurrentMessage; PLIST_ENTRY ListHead; - + CurrentEntry = MessageQueue->PostedMessagesListHead.Flink; ListHead = &MessageQueue->PostedMessagesListHead; @@ -1309,8 +1317,15 @@ MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, if (IsListEmpty(CurrentEntry)) break; if (!CurrentMessage) break; CurrentEntry = CurrentEntry->Flink; - - if ( ( !Window || Window == HWND_BOTTOM || Window->head.h == CurrentMessage->Msg.hwnd ) && +/* + MSDN: + 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL. + 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL. + 3: handle to the window whose messages are to be retrieved. + */ + if ( ( !Window || // 1 + ( Window == HWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2 + ( Window != HWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) || ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) ) { @@ -1342,7 +1357,7 @@ co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, PWND WndFilter, ret = KeWaitForSingleObject(MessageQueue->NewMessages, Executive, UserMode, - FALSE, + FALSE, NULL); UserEnterCo(); return ret; @@ -1357,6 +1372,15 @@ MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue) return ((LargeTickCount.u.LowPart - MessageQueue->LastMsgRead) > MSQ_HUNG); } +VOID +CALLBACK +HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + //DoTheScreenSaver(); + DPRINT("HungAppSysTimerProc\n"); + // Process list of windows that are hung and waiting. +} + BOOLEAN FASTCALL MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQueue) { @@ -1405,7 +1429,7 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue) PUSER_MESSAGE CurrentMessage; PUSER_SENT_MESSAGE CurrentSentMessage; PTHREADINFO pti; - + pti = MessageQueue->Thread->Tcb.Win32Thread; @@ -1428,7 +1452,7 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue) DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n"); /* remove the message from the dispatching list if needed */ - if ((!(CurrentSentMessage->HookMessage & MSQ_SENTNOWAIT)) + if ((!(CurrentSentMessage->HookMessage & MSQ_SENTNOWAIT)) && (CurrentSentMessage->DispatchingListEntry.Flink != NULL)) { RemoveEntryList(&CurrentSentMessage->DispatchingListEntry); @@ -1555,6 +1579,8 @@ MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue) { PDESKTOP desk; + MessageQueue->QF_flags |= QF_INDESTROY; + /* remove the message queue from any desktops */ if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0))) {