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))