- 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
This commit is contained in:
Giannis Adamopoulos 2011-09-19 08:32:38 +00:00
parent b880e23623
commit 06631cf0ea
14 changed files with 571 additions and 58 deletions

View file

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

View file

@ -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 */

View file

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

View file

@ -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;

View file

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

View file

@ -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,

View file

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

View file

@ -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 */

View file

@ -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;

View file

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

View file

@ -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(

View file

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

View file

@ -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.

View file

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