From 06631cf0ea9a08d1cbe3e3d17fe7ab5ca16d85bb Mon Sep 17 00:00:00 2001 From: Giannis Adamopoulos Date: Mon, 19 Sep 2011 08:32:38 +0000 Subject: [PATCH] [win32k] - Merge changes from the themes branch. These changes will introduce test regressions for class functions and for TrackMouseEvent. The changes in the class functions are needed in order to let comctl32 register its own versions of built in controls. This is a hack and will be removed when we properly support class versions. The second change that causes test regressions is in TrackMouseEvent and it is needed in order to fix WM_MOUSELEAVE messages that were completely broken and not tested at all by wine's test suite. svn path=/trunk/; revision=53745 --- .../win32/win32k/include/callback.h | 7 + .../subsystems/win32/win32k/include/hook.h | 13 + .../win32/win32k/include/msgqueue.h | 11 + .../subsystems/win32/win32k/include/win32.h | 1 + .../subsystems/win32/win32k/main/dllmain.c | 24 +- .../subsystems/win32/win32k/ntuser/callback.c | 108 +++++++ .../subsystems/win32/win32k/ntuser/class.c | 3 +- reactos/subsystems/win32/win32k/ntuser/hook.c | 274 ++++++++++++++++++ .../subsystems/win32/win32k/ntuser/input.c | 14 +- .../subsystems/win32/win32k/ntuser/msgqueue.c | 136 ++++++++- .../subsystems/win32/win32k/ntuser/ntstubs.c | 22 -- .../win32/win32k/ntuser/simplecall.c | 3 + .../subsystems/win32/win32k/ntuser/timer.c | 11 +- .../subsystems/win32/win32k/objects/bitblt.c | 2 +- 14 files changed, 571 insertions(+), 58 deletions(-) diff --git a/reactos/subsystems/win32/win32k/include/callback.h b/reactos/subsystems/win32/win32k/include/callback.h index 771998196ca..aec17866c35 100644 --- a/reactos/subsystems/win32/win32k/include/callback.h +++ b/reactos/subsystems/win32/win32k/include/callback.h @@ -54,3 +54,10 @@ IntCbFreeMemory(PVOID Data); HMENU APIENTRY co_IntCallLoadMenu(HINSTANCE,PUNICODE_STRING); NTSTATUS APIENTRY co_IntClientThreadSetup(VOID); + +HMODULE +co_IntClientLoadLibrary(PUNICODE_STRING strLibName, + PUNICODE_STRING strInitFunc, + BOOL Unload, + BOOL ApiHook); + diff --git a/reactos/subsystems/win32/win32k/include/hook.h b/reactos/subsystems/win32/win32k/include/hook.h index ce6d64e1b9f..951a8e9f3d2 100644 --- a/reactos/subsystems/win32/win32k/include/hook.h +++ b/reactos/subsystems/win32/win32k/include/hook.h @@ -5,6 +5,13 @@ #define HOOKID_TO_FLAG(HookId) (1 << ((HookId) + 1)) #define ISITHOOKED(HookId) (((PTHREADINFO)PsGetCurrentThreadWin32Thread())->fsHooks & HOOKID_TO_FLAG(HookId)) +/* NOTE: the following definition is not a real hook but + a pseudo-id that will be used only for + injecting user api hook module to all processes. + It is used internally in win32k */ +#define WH_APIHOOK WH_MAX + 1 + + typedef struct tagEVENTHOOK { THROBJHEAD head; @@ -43,4 +50,10 @@ PHOOK FASTCALL IntGetNextHook(PHOOK Hook); LRESULT FASTCALL UserCallNextHookEx( PHOOK pHook, int Code, WPARAM wParam, LPARAM lParam, BOOL Ansi); BOOL FASTCALL IntUnhookWindowsHook(int,HOOKPROC); +BOOL FASTCALL UserLoadApiHook(); +BOOL IntLoadHookModule(int iHookID, HHOOK hHook, BOOL Unload); +BOOL FASTCALL UserUnregisterUserApiHook(); + +extern PPROCESSINFO ppiUahServer; + /* EOF */ diff --git a/reactos/subsystems/win32/win32k/include/msgqueue.h b/reactos/subsystems/win32/win32k/include/msgqueue.h index 07755d00195..092fe3dc8ec 100644 --- a/reactos/subsystems/win32/win32k/include/msgqueue.h +++ b/reactos/subsystems/win32/win32k/include/msgqueue.h @@ -4,6 +4,7 @@ #define MSQ_NORMAL 0 #define MSQ_ISHOOK 1 #define MSQ_ISEVENT 2 +#define MSQ_INJECTMODULE 3 #define QSIDCOUNTS 6 @@ -206,6 +207,16 @@ co_IntSendMessageWithCallBack(HWND hWnd, SENDASYNCPROC CompletionCallback, ULONG_PTR CompletionCallbackContext, ULONG_PTR *uResult); +BOOL FASTCALL +co_MsqSendMessageAsync(PTHREADINFO ptiReceiver, + HWND hwnd, + UINT Msg, + WPARAM wParam, + LPARAM lParam, + SENDASYNCPROC CompletionCallback, + ULONG_PTR CompletionCallbackContext, + BOOL HasPackedLParam, + INT HookMessage); LRESULT FASTCALL IntDispatchMessage(MSG* Msg); BOOL FASTCALL IntTranslateKbdMessage(LPMSG lpMsg, UINT flags); diff --git a/reactos/subsystems/win32/win32k/include/win32.h b/reactos/subsystems/win32/win32k/include/win32.h index 51c0a094c2f..35b0bd80c52 100644 --- a/reactos/subsystems/win32/win32k/include/win32.h +++ b/reactos/subsystems/win32/win32k/include/win32.h @@ -30,6 +30,7 @@ #define W32PF_NOWINDOWGHOSTING (0x01000000) #define W32PF_MANUALGUICHECK (0x02000000) #define W32PF_CREATEDWINORDC (0x04000000) +#define W32PF_APIHOOKLOADED (0x08000000) extern BOOL ClientPfnInit; extern HINSTANCE hModClient; diff --git a/reactos/subsystems/win32/win32k/main/dllmain.c b/reactos/subsystems/win32/win32k/main/dllmain.c index d6a5d8d2100..4733276714b 100644 --- a/reactos/subsystems/win32/win32k/main/dllmain.c +++ b/reactos/subsystems/win32/win32k/main/dllmain.c @@ -393,6 +393,22 @@ Win32kThreadCallback(struct _ETHREAD *Thread, /* Remove it from the list */ *ppti = ptiCurrent->ptiSibling; + /* Decrement thread count and check if its 0 */ + ppiCurrent->cThreads--; + + /* Do now some process cleanup that requires a valid win32 thread */ + if(ptiCurrent->ppi->cThreads == 0) + { + UserSetCursor(NULL, TRUE); + + /* Check if we have registered the user api hook */ + if(ptiCurrent->ppi == ppiUahServer) + { + /* Unregister the api hook without blocking */ + UserUnregisterUserApiHook(); + } + } + DceFreeThreadDCE(ptiCurrent); HOOK_DestroyThreadHooks(Thread); EVENT_DestroyThreadEvents(Thread); @@ -421,14 +437,6 @@ Win32kThreadCallback(struct _ETHREAD *Thread, IntSetThreadDesktop(NULL, TRUE); - /* Decrement thread count and check if its 0 */ - ppiCurrent->cThreads--; - if (ppiCurrent->cThreads == 0) - { - /* UGLY: Prevent this function from being called later - when we don't have a THREADINFO anymore. */ - UserSetCursor(NULL, TRUE); - } /* Free the THREADINFO */ PsSetThreadWin32Thread(Thread, NULL); diff --git a/reactos/subsystems/win32/win32k/ntuser/callback.c b/reactos/subsystems/win32/win32k/ntuser/callback.c index b97d1c8ad98..f17c5a0cb52 100644 --- a/reactos/subsystems/win32/win32k/ntuser/callback.c +++ b/reactos/subsystems/win32/win32k/ntuser/callback.c @@ -116,6 +116,114 @@ IntRestoreTebWndCallback (HWND hWnd, PWND pWnd) /* FUNCTIONS *****************************************************************/ +/* calls ClientLoadLibrary in user32 */ +HMODULE +co_IntClientLoadLibrary(PUNICODE_STRING pstrLibName, + PUNICODE_STRING pstrInitFunc, + BOOL Unload, + BOOL ApiHook) +{ + PVOID ResultPointer; + ULONG ResultLength; + ULONG ArgumentLength; + PCLIENT_LOAD_LIBRARY_ARGUMENTS pArguments; + NTSTATUS Status; + HMODULE Result; + ULONG_PTR pLibNameBuffer = 0, pInitFuncBuffer = 0; + + TRACE("co_IntClientLoadLibrary: %S, %S, %d, %d\n", pstrLibName->Buffer, pstrLibName->Buffer, Unload, ApiHook); + + /* Calculate the size of the argument */ + ArgumentLength = sizeof(CLIENT_LOAD_LIBRARY_ARGUMENTS); + if(pstrLibName) + { + pLibNameBuffer = ArgumentLength; + ArgumentLength += pstrLibName->Length + sizeof(WCHAR); + } + if(pstrInitFunc) + { + pInitFuncBuffer = ArgumentLength; + ArgumentLength += pstrInitFunc->Length + sizeof(WCHAR); + } + + /* Allocate the argument*/ + pArguments = IntCbAllocateMemory(ArgumentLength); + if(pArguments == NULL) + { + return FALSE; + } + + /* Fill the argument */ + pArguments->Unload = Unload; + pArguments->ApiHook = ApiHook; + if(pstrLibName) + { + /* Copy the string to the callback memory */ + pLibNameBuffer += (ULONG_PTR)pArguments; + pArguments->strLibraryName.Buffer = (PWCHAR)pLibNameBuffer; + pArguments->strLibraryName.MaximumLength = pstrLibName->Length + sizeof(WCHAR); + RtlCopyUnicodeString(&pArguments->strLibraryName, pstrLibName); + + /* Fix argument pointer to be relative to the argument */ + pLibNameBuffer -= (ULONG_PTR)pArguments; + pArguments->strLibraryName.Buffer = (PWCHAR)(pLibNameBuffer); + } + else + { + RtlZeroMemory(&pArguments->strLibraryName, sizeof(UNICODE_STRING)); + } + + if(pstrInitFunc) + { + /* Copy the strings to the callback memory */ + pInitFuncBuffer += (ULONG_PTR)pArguments; + pArguments->strInitFuncName.Buffer = (PWCHAR)pInitFuncBuffer; + pArguments->strInitFuncName.MaximumLength = pstrInitFunc->Length + sizeof(WCHAR); + RtlCopyUnicodeString(&pArguments->strInitFuncName, pstrInitFunc); + + /* Fix argument pointers to be relative to the argument */ + pInitFuncBuffer -= (ULONG_PTR)pArguments; + pArguments->strInitFuncName.Buffer = (PWCHAR)(pInitFuncBuffer); + } + else + { + RtlZeroMemory(&pArguments->strInitFuncName, sizeof(UNICODE_STRING)); + } + + /* Do the callback */ + UserLeaveCo(); + + Status = KeUserModeCallback(USER32_CALLBACK_CLIENTLOADLIBRARY, + pArguments, + ArgumentLength, + &ResultPointer, + &ResultLength); + + UserEnterCo(); + + /* Free the argument */ + IntCbFreeMemory(pArguments); + + if(!NT_SUCCESS(Status)) + { + return FALSE; + } + + _SEH2_TRY + { + ProbeForRead(ResultPointer, sizeof(HMODULE), 1); + /* Simulate old behaviour: copy into our local buffer */ + Result = *(HMODULE*)ResultPointer; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Result = 0; + } + _SEH2_END; + + return Result; +} + VOID APIENTRY co_IntCallSentMessageCallback(SENDASYNCPROC CompletionCallback, HWND hWnd, diff --git a/reactos/subsystems/win32/win32k/ntuser/class.c b/reactos/subsystems/win32/win32k/ntuser/class.c index bd0290975b4..892f66ce1c5 100644 --- a/reactos/subsystems/win32/win32k/ntuser/class.c +++ b/reactos/subsystems/win32/win32k/ntuser/class.c @@ -1295,8 +1295,9 @@ UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx, if (lpwcx->style & CS_GLOBALCLASS) { + /* HACK: allow global classes to be re-registered*/ Class = IntFindClass( ClassAtom, - NULL, + lpwcx->hInstance, &pi->pclsPublicList, NULL); diff --git a/reactos/subsystems/win32/win32k/ntuser/hook.c b/reactos/subsystems/win32/win32k/ntuser/hook.c index 8b3aecf1daf..07037238760 100644 --- a/reactos/subsystems/win32/win32k/ntuser/hook.c +++ b/reactos/subsystems/win32/win32k/ntuser/hook.c @@ -24,8 +24,222 @@ typedef struct _HOOKPACK PVOID pHookStructs; } HOOKPACK, *PHOOKPACK; +UNICODE_STRING strUahModule; +UNICODE_STRING strUahInitFunc; +PPROCESSINFO ppiUahServer; + /* PRIVATE FUNCTIONS *********************************************************/ +/* Calls ClientLoadLibrary in user32 in order to load or unload a module */ +BOOL +IntLoadHookModule(int iHookID, HHOOK hHook, BOOL Unload) +{ + PPROCESSINFO ppi; + HMODULE hmod; + + ppi = PsGetCurrentProcessWin32Process(); + + ERR("IntLoadHookModule. Client PID: %d\n", PsGetProcessId(ppi->peProcess)); + + /* Check if this is the api hook */ + if(iHookID == WH_APIHOOK) + { + if(!Unload && !(ppi->W32PF_flags & W32PF_APIHOOKLOADED)) + { + /* A callback in user mode can trigger UserLoadApiHook to be called and + as a result IntLoadHookModule will be called recursively. + To solve this we set the flag that means that the appliaction has + loaded the api hook before the callback and in case of error we remove it */ + ppi->W32PF_flags |= W32PF_APIHOOKLOADED; + + /* Call ClientLoadLibrary in user32 */ + hmod = co_IntClientLoadLibrary(&strUahModule, &strUahInitFunc, Unload, TRUE); + TRACE("co_IntClientLoadLibrary returned %d\n", hmod ); + if(hmod == 0) + { + /* Remove the flag we set before */ + ppi->W32PF_flags &= ~W32PF_APIHOOKLOADED; + return FALSE; + } + return TRUE; + } + else if(Unload && (ppi->W32PF_flags & W32PF_APIHOOKLOADED)) + { + /* Call ClientLoadLibrary in user32 */ + hmod = co_IntClientLoadLibrary(NULL, NULL, Unload, TRUE); + if(hmod != 0) + { + ppi->W32PF_flags &= ~W32PF_APIHOOKLOADED; + return TRUE; + } + return FALSE; + } + + return TRUE; + } + + STUB; + + return FALSE; +} + +/* +IntHookModuleUnloaded: +Sends a internal message to all threads of the requested desktop +and notifies them that a global hook was destroyed +and an injected module must be unloaded. +As a result, IntLoadHookModule will be called for all the threads that +will receive the special purpose internal message. +*/ +BOOL +IntHookModuleUnloaded(PDESKTOP pdesk, int iHookID, HHOOK hHook) +{ + PTHREADINFO ptiCurrent; + PLIST_ENTRY ListEntry; + PPROCESSINFO ppiCsr; + + ERR("IntHookModuleUnloaded: iHookID=%d\n", iHookID); + + ppiCsr = PsGetProcessWin32Process(CsrProcess); + + ListEntry = pdesk->PtiList.Flink; + while(ListEntry != &pdesk->PtiList) + { + ptiCurrent = CONTAINING_RECORD(ListEntry, THREADINFO, PtiLink); + + /* FIXME: do some more security checks here */ + + /* FIXME: the first check is a reactos specific hack for system threads */ + if(!PsIsSystemProcess(ptiCurrent->ppi->peProcess) && + ptiCurrent->ppi != ppiCsr) + { + if(ptiCurrent->ppi->W32PF_flags & W32PF_APIHOOKLOADED) + { + TRACE("IntHookModuleUnloaded: sending message to PID %d, ppi=0x%x\n", PsGetProcessId(ptiCurrent->ppi->peProcess), ptiCurrent->ppi); + co_MsqSendMessageAsync( ptiCurrent, + 0, + iHookID, + TRUE, + (LPARAM)hHook, + NULL, + 0, + FALSE, + MSQ_INJECTMODULE); + } + } + ListEntry = ListEntry->Flink; + } + + return TRUE; +} + +BOOL +FASTCALL +UserLoadApiHook() +{ + return IntLoadHookModule(WH_APIHOOK, 0, FALSE); +} + +BOOL +FASTCALL +UserRegisterUserApiHook( + PUNICODE_STRING pstrDllName, + PUNICODE_STRING pstrFuncName) +{ + PTHREADINFO pti, ptiCurrent; + HWND *List; + PWND DesktopWindow, pwndCurrent; + ULONG i; + PPROCESSINFO ppiCsr; + + pti = PsGetCurrentThreadWin32Thread(); + ppiCsr = PsGetProcessWin32Process(CsrProcess); + + /* Fail if the api hook is already registered */ + if(gpsi->dwSRVIFlags & SRVINFO_APIHOOK) + { + return FALSE; + } + + ERR("UserRegisterUserApiHook. Server PID: %d\n", PsGetProcessId(pti->ppi->peProcess)); + + /* Register the api hook */ + gpsi->dwSRVIFlags |= SRVINFO_APIHOOK; + + strUahModule = *pstrDllName; + strUahInitFunc = *pstrFuncName; + ppiUahServer = pti->ppi; + + /* Broadcast an internal message to every top level window */ + DesktopWindow = UserGetWindowObject(IntGetDesktopWindow()); + List = IntWinListChildren(DesktopWindow); + + if (List != NULL) + { + for (i = 0; List[i]; i++) + { + pwndCurrent = UserGetWindowObject(List[i]); + if(pwndCurrent == NULL) + { + continue; + } + ptiCurrent = pwndCurrent->head.pti; + + /* FIXME: the first check is a reactos specific hack for system threads */ + if(PsIsSystemProcess(ptiCurrent->ppi->peProcess) || + ptiCurrent->ppi == ppiCsr) + { + continue; + } + + co_MsqSendMessageAsync( ptiCurrent, + 0, + WH_APIHOOK, + FALSE, /* load the module */ + 0, + NULL, + 0, + FALSE, + MSQ_INJECTMODULE); + } + ExFreePoolWithTag(List, USERTAG_WINDOWLIST); + } + + return TRUE; +} + +BOOL +FASTCALL +UserUnregisterUserApiHook() +{ + PTHREADINFO pti; + + pti = PsGetCurrentThreadWin32Thread(); + + /* Fail if the api hook is not registered */ + if(!(gpsi->dwSRVIFlags & SRVINFO_APIHOOK)) + { + return FALSE; + } + + /* Only the process that registered the api hook can uregister it */ + if(ppiUahServer != PsGetCurrentProcessWin32Process()) + { + return FALSE; + } + + ERR("UserUnregisterUserApiHook. Server PID: %d\n", PsGetProcessId(pti->ppi->peProcess)); + + /* Unregister the api hook */ + gpsi->dwSRVIFlags &= ~SRVINFO_APIHOOK; + ppiUahServer = NULL; + ReleaseCapturedUnicodeString(&strUahModule, UserMode); + ReleaseCapturedUnicodeString(&strUahInitFunc, UserMode); + + /* Notify all applications that the api hook module must be unloaded */ + return IntHookModuleUnloaded(pti->rpdesk, WH_APIHOOK, 0); +} + static LRESULT FASTCALL @@ -1510,4 +1724,64 @@ CLEANUP: END_CLEANUP; } +BOOL +APIENTRY +NtUserRegisterUserApiHook( + PUNICODE_STRING m_dllname1, + PUNICODE_STRING m_funname1, + DWORD dwUnknown3, + DWORD dwUnknown4) +{ + BOOL ret; + UNICODE_STRING strDllNameSafe; + UNICODE_STRING strFuncNameSafe; + NTSTATUS Status; + + /* Probe and capture parameters */ + Status = ProbeAndCaptureUnicodeString(&strDllNameSafe, UserMode, m_dllname1); + if(!NT_SUCCESS(Status)) + { + EngSetLastError(RtlNtStatusToDosError(Status)); + return FALSE; + } + + Status = ProbeAndCaptureUnicodeString(&strFuncNameSafe, UserMode, m_funname1); + if(!NT_SUCCESS(Status)) + { + ReleaseCapturedUnicodeString(&strDllNameSafe, UserMode); + EngSetLastError(RtlNtStatusToDosError(Status)); + return FALSE; + } + + UserEnterExclusive(); + + /* Call internal function */ + ret = UserRegisterUserApiHook(&strDllNameSafe, &strFuncNameSafe); + + UserLeave(); + + /* Cleanup only in case of failure */ + if(ret == FALSE) + { + ReleaseCapturedUnicodeString(&strDllNameSafe, UserMode); + ReleaseCapturedUnicodeString(&strFuncNameSafe, UserMode); + } + + return ret; +} + +BOOL +APIENTRY +NtUserUnregisterUserApiHook(VOID) +{ + BOOL ret; + + UserEnterExclusive(); + ret = UserUnregisterUserApiHook(); + UserLeave(); + + return ret; +} + + /* EOF */ diff --git a/reactos/subsystems/win32/win32k/ntuser/input.c b/reactos/subsystems/win32/win32k/ntuser/input.c index 61b53425551..334edc41329 100644 --- a/reactos/subsystems/win32/win32k/ntuser/input.c +++ b/reactos/subsystems/win32/win32k/ntuser/input.c @@ -1611,19 +1611,6 @@ IntTrackMouseEvent( if (!(pWnd = UserGetWindowObject(lpEventTrack->hwndTrack))) return FALSE; - if ( pDesk->spwndTrack != pWnd || - (pDesk->htEx != HTCLIENT) ^ !!(lpEventTrack->dwFlags & TME_NONCLIENT) ) - { - if ( lpEventTrack->dwFlags & TME_LEAVE && !(lpEventTrack->dwFlags & TME_CANCEL) ) - { - UserPostMessage( lpEventTrack->hwndTrack, - lpEventTrack->dwFlags & TME_NONCLIENT ? WM_NCMOUSELEAVE : WM_MOUSELEAVE, - 0, 0); - } - TRACE("IntTrackMouseEvent spwndTrack 0x%x pwnd 0x%x\n", pDesk->spwndTrack, pWnd); - return TRUE; - } - /* Tracking spwndTrack same as pWnd */ if ( lpEventTrack->dwFlags & TME_CANCEL ) // Canceled mode. { @@ -1641,6 +1628,7 @@ IntTrackMouseEvent( } else // Not Canceled. { + pDesk->spwndTrack = pWnd; if ( lpEventTrack->dwFlags & TME_LEAVE ) pDesk->dwDTFlags |= DF_TME_LEAVE; diff --git a/reactos/subsystems/win32/win32k/ntuser/msgqueue.c b/reactos/subsystems/win32/win32k/ntuser/msgqueue.c index f90bf1f3005..7e73061ce45 100644 --- a/reactos/subsystems/win32/win32k/ntuser/msgqueue.c +++ b/reactos/subsystems/win32/win32k/ntuser/msgqueue.c @@ -539,22 +539,35 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook if (pwnd) { - PWND pwndTrack = IntChildrenWindowFromPoint(pwnd, Msg->pt.x, Msg->pt.y); - - if ( pDesk->spwndTrack != pwndTrack && pDesk->dwDTFlags & (DF_TME_LEAVE|DF_TME_HOVER) ) + /* If we a re tracking the mouse and it moves to another top level window */ + if(pDesk->spwndTrack && + UserGetAncestor(pDesk->spwndTrack, GA_ROOT) != pwnd) { - if ( pDesk->dwDTFlags & DF_TME_LEAVE ) - UserPostMessage( UserHMGetHandle(pDesk->spwndTrack), - (pDesk->htEx != HTCLIENT) ? WM_NCMOUSELEAVE : WM_MOUSELEAVE, - 0, 0); + /* Generate a WM_MOUSELEAVE message */ + if ( pDesk->dwDTFlags & DF_TME_LEAVE ) + { + MSG msgMouseLeave; - if ( pDesk->dwDTFlags & DF_TME_HOVER ) - IntKillTimer(UserHMGetHandle(pDesk->spwndTrack), ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE); + TRACE("co_MsqInsertMouseMessage: generating WM_MOUSELEAVE\n"); - pDesk->dwDTFlags &= ~(DF_TME_LEAVE|DF_TME_HOVER); + msgMouseLeave.hwnd = UserHMGetHandle(pDesk->spwndTrack); + msgMouseLeave.message = WM_MOUSELEAVE; + msgMouseLeave.pt = Msg->pt; + msgMouseLeave.time = Msg->time; + msgMouseLeave.lParam = msgMouseLeave.wParam = 0; + + MsqPostMessage(pwnd->head.pti->MessageQueue, Msg, TRUE, QS_MOUSE); + } + + /* Stop tracking */ + if ( pDesk->dwDTFlags & DF_TME_HOVER ) + { + IntKillTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE); + } + + pDesk->spwndTrack = NULL; + pDesk->htEx = 0; } - pDesk->spwndTrack = pwndTrack; - pDesk->htEx = GetNCHitEx(pDesk->spwndTrack, Msg->pt); } hdcScreen = IntGetScreenDC(); @@ -811,6 +824,12 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue) Message->Msg.wParam, Message->Msg.lParam); } + else if(Message->HookMessage == MSQ_INJECTMODULE) + { + Result = IntLoadHookModule(Message->Msg.message, + (HHOOK)Message->Msg.lParam, + Message->Msg.wParam); + } else if ((Message->CompletionCallback) && (Message->CallBackSenderQueue == MessageQueue)) { /* Call the callback routine */ @@ -1006,6 +1025,58 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow) } } +BOOL FASTCALL +co_MsqSendMessageAsync(PTHREADINFO ptiReceiver, + HWND hwnd, + UINT Msg, + WPARAM wParam, + LPARAM lParam, + SENDASYNCPROC CompletionCallback, + ULONG_PTR CompletionCallbackContext, + BOOL HasPackedLParam, + INT HookMessage) +{ + + PTHREADINFO ptiSender; + PUSER_SENT_MESSAGE Message; + + if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG))) + { + ERR("MsqSendMessage(): Not enough memory to allocate a message"); + return FALSE; + } + + ptiSender = PsGetCurrentThreadWin32Thread(); + + IntReferenceMessageQueue(ptiReceiver->MessageQueue); + /* Take reference on this MessageQueue if its a callback. It will be released + when message is processed or removed from target hwnd MessageQueue */ + if (CompletionCallback) + IntReferenceMessageQueue(ptiSender->MessageQueue); + + Message->Msg.hwnd = hwnd; + Message->Msg.message = Msg; + Message->Msg.wParam = wParam; + Message->Msg.lParam = lParam; + Message->CompletionEvent = NULL; + Message->Result = 0; + Message->lResult = 0; + Message->SenderQueue = NULL; + Message->CallBackSenderQueue = ptiSender->MessageQueue; + Message->DispatchingListEntry.Flink = NULL; + Message->CompletionCallback = CompletionCallback; + Message->CompletionCallbackContext = CompletionCallbackContext; + Message->HookMessage = HookMessage; + Message->HasPackedLParam = HasPackedLParam; + Message->QS_Flags = QS_SENDMESSAGE; + + InsertTailList(&ptiReceiver->MessageQueue->SentMessagesListHead, &Message->ListEntry); + MsqWakeQueue(ptiReceiver->MessageQueue, QS_SENDMESSAGE, TRUE); + IntDereferenceMessageQueue(ptiReceiver->MessageQueue); + + return TRUE; +} + NTSTATUS FASTCALL co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, @@ -1281,6 +1352,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT PUSER_MESSAGE_QUEUE MessageQueue; PTHREADINFO pti; PSYSTEM_CURSORINFO CurInfo; + PDESKTOP pDesk; DECLARE_RETURN(BOOL); pti = PsGetCurrentThreadWin32Thread(); @@ -1289,6 +1361,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT CurInfo = IntGetSysCursorInfo(); pwndMsg = UserGetWindowObject(msg->hwnd); clk_msg = MessageQueue->msgDblClk; + pDesk = pwndDesktop->head.rpdesk; /* find the window to dispatch this mouse message to */ if (MessageQueue->CaptureWindow) @@ -1310,6 +1383,45 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT RETURN(FALSE); } + /* If we a re tracking the mouse and it moves to another window */ + if(pDesk->spwndTrack && + pDesk->spwndTrack != pwndMsg && + msg->message != WM_MOUSELEAVE) + { + /* Generate a WM_MOUSELEAVE message */ + if ( pDesk->dwDTFlags & DF_TME_LEAVE ) + { + MSG msgMouseLeave; + + TRACE("co_IntProcessMouseMessage: generating WM_MOUSELEAVE\n"); + + msgMouseLeave.hwnd = UserHMGetHandle(pDesk->spwndTrack); + msgMouseLeave.message = WM_MOUSELEAVE; + msgMouseLeave.pt = msg->pt; + msgMouseLeave.time = msg->time; + msgMouseLeave.lParam = msgMouseLeave.wParam = 0; + + MsqPostMessage(pwndMsg->head.pti->MessageQueue, + &msgMouseLeave, + TRUE, + QS_MOUSE); + } + + /* Stop tracking */ + if ( pDesk->dwDTFlags & DF_TME_HOVER ) + { + IntKillTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE); + } + + pDesk->spwndTrack = NULL; + pDesk->htEx = 0; + } + + if(pDesk->spwndTrack) + { + pDesk->htEx = hittest; + } + msg->hwnd = UserHMGetHandle(pwndMsg); #if 0 diff --git a/reactos/subsystems/win32/win32k/ntuser/ntstubs.c b/reactos/subsystems/win32/win32k/ntuser/ntstubs.c index 8205febe758..8c1e1147566 100644 --- a/reactos/subsystems/win32/win32k/ntuser/ntstubs.c +++ b/reactos/subsystems/win32/win32k/ntuser/ntstubs.c @@ -816,20 +816,6 @@ NtUserRealWaitMessageEx( return 0; } -BOOL -APIENTRY -NtUserRegisterUserApiHook( - PUNICODE_STRING m_dllname1, - PUNICODE_STRING m_funname1, - DWORD dwUnknown3, - DWORD dwUnknown4) -{ - UserEnterExclusive(); - STUB; - UserLeave(); - return 0; -} - BOOL APIENTRY NtUserRegisterRawInputDevices( @@ -963,14 +949,6 @@ NtUserPaintMenuBar( return 0; } -BOOL -APIENTRY -NtUserUnregisterUserApiHook(VOID) -{ - STUB; - return 0; -} - BOOL APIENTRY NtUserGetLayeredWindowAttributes( diff --git a/reactos/subsystems/win32/win32k/ntuser/simplecall.c b/reactos/subsystems/win32/win32k/ntuser/simplecall.c index e156006367d..0a24b68b4a7 100644 --- a/reactos/subsystems/win32/win32k/ntuser/simplecall.c +++ b/reactos/subsystems/win32/win32k/ntuser/simplecall.c @@ -120,6 +120,9 @@ NtUserCallNoParam(DWORD Routine) case NOPARAM_ROUTINE_RELEASECAPTURE: RETURN( (DWORD_PTR)IntReleaseCapture()); + case NOPARAM_ROUTINE_LOADUSERAPIHOOK: + RETURN(UserLoadApiHook()); + default: ERR("Calling invalid routine number 0x%x in NtUserCallNoParam\n", Routine); EngSetLastError(ERROR_INVALID_PARAMETER); diff --git a/reactos/subsystems/win32/win32k/ntuser/timer.c b/reactos/subsystems/win32/win32k/ntuser/timer.c index 761414f05fe..7500fe26174 100644 --- a/reactos/subsystems/win32/win32k/ntuser/timer.c +++ b/reactos/subsystems/win32/win32k/ntuser/timer.c @@ -324,7 +324,7 @@ SystemTimerProc(HWND hwnd, if ( pDesk->dwDTFlags & DF_TME_HOVER && pWnd == pDesk->spwndTrack ) { - Point = gpsi->ptCursor; + Point = pWnd->head.pti->MessageQueue->MouseMoveMsg.pt; if ( RECTL_bPointInRect(&pDesk->rcMouseHover, Point.x, Point.y) ) { if (pDesk->htEx == HTCLIENT) // In a client area. @@ -345,10 +345,19 @@ SystemTimerProc(HWND hwnd, wParam = pDesk->htEx; // Need to support all HTXYZ hits. Msg = WM_NCMOUSEHOVER; } + TRACE("Generating WM_NCMOUSEHOVER\n"); UserPostMessage(hwnd, Msg, wParam, MAKELPARAM(Point.x, Point.y)); pDesk->dwDTFlags &= ~DF_TME_HOVER; break; // Kill this timer. } + else + { + RECTL_vSetRect(&pDesk->rcMouseHover, + Point.x - gspv.iMouseHoverWidth / 2, + Point.y - gspv.iMouseHoverHeight / 2, + Point.x + gspv.iMouseHoverWidth / 2, + Point.y + gspv.iMouseHoverHeight / 2); + } } } return; // Not this window so just return. diff --git a/reactos/subsystems/win32/win32k/objects/bitblt.c b/reactos/subsystems/win32/win32k/objects/bitblt.c index 6f0f1f78d82..0c3f0a756e2 100644 --- a/reactos/subsystems/win32/win32k/objects/bitblt.c +++ b/reactos/subsystems/win32/win32k/objects/bitblt.c @@ -549,7 +549,7 @@ GreStretchBltMask( if (0 == WidthDest || 0 == HeightDest || 0 == WidthSrc || 0 == HeightSrc) { EngSetLastError(ERROR_INVALID_PARAMETER); - return FALSE; + return TRUE; } if (!hDCDest || (UsesSource && !hDCSrc) || (UsesMask && !hDCMask))