From 7d1736a1a2a39ab506a3fe94fdd0e27aef1d9c46 Mon Sep 17 00:00:00 2001 From: James Tabor Date: Fri, 3 Dec 2010 15:34:06 +0000 Subject: [PATCH] [Win32k|User32] - Fixed SendNotifyMessage, thanks to Michael Martin callback changes. Fixed DispatchMessage when dealing with thread errors. Fixed all but one of the Get/PeekMessage wine tests. Fixed attaching threads to process information. Plus other fixes. - Implemented support for QS bits, ReplyMessage (not fully correct), and others. - Tested everything here, please post regressions so I can add more applications to the test list. This patch is synced with 49720 and 49772. After that there are graphic issues. - Credits goes to wine for helping with diagnosing issues in the ReactOS message system. svn path=/trunk/; revision=49929 --- reactos/dll/win32/user32/windows/menu.c | 7 +- reactos/dll/win32/user32/windows/message.c | 97 ++++- reactos/include/reactos/win32k/ntuser.h | 3 +- .../win32/win32k/include/msgqueue.h | 44 +- .../subsystems/win32/win32k/include/win32.h | 1 + .../subsystems/win32/win32k/main/dllmain.c | 30 +- .../subsystems/win32/win32k/ntuser/desktop.c | 4 +- .../subsystems/win32/win32k/ntuser/input.c | 14 +- .../subsystems/win32/win32k/ntuser/message.c | 275 ++++++++---- reactos/subsystems/win32/win32k/ntuser/misc.c | 40 +- .../subsystems/win32/win32k/ntuser/msgqueue.c | 407 ++++++++++++------ .../subsystems/win32/win32k/ntuser/painting.c | 10 +- .../win32/win32k/ntuser/simplecall.c | 2 + .../subsystems/win32/win32k/ntuser/timer.c | 2 +- 14 files changed, 657 insertions(+), 279 deletions(-) diff --git a/reactos/dll/win32/user32/windows/menu.c b/reactos/dll/win32/user32/windows/menu.c index 8f8610d64b1..32b00314769 100644 --- a/reactos/dll/win32/user32/windows/menu.c +++ b/reactos/dll/win32/user32/windows/menu.c @@ -3182,7 +3182,7 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, SetCapture(mt.OwnerWnd); (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, mt.OwnerWnd); - ERR("MenuTrackMenu 1\n"); + FIXME("MenuTrackMenu 1\n"); while (! fEndMenu) { PVOID menu = ValidateHandle(mt.CurrentMenu, VALIDATE_TYPE_MENU); @@ -3210,6 +3210,7 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, } WaitMessage(); } + //FIXME("MenuTrackMenu loop 1\n"); } /* check if EndMenu() tried to cancel us, by posting this message */ @@ -3417,6 +3418,7 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, { PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); DispatchMessageW( &msg ); + //FIXME("MenuTrackMenu loop 2\n"); continue; } @@ -3427,8 +3429,9 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, if (fRemove && !(mt.TrackFlags & TF_SKIPREMOVE) ) PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); else mt.TrackFlags &= ~TF_SKIPREMOVE; + //FIXME("MenuTrackMenu loop 3\n"); } - ERR("MenuTrackMenu 2\n"); + FIXME("MenuTrackMenu 2\n"); (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, NULL); SetCapture(NULL); /* release the capture */ diff --git a/reactos/dll/win32/user32/windows/message.c b/reactos/dll/win32/user32/windows/message.c index 300bfc796cf..93bb170214c 100644 --- a/reactos/dll/win32/user32/windows/message.c +++ b/reactos/dll/win32/user32/windows/message.c @@ -1097,7 +1097,6 @@ WINAPI InSendMessage(VOID) { PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo; -// FIXME("ISM %x\n",pcti); if ( pcti ) { if (pcti->CTI_flags & CTI_INSENDMESSAGE) @@ -1118,7 +1117,6 @@ InSendMessageEx( LPVOID lpReserved) { PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo; -// FIXME("ISMEX %x\n",pcti); if (pcti && !(pcti->CTI_flags & CTI_INSENDMESSAGE)) return ISMEX_NOSEND; else @@ -1442,6 +1440,12 @@ IntCallMessageProc(IN PWND Wnd, IN HWND hWnd, IN UINT Msg, IN WPARAM wParam, IN Class = DesktopPtrToUser(Wnd->pcls); WndProc = NULL; + + if ( Wnd->head.pti != GetW32ThreadInfo()) + { // Must be inside the same thread! + SetLastError( ERROR_MESSAGE_SYNC_ONLY ); + return 0; + } /* This is the message exchange for user32. If there's a need to monitor messages, do it here! @@ -1586,11 +1590,16 @@ DispatchMessageA(CONST MSG *lpmsg) MSG UnicodeMsg; PWND Wnd; + if ( lpmsg->message & ~WM_MAXIMUM ) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + if (lpmsg->hwnd != NULL) { Wnd = ValidateHwnd(lpmsg->hwnd); - if (!Wnd || Wnd->head.pti != GetW32ThreadInfo()) - return 0; + if (!Wnd) return 0; } else Wnd = NULL; @@ -1602,7 +1611,7 @@ DispatchMessageA(CONST MSG *lpmsg) if ( lpmsg->message == WM_SYSTIMER ) return NtUserDispatchMessage( (PMSG)lpmsg ); - _SEH2_TRY // wine does this. + _SEH2_TRY // wine does this. Hint: Prevents call to another thread.... { Ret = WndProc(lpmsg->hwnd, lpmsg->message, @@ -1613,7 +1622,6 @@ DispatchMessageA(CONST MSG *lpmsg) { } _SEH2_END; - } else if (Wnd != NULL) { @@ -1654,11 +1662,16 @@ DispatchMessageW(CONST MSG *lpmsg) LRESULT Ret = 0; PWND Wnd; + if ( lpmsg->message & ~WM_MAXIMUM ) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + if (lpmsg->hwnd != NULL) { Wnd = ValidateHwnd(lpmsg->hwnd); - if (!Wnd || Wnd->head.pti != GetW32ThreadInfo()) - return 0; + if (!Wnd) return 0; } else Wnd = NULL; @@ -1795,6 +1808,42 @@ GetMessageW(LPMSG lpMsg, return Res; } +BOOL WINAPI +PeekMessageWorker(PNTUSERGETMESSAGEINFO pInfo, + HWND hWnd, + UINT wMsgFilterMin, + UINT wMsgFilterMax, + UINT wRemoveMsg) +{ + PCLIENTINFO pci; + PCLIENTTHREADINFO pcti; + pci = GetWin32ClientInfo(); + pcti = pci->pClientThreadInfo; + + if (!hWnd && pci && pcti) + { + pci->cSpins++; + + if ((pci->cSpins >= 100) && (pci->dwTIFlags & TIF_SPINNING)) + { // Yield after 100 spin cycles and ready to swap vinyl. + if (!(pci->dwTIFlags & TIF_WAITFORINPUTIDLE)) + { // Not waiting for idle event. + if (!pcti->fsChangeBits && !pcti->fsWakeBits) + { // No messages are available. + if ((GetTickCount() - pcti->tickLastMsgChecked) > 1000) + { // Up the msg read count if over 1 sec. + NtUserGetThreadState(THREADSTATE_UPTIMELASTREAD); + } + pci->cSpins = 0; + ZwYieldExecution(); + FIXME("seeSpins!\n"); + return FALSE; + } + } + } + } + return NtUserPeekMessage(pInfo, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); +} /* * @implemented @@ -1812,7 +1861,7 @@ PeekMessageA(LPMSG lpMsg, PUSER32_THREAD_DATA ThreadData = User32GetThreadData(); MsgConversionCleanup(lpMsg, TRUE, FALSE, NULL); - Res = NtUserPeekMessage(&Info, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); + Res = PeekMessageWorker(&Info, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); if (-1 == (int) Res || !Res) { return FALSE; @@ -1865,7 +1914,7 @@ PeekMessageW( PUSER32_THREAD_DATA ThreadData = User32GetThreadData(); MsgConversionCleanup(lpMsg, FALSE, FALSE, NULL); - Res = NtUserPeekMessage(&Info, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); + Res = PeekMessageWorker(&Info, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); if (-1 == (int) Res || !Res) { return FALSE; @@ -2567,7 +2616,8 @@ DWORD WINAPI RealGetQueueStatus(UINT flags) { - if (flags & ~(QS_SMRESULT|QS_ALLPOSTMESSAGE|QS_ALLINPUT)) + #define QS_TEMPALLINPUT 255 // ATM, do not support QS_RAWINPUT + if (flags & ~(QS_SMRESULT|QS_ALLPOSTMESSAGE|QS_TEMPALLINPUT)) { SetLastError( ERROR_INVALID_FLAGS ); return 0; @@ -2802,6 +2852,8 @@ RealMsgWaitForMultipleObjectsEx( LPHANDLE RealHandles; HANDLE MessageQueueHandle; DWORD Result; + PCLIENTINFO pci; + PCLIENTTHREADINFO pcti; if (dwFlags & ~(MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE)) { @@ -2809,14 +2861,21 @@ RealMsgWaitForMultipleObjectsEx( return WAIT_FAILED; } -/* - if (dwFlags & MWMO_INPUTAVAILABLE) - { - RealGetQueueStatus(dwWakeMask); - } - */ + pci = GetWin32ClientInfo(); + if (!pci) return WAIT_FAILED; - MessageQueueHandle = NtUserMsqSetWakeMask(dwWakeMask); + pcti = pci->pClientThreadInfo; + if (pcti && ( !nCount || !(dwFlags & MWMO_WAITALL) )) + { + if ( (pcti->fsChangeBits & LOWORD(dwWakeMask)) || + ( (dwFlags & MWMO_INPUTAVAILABLE) && (pcti->fsWakeBits & LOWORD(dwWakeMask)) ) ) + { + //FIXME("Chg 0x%x Wake 0x%x Mask 0x%x nCnt %d\n",pcti->fsChangeBits, pcti->fsWakeBits, dwWakeMask, nCount); + return nCount; + } + } + + MessageQueueHandle = NtUserMsqSetWakeMask(MAKELONG(dwWakeMask, dwFlags)); if (MessageQueueHandle == NULL) { SetLastError(0); /* ? */ @@ -2840,7 +2899,7 @@ RealMsgWaitForMultipleObjectsEx( HeapFree(GetProcessHeap(), 0, RealHandles); NtUserMsqClearWakeMask(); - + //FIXME("Result 0X%x\n",Result); return Result; } diff --git a/reactos/include/reactos/win32k/ntuser.h b/reactos/include/reactos/win32k/ntuser.h index 5c4a335ec9f..e6745d9f7fc 100644 --- a/reactos/include/reactos/win32k/ntuser.h +++ b/reactos/include/reactos/win32k/ntuser.h @@ -2104,7 +2104,8 @@ enum ThreadStateRoutines THREADSTATE_PROGMANWINDOW, THREADSTATE_TASKMANWINDOW, THREADSTATE_GETMESSAGETIME, - THREADSTATE_GETINPUTSTATE + THREADSTATE_GETINPUTSTATE, + THREADSTATE_UPTIMELASTREAD }; DWORD_PTR diff --git a/reactos/subsystems/win32/win32k/include/msgqueue.h b/reactos/subsystems/win32/win32k/include/msgqueue.h index 8a8bac87a24..00ea6e131d1 100644 --- a/reactos/subsystems/win32/win32k/include/msgqueue.h +++ b/reactos/subsystems/win32/win32k/include/msgqueue.h @@ -8,10 +8,23 @@ #define MSQ_ISEVENT 2 #define MSQ_SENTNOWAIT 0x80000000 +#define QSIDCOUNTS 6 + +typedef enum _QS_ROS_TYPES +{ + QSRosKey = 0, + QSRosMouseMove, + QSRosMouseButton, + QSRosPostMessage, + QSRosSendMessage, + QSRosHotKey, +}QS_ROS_TYPES,*PQS_ROS_TYPES; + typedef struct _USER_MESSAGE { LIST_ENTRY ListEntry; MSG Msg; + DWORD QS_Flags; } USER_MESSAGE, *PUSER_MESSAGE; struct _USER_MESSAGE_QUEUE; @@ -20,8 +33,10 @@ typedef struct _USER_SENT_MESSAGE { LIST_ENTRY ListEntry; MSG Msg; + DWORD QS_Flags; // Original QS bits used to create this message. PKEVENT CompletionEvent; LRESULT* Result; + LRESULT lResult; struct _USER_MESSAGE_QUEUE* SenderQueue; SENDASYNCPROC CompletionCallback; ULONG_PTR CompletionCallbackContext; @@ -31,16 +46,6 @@ typedef struct _USER_SENT_MESSAGE BOOL HasPackedLParam; } USER_SENT_MESSAGE, *PUSER_SENT_MESSAGE; -typedef struct _USER_SENT_MESSAGE_NOTIFY -{ - SENDASYNCPROC CompletionCallback; - ULONG_PTR CompletionCallbackContext; - LRESULT Result; - HWND hWnd; - UINT Msg; - LIST_ENTRY ListEntry; -} USER_SENT_MESSAGE_NOTIFY, *PUSER_SENT_MESSAGE_NOTIFY; - typedef struct _USER_MESSAGE_QUEUE { /* Reference counter, only access this variable with interlocked functions! */ @@ -52,8 +57,6 @@ typedef struct _USER_MESSAGE_QUEUE LIST_ENTRY SentMessagesListHead; /* Queue of messages posted to the queue. */ LIST_ENTRY PostedMessagesListHead; - /* Queue of sent-message notifies for the queue. */ - LIST_ENTRY NotifyMessagesListHead; /* Queue for hardware messages for the queue. */ LIST_ENTRY HardwareMessagesListHead; /* Lock for the hardware message list. */ @@ -76,8 +79,6 @@ typedef struct _USER_MESSAGE_QUEUE ULONG LastMsgRead; /* Current window with focus (ie. receives keyboard input) for this queue. */ HWND FocusWindow; - /* Count of paints pending. */ - ULONG PaintCount; /* Current active window for this queue. */ HWND ActiveWindow; /* Current capture window for this queue. */ @@ -92,9 +93,11 @@ typedef struct _USER_MESSAGE_QUEUE PTHRDCARETINFO CaretInfo; /* queue state tracking */ - WORD WakeMask; - WORD QueueBits; - WORD ChangedBits; + // Send list QS_SENDMESSAGE + // Post list QS_POSTMESSAGE|QS_HOTKEY|QS_PAINT|QS_TIMER|QS_KEY + // Hard list QS_MOUSE|QS_KEY only + // Accounting of queue bit sets, the rest are flags. QS_TIMER QS_PAINT counts are handled in thread information. + DWORD nCntsQBits[QSIDCOUNTS]; // QS_KEY QS_MOUSEMOVE QS_MOUSEBUTTON QS_POSTMESSAGE QS_SENDMESSAGE QS_HOTKEY /* extra message information */ LPARAM ExtraInfo; @@ -130,6 +133,7 @@ MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, IN PWND Window, IN UINT MsgFilterLow, IN UINT MsgFilterHigh, + IN UINT QSflags, OUT PMSG Message); BOOL APIENTRY co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, @@ -137,6 +141,7 @@ co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, IN PWND Window, IN UINT MsgFilterLow, IN UINT MsgFilterHigh, + IN UINT QSflags, OUT MSG* pMsg); BOOL APIENTRY co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue, @@ -220,7 +225,6 @@ MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd); __inline BOOL MsqIsSignaled( PUSER_MESSAGE_QUEUE queue ); __inline VOID MsqSetQueueBits( PUSER_MESSAGE_QUEUE queue, WORD bits ); -__inline VOID MsqClearQueueBits( PUSER_MESSAGE_QUEUE queue, WORD bits ); BOOL APIENTRY IntInitMessagePumpHook(); BOOL APIENTRY IntUninitMessagePumpHook(); #define MAKE_LONG(x, y) ((((y) & 0xFFFF) << 16) | ((x) & 0xFFFF)) @@ -285,5 +289,9 @@ MsqCalculateMessageTime(IN PLARGE_INTEGER TickCount) VOID FASTCALL IdlePing(VOID); VOID FASTCALL IdlePong(VOID); +BOOL FASTCALL co_MsqReplyMessage(LRESULT); +UINT FASTCALL GetWakeMask(UINT, UINT); +VOID FASTCALL MsqWakeQueue(PUSER_MESSAGE_QUEUE,DWORD,BOOL); +VOID FASTCALL ClearMsgBitsMask(PUSER_MESSAGE_QUEUE,UINT); /* EOF */ diff --git a/reactos/subsystems/win32/win32k/include/win32.h b/reactos/subsystems/win32/win32k/include/win32.h index ed1e645a0a6..68a52a8e6e6 100644 --- a/reactos/subsystems/win32/win32k/include/win32.h +++ b/reactos/subsystems/win32/win32k/include/win32.h @@ -161,6 +161,7 @@ typedef struct _PROCESSINFO struct _DESKTOP* rpdeskStartup; PCLS pclsPrivateList; PCLS pclsPublicList; + INT cThreads; DWORD dwhmodLibLoadedMask; HANDLE ahmodLibLoaded[CLIBS]; struct _WINSTATION_OBJECT *prpwinsta; diff --git a/reactos/subsystems/win32/win32k/main/dllmain.c b/reactos/subsystems/win32/win32k/main/dllmain.c index d0bbae1b025..c8cf433ce04 100644 --- a/reactos/subsystems/win32/win32k/main/dllmain.c +++ b/reactos/subsystems/win32/win32k/main/dllmain.c @@ -268,6 +268,9 @@ Win32kThreadCallback(struct _ETHREAD *Thread, Win32Thread->TIF_flags &= ~TIF_INCLEANUP; co_IntDestroyCaret(Win32Thread); Win32Thread->ppi = PsGetCurrentProcessWin32Process(); + Win32Thread->ptiSibling = Win32Thread->ppi->ptiList; + Win32Thread->ppi->ptiList = Win32Thread; + Win32Thread->ppi->cThreads++; if (Win32Thread->rpdesk && !Win32Thread->pDeskInfo) { Win32Thread->pDeskInfo = Win32Thread->rpdesk->pDeskInfo; @@ -298,16 +301,39 @@ Win32kThreadCallback(struct _ETHREAD *Thread, else { DPRINT1("No TEB for this Thread!\n"); + // System thread running! Now SendMessage should be okay. + Win32Thread->pcti = &Win32Thread->cti; } Win32Thread->pEThread = Thread; } else { + PTHREADINFO pti; PSINGLE_LIST_ENTRY e; DPRINT("Destroying W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql()); Win32Thread->TIF_flags |= TIF_INCLEANUP; + pti = Win32Thread->ppi->ptiList; + if (pti == Win32Thread) + { + Win32Thread->ppi->ptiList = Win32Thread->ptiSibling; + Win32Thread->ppi->cThreads--; + } + else + { + do + { + if (pti->ptiSibling == Win32Thread) + { + pti->ptiSibling = Win32Thread->ptiSibling; + Win32Thread->ppi->cThreads--; + break; + } + pti = pti->ptiSibling; + } + while (pti); + } DceFreeThreadDCE(Win32Thread); HOOK_DestroyThreadHooks(Thread); EVENT_DestroyThreadEvents(Thread); @@ -332,9 +358,7 @@ Win32kThreadCallback(struct _ETHREAD *Thread, e = PopEntryList(&Win32Thread->ReferencesList); } - IntSetThreadDesktop(NULL, - TRUE); - + IntSetThreadDesktop(NULL, TRUE); PsSetThreadWin32Thread(Thread, NULL); } diff --git a/reactos/subsystems/win32/win32k/ntuser/desktop.c b/reactos/subsystems/win32/win32k/ntuser/desktop.c index c4af4525c8c..8e97e1b7b7a 100644 --- a/reactos/subsystems/win32/win32k/ntuser/desktop.c +++ b/reactos/subsystems/win32/win32k/ntuser/desktop.c @@ -1926,7 +1926,7 @@ IntSetThreadDesktop(IN PDESKTOP DesktopObject, RtlZeroMemory(&ctiSave, sizeof(CLIENTTHREADINFO)); - if (W32Thread->pcti && OldDesktop) + if (W32Thread->pcti && OldDesktop && NtCurrentTeb()) { RtlCopyMemory(&ctiSave, W32Thread->pcti, sizeof(CLIENTTHREADINFO)); DPRINT("Free ClientThreadInfo\n"); @@ -1934,7 +1934,7 @@ IntSetThreadDesktop(IN PDESKTOP DesktopObject, W32Thread->pcti = NULL; } - if (!W32Thread->pcti && DesktopObject) + if (!W32Thread->pcti && DesktopObject && NtCurrentTeb()) { DPRINT("Allocate ClientThreadInfo\n"); W32Thread->pcti = DesktopHeapAlloc( DesktopObject, diff --git a/reactos/subsystems/win32/win32k/ntuser/input.c b/reactos/subsystems/win32/win32k/ntuser/input.c index 717e8c4be1c..a8d6d83bb76 100644 --- a/reactos/subsystems/win32/win32k/ntuser/input.c +++ b/reactos/subsystems/win32/win32k/ntuser/input.c @@ -2,7 +2,7 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * PURPOSE: Window classes - * FILE: subsys/win32k/ntuser/class.c + * FILE: subsystems/win32/win32k/ntuser/input.c * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) * REVISION HISTORY: * 06-06-2001 CSH Created @@ -206,13 +206,6 @@ MouseThreadMain(PVOID StartContext) NTSTATUS Status; MOUSE_ATTRIBUTES MouseAttr; - Status = Win32kInitWin32Thread(PsGetCurrentThread()); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n"); - return; //(Status); - } - KeSetPriorityThread(&PsGetCurrentThread()->Tcb, LOW_REALTIME_PRIORITY + 3); @@ -1399,8 +1392,9 @@ IntKeyboardInput(KEYBDINPUT *ki) FocusMessageQueue->Desktop->pDeskInfo->LastInputWasKbd = TRUE; Msg.pt = gpsi->ptCursor; - - MsqPostMessage(FocusMessageQueue, &Msg, FALSE, QS_KEY); + // Post to hardware queue, based on the first part of wine "some GetMessage tests" + // in test_PeekMessage() + MsqPostMessage(FocusMessageQueue, &Msg, TRUE, QS_KEY); } else { diff --git a/reactos/subsystems/win32/win32k/ntuser/message.c b/reactos/subsystems/win32/win32k/ntuser/message.c index 01dcb73a982..70f1678b622 100644 --- a/reactos/subsystems/win32/win32k/ntuser/message.c +++ b/reactos/subsystems/win32/win32k/ntuser/message.c @@ -2,7 +2,7 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * PURPOSE: Messages -* FILE: subsys/win32k/ntuser/message.c +* FILE: subsystems/win32/win32k/ntuser/message.c * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) * REVISION HISTORY: * 06-06-2001 CSH Created @@ -342,12 +342,17 @@ IdlePing(VOID) pti = PsGetCurrentThreadWin32Thread(); - if ( pti && pti->pDeskInfo && pti == ptiForeground ) + if ( pti ) { - if ( pti->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) || - pti->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) ) + pti->pClientInfo->cSpins = 0; // Reset spins. + + if ( pti->pDeskInfo && pti == ptiForeground ) { - co_HOOK_CallHooks(WH_FOREGROUNDIDLE,HC_ACTION,0,0); + if ( pti->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) || + pti->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) ) + { + co_HOOK_CallHooks(WH_FOREGROUNDIDLE,HC_ACTION,0,0); + } } } @@ -371,6 +376,25 @@ IdlePong(VOID) } } +UINT FASTCALL +GetWakeMask(UINT first, UINT last ) +{ + UINT mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */ + + if (first || last) + { + if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY; + if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) || + ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE; + if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER; + if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER; + if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT; + } + else mask = QS_ALLINPUT; + + return mask; +} + static VOID FASTCALL IntCallWndProc( PWND Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { @@ -424,6 +448,12 @@ IntDispatchMessage(PMSG pMsg) pti = PsGetCurrentThreadWin32Thread(); + if ( Window->head.pti != pti) + { + SetLastWin32Error( ERROR_MESSAGE_SYNC_ONLY ); + return 0; + } + if (((pMsg->message == WM_SYSTIMER) || (pMsg->message == WM_TIMER)) && (pMsg->lParam) ) @@ -503,24 +533,34 @@ IntDispatchMessage(PMSG pMsg) } /* -* Internal version of PeekMessage() doing all the work -*/ + * Internal version of PeekMessage() doing all the work + */ BOOL FASTCALL co_IntPeekMessage( PMSG Msg, PWND Window, UINT MsgFilterMin, UINT MsgFilterMax, - UINT RemoveMsg ) + UINT RemoveMsg, + BOOL bGMSG ) { PTHREADINFO pti; + PCLIENTINFO pci; LARGE_INTEGER LargeTickCount; PUSER_MESSAGE_QUEUE ThreadQueue; BOOL RemoveMessages; + UINT ProcessMask; + BOOL Hit = FALSE; pti = PsGetCurrentThreadWin32Thread(); ThreadQueue = pti->MessageQueue; + pci = pti->pClientInfo; RemoveMessages = RemoveMsg & PM_REMOVE; + ProcessMask = HIWORD(RemoveMsg); + + /* Hint, "If wMsgFilterMin and wMsgFilterMax are both zero, PeekMessage returns + all available messages (that is, no range filtering is performed)". */ + if (!ProcessMask) ProcessMask = (QS_ALLPOSTMESSAGE|QS_ALLINPUT); IdlePong(); @@ -528,16 +568,49 @@ co_IntPeekMessage( PMSG Msg, { KeQueryTickCount(&LargeTickCount); ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart; + pti->pcti->tickLastMsgChecked = LargeTickCount.u.LowPart; /* Dispatch sent messages here. */ - while (co_MsqDispatchOneSentMessage(ThreadQueue)) ; + while ( co_MsqDispatchOneSentMessage(ThreadQueue) ) + { + /* if some PM_QS* flags were specified, only handle sent messages from now on */ + if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE; // wine does this; ProcessMask = QS_SENDMESSAGE; + } + if (Hit) return FALSE; + + /* Clear changed bits so we can wait on them if we don't find a message */ + if (ProcessMask & QS_POSTMESSAGE) + { + pti->pcti->fsChangeBits &= ~(QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER); + if (MsgFilterMin == 0 && MsgFilterMax == 0) // wine hack does this; ~0U) + { + pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE; + } + } + + if (ProcessMask & QS_INPUT) + { + pti->pcti->fsChangeBits &= ~QS_INPUT; + } + + /* Now check for normal messages. */ + if ((ProcessMask & QS_POSTMESSAGE) && + MsqPeekMessage( ThreadQueue, + RemoveMessages, + Window, + MsgFilterMin, + MsgFilterMax, + ProcessMask, + Msg )) + { + return TRUE; + } /* Now look for a quit message. */ - if (ThreadQueue->QuitPosted) { /* According to the PSDK, WM_QUIT messages are always returned, regardless - of the filter specified */ + of the filter specified */ Msg->hwnd = NULL; Msg->message = WM_QUIT; Msg->wParam = ThreadQueue->QuitExitCode; @@ -545,49 +618,48 @@ co_IntPeekMessage( PMSG Msg, if (RemoveMessages) { ThreadQueue->QuitPosted = FALSE; + ClearMsgBitsMask(ThreadQueue, QS_POSTMESSAGE); + pti->pcti->fsWakeBits &= ~QS_ALLPOSTMESSAGE; + pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE; } - - return TRUE; - } - - /* Now check for normal messages. */ - if (MsqPeekMessage( ThreadQueue, - RemoveMessages, - Window, - MsgFilterMin, - MsgFilterMax, - Msg )) - { return TRUE; } /* Check for hardware events. */ - if(co_MsqPeekMouseMove(ThreadQueue, - RemoveMessages, - Window, - MsgFilterMin, - MsgFilterMax, - Msg )) + if ((ProcessMask & QS_MOUSE) && + co_MsqPeekMouseMove( ThreadQueue, + RemoveMessages, + Window, + MsgFilterMin, + MsgFilterMax, + Msg )) { return TRUE; } - if(co_MsqPeekHardwareMessage(ThreadQueue, - RemoveMessages, - Window, - MsgFilterMin, - MsgFilterMax, - Msg)) + if ((ProcessMask & QS_INPUT) && + co_MsqPeekHardwareMessage( ThreadQueue, + RemoveMessages, + Window, + MsgFilterMin, + MsgFilterMax, + ProcessMask, + Msg)) { return TRUE; } /* Check for sent messages again. */ - while (co_MsqDispatchOneSentMessage(ThreadQueue)) - ; + while ( co_MsqDispatchOneSentMessage(ThreadQueue) ) + { + if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE; + } + if (Hit) return FALSE; /* Check for paint messages. */ - if( IntGetPaintMessage( Window, + if ((ProcessMask & QS_PAINT) && + pti->cPaintsReady && + IntGetPaintMessage( Window, MsgFilterMin, MsgFilterMax, pti, @@ -597,7 +669,11 @@ co_IntPeekMessage( PMSG Msg, return TRUE; } - if (PostTimerMessages(Window)) + /* This is correct, check for the current threads timers waiting to be + posted to this threads message queue. If any we loop again. + */ + if ((ProcessMask & QS_TIMER) && + PostTimerMessages(Window)) { continue; } @@ -718,11 +794,12 @@ co_IntWaitMessage( PWND Window, do { - if ( co_IntPeekMessage( &Msg, - Window, - MsgFilterMin, - MsgFilterMax, - PM_NOREMOVE)) + if ( co_IntPeekMessage( &Msg, // Dont reenter! + Window, + MsgFilterMin, + MsgFilterMax, + MAKELONG( PM_NOREMOVE, GetWakeMask( MsgFilterMin, MsgFilterMax)), + TRUE ) ) // act like GetMessage. { return TRUE; } @@ -754,6 +831,7 @@ co_IntGetPeekMessage( PMSG pMsg, BOOL bGMSG ) { PWND Window; + PTHREADINFO pti; BOOL Present = FALSE; if ( hWnd == HWND_TOPMOST || hWnd == HWND_BROADCAST ) @@ -781,13 +859,19 @@ co_IntGetPeekMessage( PMSG pMsg, MsgFilterMax = 0; } + if (bGMSG) + { + RemoveMsg |= ((GetWakeMask( MsgFilterMin, MsgFilterMax ))<< 16); + } + do { Present = co_IntPeekMessage( pMsg, Window, MsgFilterMin, MsgFilterMax, - RemoveMsg ); + RemoveMsg, + bGMSG ); if (Present) { // The WH_GETMESSAGE hook enables an application to monitor messages about to @@ -796,13 +880,19 @@ co_IntGetPeekMessage( PMSG pMsg, co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)pMsg); if ( bGMSG ) - return (WM_QUIT != pMsg->message); + { + Present = (WM_QUIT != pMsg->message); + break; + } } if ( bGMSG ) { if ( !co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax) ) - return -1; + { + Present = -1; + break; + } } else { @@ -821,6 +911,14 @@ co_IntGetPeekMessage( PMSG pMsg, } while( bGMSG && !Present ); + pti = PsGetCurrentThreadWin32Thread(); + // Been spinning, time to swap vinyl... + if (pti->pClientInfo->cSpins >= 100) + { + // Clear the spin cycle to fix the mix. + pti->pClientInfo->cSpins = 0; + //if (!(pti->TIF_flags & TIF_SPINNING)) FIXME need to swap vinyl.. + } return Present; } @@ -947,7 +1045,7 @@ UserPostMessage( HWND Wnd, MsqPostQuitMessage(Window->head.pti->MessageQueue, wParam); } else - { + { Message.hwnd = Wnd; Message.message = Msg; Message.wParam = wParam; @@ -1283,7 +1381,9 @@ co_IntSendMessageWithCallBack( HWND hWnd, Message->Msg.lParam = lParamPacked; Message->CompletionEvent = NULL; Message->Result = 0; - Message->SenderQueue = NULL; //Win32Thread->MessageQueue; + Message->lResult = 0; + Message->QS_Flags = 0; + Message->SenderQueue = NULL; // mjmartin, you are right! This is null. Win32Thread->MessageQueue; IntReferenceMessageQueue(Window->head.pti->MessageQueue); Message->CompletionCallback = CompletionCallback; @@ -1291,6 +1391,9 @@ co_IntSendMessageWithCallBack( HWND hWnd, Message->HookMessage = MSQ_NORMAL | MSQ_SENTNOWAIT; Message->HasPackedLParam = (lParamBufferSize > 0); + Message->QS_Flags = QS_SENDMESSAGE; + MsqWakeQueue(Window->head.pti->MessageQueue, QS_SENDMESSAGE, FALSE); + InsertTailList(&Window->head.pti->MessageQueue->SentMessagesListHead, &Message->ListEntry); IntDereferenceMessageQueue(Window->head.pti->MessageQueue); @@ -1468,7 +1571,7 @@ UserSendNotifyMessage( HWND hWnd, WPARAM wParam, LPARAM lParam ) { - BOOL Result = TRUE; + BOOL Ret = TRUE; if (FindMsgMemory(Msg) != 0) { @@ -1491,37 +1594,28 @@ UserSendNotifyMessage( HWND hWnd, UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam); for (i = 0; List[i]; i++) { - UserSendNotifyMessage(List[i], Msg, wParam, lParam); + Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam); + if (!Ret) + { + DPRINT1("SendNotifyMessage: Failed in Broadcast!\n"); + break; + } } ExFreePool(List); } } else { - ULONG_PTR PResult; - PTHREADINFO pti; - PWND Window; - - if ( !(Window = UserGetWindowObject(hWnd)) ) return FALSE; - - pti = PsGetCurrentThreadWin32Thread(); - - if (Window->head.pti->MessageQueue != pti->MessageQueue) - { // Send message w/o waiting for it. - Result = UserPostMessage(hWnd, Msg, wParam, lParam); - } - else - { // Handle message and callback. - Result = co_IntSendMessageTimeoutSingle( hWnd, - Msg, - wParam, - lParam, - SMTO_NORMAL, - 0, - &PResult ); - } + ULONG_PTR lResult = 0; + Ret = co_IntSendMessageWithCallBack( hWnd, + Msg, + wParam, + lParam, + NULL, + 0, + &lResult); } - return Result; + return Ret; } @@ -1537,15 +1631,13 @@ IntGetQueueStatus(DWORD Changes) // wine: Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT); - Result = MAKELONG(Queue->ChangedBits & Changes, Queue->QueueBits & Changes); + /* High word, types of messages currently in the queue. + Low word, types of messages that have been added to the queue and that + are still in the queue + */ + Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes); - if (pti->pcti) - { - pti->pcti->fsChangeBits = Queue->ChangedBits; - pti->pcti->fsChangeBits &= ~Changes; - } - - Queue->ChangedBits &= ~Changes; + pti->pcti->fsChangeBits &= ~Changes; return Result; } @@ -1684,9 +1776,9 @@ NtUserWaitMessage(VOID) BOOL ret; UserEnterExclusive(); - + DPRINT("NtUserWaitMessage Enter\n"); ret = co_IntWaitMessage(NULL, 0, 0); - + DPRINT("NtUserWaitMessage Leave\n"); UserLeave(); return ret; @@ -2338,6 +2430,13 @@ NtUserWaitForInputIdle( IN HANDLE hProcess, if (dwMilliseconds != INFINITE) Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000; + W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE; + for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling) + { + pti->TIF_flags |= TIF_WAITFORINPUTIDLE; + pti->pClientInfo->dwTIFlags = pti->TIF_flags; + } + DPRINT("WFII: ppi 0x%x\n",W32Process); DPRINT("WFII: waiting for %p\n", Handles[1] ); do @@ -2368,7 +2467,7 @@ NtUserWaitForInputIdle( IN HANDLE hProcess, case STATUS_WAIT_2: { MSG Msg; - co_IntPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE ); + co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE); DPRINT1("WFII: WAIT 2\n"); } break; @@ -2387,6 +2486,12 @@ NtUserWaitForInputIdle( IN HANDLE hProcess, while (TRUE); WaitExit: + for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling) + { + pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE; + pti->pClientInfo->dwTIFlags = pti->TIF_flags; + } + W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE; ObDereferenceObject(Process); UserLeave(); return Status; diff --git a/reactos/subsystems/win32/win32k/ntuser/misc.c b/reactos/subsystems/win32/win32k/ntuser/misc.c index d884d0c145f..c2c240d033e 100644 --- a/reactos/subsystems/win32/win32k/ntuser/misc.c +++ b/reactos/subsystems/win32/win32k/ntuser/misc.c @@ -2,7 +2,7 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * PURPOSE: Misc User funcs - * FILE: subsystem/win32/win32k/ntuser/misc.c + * FILE: subsystems/win32/win32k/ntuser/misc.c * PROGRAMER: Ge van Geldorp (ge@gse.nl) * REVISION HISTORY: * 2003/05/22 Created @@ -102,6 +102,8 @@ NtUserGetThreadState( break; case THREADSTATE_INSENDMESSAGE: { + PUSER_SENT_MESSAGE Message; + PLIST_ENTRY Entry; PUSER_MESSAGE_QUEUE MessageQueue = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->MessageQueue; DPRINT1("THREADSTATE_INSENDMESSAGE\n"); @@ -109,21 +111,39 @@ NtUserGetThreadState( ret = ISMEX_NOSEND; if (!IsListEmpty(&MessageQueue->SentMessagesListHead)) { - ret = ISMEX_SEND; + Entry = MessageQueue->SentMessagesListHead.Flink; + Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry); + + if (Message->SenderQueue) + ret = ISMEX_SEND; + else + { + if (Message->CompletionCallback) + ret = ISMEX_CALLBACK; + else + ret = ISMEX_NOTIFY; + } + /* if ReplyMessage */ + if (Message->QS_Flags & QS_SMRESULT) ret |= ISMEX_REPLIED; } - else if (!IsListEmpty(&MessageQueue->NotifyMessagesListHead)) - { - /* FIXME Need to set message flag when in callback mode with notify */ - ret = ISMEX_NOTIFY; - } - /* FIXME Need to set message flag if replied to or ReplyMessage */ + break; } - case THREADSTATE_GETMESSAGETIME: - /* FIXME Needs more work! */ + case THREADSTATE_GETMESSAGETIME: ret = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->timeLast; break; + case THREADSTATE_UPTIMELASTREAD: + { + PTHREADINFO pti; + LARGE_INTEGER LargeTickCount; + pti = PsGetCurrentThreadWin32Thread(); + KeQueryTickCount(&LargeTickCount); + pti->MessageQueue->LastMsgRead = LargeTickCount.u.LowPart; + pti->pcti->tickLastMsgChecked = LargeTickCount.u.LowPart; + } + break; + case THREADSTATE_GETINPUTSTATE: ret = LOWORD(IntGetQueueStatus(QS_POSTMESSAGE|QS_TIMER|QS_PAINT|QS_SENDMESSAGE|QS_INPUT)) & (QS_KEY | QS_MOUSEBUTTON); break; diff --git a/reactos/subsystems/win32/win32k/ntuser/msgqueue.c b/reactos/subsystems/win32/win32k/ntuser/msgqueue.c index b03ba84365b..9b5ac9cd269 100644 --- a/reactos/subsystems/win32/win32k/ntuser/msgqueue.c +++ b/reactos/subsystems/win32/win32k/ntuser/msgqueue.c @@ -1,21 +1,3 @@ -/* - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ /* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -41,74 +23,6 @@ static PAGED_LOOKASIDE_LIST MessageLookasideList; /* FUNCTIONS *****************************************************************/ -HANDLE FASTCALL -IntMsqSetWakeMask(DWORD WakeMask) -{ - PTHREADINFO Win32Thread; - PUSER_MESSAGE_QUEUE MessageQueue; - HANDLE MessageEventHandle; - - Win32Thread = PsGetCurrentThreadWin32Thread(); - if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL) - return 0; - - MessageQueue = Win32Thread->MessageQueue; - MessageQueue->WakeMask = WakeMask; - MessageEventHandle = MessageQueue->NewMessagesHandle; - - if (Win32Thread->pcti) - Win32Thread->pcti->fsWakeMask = WakeMask; - - IdlePing(); - - return MessageEventHandle; -} - -BOOL FASTCALL -IntMsqClearWakeMask(VOID) -{ - PTHREADINFO Win32Thread; - PUSER_MESSAGE_QUEUE MessageQueue; - - Win32Thread = PsGetCurrentThreadWin32Thread(); - if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL) - return FALSE; - - MessageQueue = Win32Thread->MessageQueue; -// HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt) - MessageQueue->WakeMask = ~0; - - if (Win32Thread->pcti) - Win32Thread->pcti->fsWakeMask = 0; - - IdlePong(); - - return TRUE; -} - -VOID FASTCALL -MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue, DWORD MessageBits) -{ - Queue->QueueBits |= MessageBits; - Queue->ChangedBits |= MessageBits; - if (Queue->WakeMask & MessageBits) - KeSetEvent(Queue->NewMessages, IO_NO_INCREMENT, FALSE); -} - -VOID FASTCALL -MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue) -{ - Queue->PaintCount++; - MsqWakeQueue(Queue, QS_PAINT); -} - -VOID FASTCALL -MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue) -{ - Queue->PaintCount--; -} - - INIT_FUNCTION NTSTATUS NTAPI @@ -125,12 +39,153 @@ MsqInitializeImpl(VOID) return(STATUS_SUCCESS); } +HANDLE FASTCALL +IntMsqSetWakeMask(DWORD WakeMask) +{ + PTHREADINFO Win32Thread; + PUSER_MESSAGE_QUEUE MessageQueue; + HANDLE MessageEventHandle; + DWORD dwFlags = HIWORD(WakeMask); + + Win32Thread = PsGetCurrentThreadWin32Thread(); + if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL) + return 0; + + MessageQueue = Win32Thread->MessageQueue; +// Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient + MessageEventHandle = MessageQueue->NewMessagesHandle; + + if (Win32Thread->pcti) + { + if ( (Win32Thread->pcti->fsChangeBits & LOWORD(WakeMask)) || + ( (dwFlags & MWMO_INPUTAVAILABLE) && (Win32Thread->pcti->fsWakeBits & LOWORD(WakeMask)) ) ) + { + DPRINT1("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread->pcti->fsChangeBits, Win32Thread->pcti->fsWakeBits, WakeMask); + KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE); // Wake it up! + return MessageEventHandle; + } + } + + IdlePing(); + + return MessageEventHandle; +} + +BOOL FASTCALL +IntMsqClearWakeMask(VOID) +{ + PTHREADINFO Win32Thread; + + Win32Thread = PsGetCurrentThreadWin32Thread(); + if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL) + return FALSE; + // Very hacky, but that is what they do. + Win32Thread->pcti->fsWakeBits = 0; + + IdlePong(); + + return TRUE; +} + +/* + Due to the uncertainty of knowing what was set in our multilevel message queue, + and even if the bits are all cleared. The same as cTimers/cPaintsReady. + I think this is the best solution... (jt) */ +VOID FASTCALL +MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue, DWORD MessageBits, BOOL KeyEvent) +{ + PTHREADINFO pti; + + pti = Queue->Thread->Tcb.Win32Thread; + pti->pcti->fsWakeBits |= MessageBits; + pti->pcti->fsChangeBits |= MessageBits; + + // Start bit accounting to help clear the main set of bits. + if (MessageBits & QS_KEY) Queue->nCntsQBits[QSRosKey]++; + if (MessageBits & QS_MOUSEMOVE) Queue->nCntsQBits[QSRosMouseMove]++; + if (MessageBits & QS_MOUSEBUTTON) Queue->nCntsQBits[QSRosMouseButton]++; + if (MessageBits & QS_POSTMESSAGE) Queue->nCntsQBits[QSRosPostMessage]++; + if (MessageBits & QS_SENDMESSAGE) Queue->nCntsQBits[QSRosSendMessage]++; + if (MessageBits & QS_HOTKEY) Queue->nCntsQBits[QSRosHotKey]++; + + if (KeyEvent) + KeSetEvent(Queue->NewMessages, IO_NO_INCREMENT, FALSE); +} + +VOID FASTCALL +ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue, UINT MessageBits) +{ + PTHREADINFO pti; + UINT ClrMask = 0; + + pti = Queue->Thread->Tcb.Win32Thread; + + if (MessageBits & QS_KEY) + { + if (--Queue->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY; + } + if (MessageBits & QS_MOUSEMOVE) // ReactOS hard coded. + { // Account for tracking mouse moves.. + if (--Queue->nCntsQBits[QSRosMouseMove] == 0) ClrMask |= QS_MOUSEMOVE; + // Handle mouse move bits here. + if (Queue->MouseMoved) ClrMask |= QS_MOUSEMOVE; + } + if (MessageBits & QS_MOUSEBUTTON) + { + if (--Queue->nCntsQBits[QSRosMouseButton] == 0) ClrMask |= QS_MOUSEBUTTON; + } + if (MessageBits & QS_POSTMESSAGE) + { + if (--Queue->nCntsQBits[QSRosPostMessage] == 0) ClrMask |= QS_POSTMESSAGE; + } + if (MessageBits & QS_TIMER) // ReactOS hard coded. + { // Handle timer bits here. + if ( pti->cTimersReady ) + { + if (--pti->cTimersReady == 0) ClrMask |= QS_TIMER; + } + } + if (MessageBits & QS_PAINT) // ReactOS hard coded. + { // Handle paint bits here. + if ( pti->cPaintsReady ) + { + if (--pti->cPaintsReady == 0) ClrMask |= QS_PAINT; + } + } + if (MessageBits & QS_SENDMESSAGE) + { + if (--Queue->nCntsQBits[QSRosSendMessage] == 0) ClrMask |= QS_SENDMESSAGE; + } + if (MessageBits & QS_HOTKEY) + { + if (--Queue->nCntsQBits[QSRosHotKey] == 0) ClrMask |= QS_HOTKEY; + } + + pti->pcti->fsWakeBits &= ~ClrMask; + pti->pcti->fsChangeBits &= ~ClrMask; +} + +VOID FASTCALL +MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue) +{ + PTHREADINFO pti; + pti = Queue->Thread->Tcb.Win32Thread; + pti->cPaintsReady++; + MsqWakeQueue(Queue, QS_PAINT, TRUE); +} + +VOID FASTCALL +MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue) +{ + ClearMsgBitsMask(Queue, QS_PAINT); +} + VOID FASTCALL MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg) { MessageQueue->MouseMoveMsg = *Msg; MessageQueue->MouseMoved = TRUE; - MsqWakeQueue(MessageQueue, QS_MOUSEMOVE); + MsqWakeQueue(MessageQueue, QS_MOUSEMOVE, TRUE); } VOID FASTCALL @@ -366,6 +421,7 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue) PUSER_SENT_MESSAGE Message; PLIST_ENTRY Entry; LRESULT Result; + PTHREADINFO pti; if (IsListEmpty(&MessageQueue->SentMessagesListHead)) { @@ -376,11 +432,20 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue) Entry = RemoveHeadList(&MessageQueue->SentMessagesListHead); Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry); + pti = MessageQueue->Thread->Tcb.Win32Thread; + // Processing a message sent to it from another thread. + if ( MessageQueue != Message->SenderQueue ) // most likely, but, to be sure. + { + pti->pcti->CTI_flags |= CTI_INSENDMESSAGE; // Let the user know... + } + /* insert it to the list of messages that are currently dispatched by this message queue */ InsertTailList(&MessageQueue->LocalDispatchingMessagesHead, &Message->ListEntry); + ClearMsgBitsMask(MessageQueue, Message->QS_Flags); + if (Message->HookMessage == MSQ_ISHOOK) { // Direct Hook Call processor Result = co_CallHook( Message->Msg.message, // HookId @@ -419,6 +484,11 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue) /* still keep the sender's message queue locked, so the sender can't exit the MsqSendMessage() function (if timed out) */ + if (Message->QS_Flags & QS_SMRESULT) + { + Result = Message->lResult; + } + /* Let the sender know the result. */ if (Message->Result != NULL) { @@ -456,6 +526,9 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue) /* free the message */ ExFreePoolWithTag(Message, TAG_USRMSG); + + pti->pcti->CTI_flags &= ~CTI_INSENDMESSAGE; + return(TRUE); } @@ -483,6 +556,7 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow) if (PostedMessage->Msg.hwnd == Window->head.h) { RemoveEntryList(&PostedMessage->ListEntry); + ClearMsgBitsMask(MessageQueue, PostedMessage->QS_Flags); MsqDestroyMessage(PostedMessage); CurrentEntry = MessageQueue->PostedMessagesListHead.Flink; } @@ -504,6 +578,7 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow) DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n"); RemoveEntryList(&SentMessage->ListEntry); + ClearMsgBitsMask(MessageQueue, SentMessage->QS_Flags); /* remove the message from the dispatching list if neede */ if ((!(SentMessage->HookMessage & MSQ_SENTNOWAIT)) @@ -581,6 +656,8 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, Message->Msg.lParam = lParam; Message->CompletionEvent = &CompletionEvent; Message->Result = &Result; + Message->lResult = 0; + Message->QS_Flags = 0; Message->SenderQueue = ThreadQueue; IntReferenceMessageQueue(ThreadQueue); Message->CompletionCallback = NULL; @@ -596,7 +673,8 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, /* queue it in the destination's message queue */ InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry); - MsqWakeQueue(MessageQueue, QS_SENDMESSAGE); + Message->QS_Flags = QS_SENDMESSAGE; + MsqWakeQueue(MessageQueue, QS_SENDMESSAGE, TRUE); /* we can't access the Message anymore since it could have already been deleted! */ @@ -746,7 +824,9 @@ MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg, BOOLEAN HardwareMessa InsertTailList(&MessageQueue->HardwareMessagesListHead, &Message->ListEntry); } - MsqWakeQueue(MessageQueue, MessageBits); + + Message->QS_Flags = MessageBits; + MsqWakeQueue(MessageQueue, MessageBits, (MessageBits & QS_TIMER ? FALSE : TRUE)); } VOID FASTCALL @@ -754,7 +834,7 @@ MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue, ULONG ExitCode) { MessageQueue->QuitPosted = TRUE; MessageQueue->QuitExitCode = ExitCode; - MsqWakeQueue(MessageQueue, QS_POSTMESSAGE); + MsqWakeQueue(MessageQueue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE); } /*********************************************************************** @@ -1122,17 +1202,38 @@ co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue, *pMsg = msg; if(Remove) + { + ClearMsgBitsMask(MessageQueue, QS_MOUSEMOVE); MessageQueue->MouseMoved = FALSE; + } return AcceptMessage; } +/* check whether a message filter contains at least one potential hardware message */ +static INT FASTCALL +filter_contains_hw_range( UINT first, UINT last ) +{ + /* hardware message ranges are (in numerical order): + * WM_NCMOUSEFIRST .. WM_NCMOUSELAST + * WM_KEYFIRST .. WM_KEYLAST + * WM_MOUSEFIRST .. WM_MOUSELAST + */ + if (!last) --last; + if (last < WM_NCMOUSEFIRST) return 0; + if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0; + if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0; + if (first > WM_MOUSELAST) return 0; + return 1; +} + BOOL APIENTRY co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, IN BOOL Remove, IN PWND Window, IN UINT MsgFilterLow, IN UINT MsgFilterHigh, + IN UINT QSflags, OUT MSG* pMsg) { @@ -1141,33 +1242,45 @@ co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, PLIST_ENTRY ListHead, CurrentEntry = NULL; MSG msg; + if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE; + ListHead = &MessageQueue->HardwareMessagesListHead; CurrentEntry = ListHead->Flink; - while(CurrentEntry != ListHead) - { - CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, + if (IsListEmpty(CurrentEntry)) return FALSE; + + CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry); - - msg = CurrentMessage->Msg; - - AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh); - + do + { + if (IsListEmpty(CurrentEntry)) break; + if (!CurrentMessage) break; CurrentEntry = CurrentMessage->ListEntry.Flink; - if (Remove) + if ( (( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && (CurrentMessage->QS_Flags & QSflags)) || + ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) { - RemoveEntryList(&CurrentMessage->ListEntry); - MsqDestroyMessage(CurrentMessage); - } + msg = CurrentMessage->Msg; - if(AcceptMessage) - { - *pMsg = msg; - return TRUE; - } + AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh); + if (Remove) + { + RemoveEntryList(&CurrentMessage->ListEntry); + ClearMsgBitsMask(MessageQueue, CurrentMessage->QS_Flags); + MsqDestroyMessage(CurrentMessage); + } + + if (AcceptMessage) + { + *pMsg = msg; + return TRUE; + } + } + CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, + ListEntry); } + while(CurrentEntry != ListHead); return FALSE; } @@ -1178,6 +1291,7 @@ MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, IN PWND Window, IN UINT MsgFilterLow, IN UINT MsgFilterHigh, + IN UINT QSflags, OUT PMSG Message) { PLIST_ENTRY CurrentEntry; @@ -1186,29 +1300,35 @@ MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue, CurrentEntry = MessageQueue->PostedMessagesListHead.Flink; ListHead = &MessageQueue->PostedMessagesListHead; - while (CurrentEntry != ListHead) - { - CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, + + if (IsListEmpty(CurrentEntry)) return FALSE; + + CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry); - if ( ( !Window || - PtrToInt(Window) == 1 || - Window->head.h == CurrentMessage->Msg.hwnd ) && - ( (MsgFilterLow == 0 && MsgFilterHigh == 0) || - ( MsgFilterLow <= CurrentMessage->Msg.message && - MsgFilterHigh >= CurrentMessage->Msg.message ) ) ) + do + { + if (IsListEmpty(CurrentEntry)) break; + if (!CurrentMessage) break; + CurrentEntry = CurrentEntry->Flink; + + if ( ( !Window || Window == HWND_BOTTOM || Window->head.h == CurrentMessage->Msg.hwnd ) && + ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) || + ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) ) { - *Message= CurrentMessage->Msg; + *Message = CurrentMessage->Msg; if (Remove) { RemoveEntryList(&CurrentMessage->ListEntry); + ClearMsgBitsMask(MessageQueue, CurrentMessage->QS_Flags); MsqDestroyMessage(CurrentMessage); } - return(TRUE); } - CurrentEntry = CurrentEntry->Flink; + CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, + ListEntry); } + while (CurrentEntry != ListHead); return(FALSE); } @@ -1257,9 +1377,6 @@ MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQu KeQueryTickCount(&LargeTickCount); MessageQueue->LastMsgRead = LargeTickCount.u.LowPart; MessageQueue->FocusWindow = NULL; - MessageQueue->PaintCount = 0; -// HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt) - MessageQueue->WakeMask = ~0; MessageQueue->NewMessagesHandle = NULL; Status = ZwCreateEvent(&MessageQueue->NewMessagesHandle, EVENT_ALL_ACCESS, @@ -1288,6 +1405,10 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue) PLIST_ENTRY CurrentEntry; PUSER_MESSAGE CurrentMessage; PUSER_SENT_MESSAGE CurrentSentMessage; + PTHREADINFO pti; + + pti = MessageQueue->Thread->Tcb.Win32Thread; + /* cleanup posted messages */ while (!IsListEmpty(&MessageQueue->PostedMessagesListHead)) @@ -1391,6 +1512,16 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue) locked later */ } + // Clear it all out. + pti->pcti->fsWakeBits = 0; + pti->pcti->fsChangeBits = 0; + + MessageQueue->nCntsQBits[QSRosKey] = 0; + MessageQueue->nCntsQBits[QSRosMouseMove] = 0; + MessageQueue->nCntsQBits[QSRosMouseButton] = 0; + MessageQueue->nCntsQBits[QSRosPostMessage] = 0; + MessageQueue->nCntsQBits[QSRosSendMessage] = 0; + MessageQueue->nCntsQBits[QSRosHotKey] = 0; } PUSER_MESSAGE_QUEUE FASTCALL @@ -1475,6 +1606,38 @@ MsqGetMessageExtraInfo(VOID) return MessageQueue->ExtraInfo; } +BOOL FASTCALL +co_MsqReplyMessage( LRESULT lResult ) +{ + PUSER_SENT_MESSAGE Message; + PLIST_ENTRY Entry; + PTHREADINFO pti; + PUSER_MESSAGE_QUEUE MessageQueue; + + pti = PsGetCurrentThreadWin32Thread(); + MessageQueue = pti->MessageQueue; + + if(!MessageQueue) return FALSE; + + if (IsListEmpty(&MessageQueue->SentMessagesListHead)) + { + return(FALSE); + } + // Do we loop through all msgs or just set the first one? + Entry = MessageQueue->SentMessagesListHead.Flink; + Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry); + + if (Message->QS_Flags & QS_SMRESULT) return FALSE; + + if (Message->SenderQueue || Message->CompletionCallback) + { + Message->lResult = lResult; + Message->QS_Flags |= QS_SMRESULT; + MsqWakeQueue(MessageQueue, 0, TRUE); // Wake it up!? Bits? + } + return TRUE; +} + HWND FASTCALL MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd) { diff --git a/reactos/subsystems/win32/win32k/ntuser/painting.c b/reactos/subsystems/win32/win32k/ntuser/painting.c index 6eca443034a..6cc9b5a15bd 100644 --- a/reactos/subsystems/win32/win32k/ntuser/painting.c +++ b/reactos/subsystems/win32/win32k/ntuser/painting.c @@ -2,7 +2,7 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * PURPOSE: Window painting function - * FILE: subsys/win32k/ntuser/painting.c + * FILE: subsystems/win32/win32k/ntuser/painting.c * PROGRAMER: Filip Navara (xnavara@volny.cz) * REVISION HISTORY: * 06/06/2001 Created (?) @@ -660,9 +660,7 @@ IntGetPaintMessage( MSG *Message, BOOL Remove) { - PUSER_MESSAGE_QUEUE MessageQueue = (PUSER_MESSAGE_QUEUE)Thread->MessageQueue; - - if (!MessageQueue->PaintCount) + if (!Thread->cPaintsReady) return FALSE; if ((MsgFilterMin != 0 || MsgFilterMax != 0) && @@ -673,9 +671,9 @@ IntGetPaintMessage( if (Message->hwnd == NULL) { - DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n"); + DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found! Counts %d\n",Thread->cPaintsReady); /* Hack to stop spamming the debuglog ! */ - MessageQueue->PaintCount = 0; + Thread->cPaintsReady = 0; return FALSE; } diff --git a/reactos/subsystems/win32/win32k/ntuser/simplecall.c b/reactos/subsystems/win32/win32k/ntuser/simplecall.c index 953f936574a..df2f1e4b00a 100644 --- a/reactos/subsystems/win32/win32k/ntuser/simplecall.c +++ b/reactos/subsystems/win32/win32k/ntuser/simplecall.c @@ -333,6 +333,8 @@ NtUserCallOneParam( _SEH2_END; RETURN(Ret); } + case ONEPARAM_ROUTINE_REPLYMESSAGE: + RETURN (co_MsqReplyMessage((LRESULT) Param)); } DPRINT1("Calling invalid routine number 0x%x in NtUserCallOneParam(), Param=0x%x\n", Routine, Param); diff --git a/reactos/subsystems/win32/win32k/ntuser/timer.c b/reactos/subsystems/win32/win32k/ntuser/timer.c index b3a7fbde3bc..ee316aab8c2 100644 --- a/reactos/subsystems/win32/win32k/ntuser/timer.c +++ b/reactos/subsystems/win32/win32k/ntuser/timer.c @@ -361,7 +361,7 @@ PostTimerMessages(PWND Window) MsqPostMessage(ThreadQueue, &Msg, FALSE, QS_TIMER); pTmr->flags &= ~TMRF_READY; - ThreadQueue->WakeMask = ~QS_TIMER; + pti->cTimersReady++; Hit = TRUE; break; }