* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Window hooks
- * FILE: subsystems/win32/win32k/ntuser/hook.c
+ * FILE: win32ss/user/ntuser/hook.c
* PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
* James Tabor (james.tabor@rectos.org)
* Rafal Harabien (rafalh@reactos.org)
ppi = PsGetCurrentProcessWin32Process();
- ERR("IntLoadHookModule. Client PID: %d\n", PsGetProcessId(ppi->peProcess));
+ TRACE("IntLoadHookModule. Client PID: %p\n", PsGetProcessId(ppi->peProcess));
/* Check if this is the api hook */
if(iHookID == WH_APIHOOK)
PLIST_ENTRY ListEntry;
PPROCESSINFO ppiCsr;
- ERR("IntHookModuleUnloaded: iHookID=%d\n", iHookID);
+ TRACE("IntHookModuleUnloaded: iHookID=%d\n", iHookID);
- ppiCsr = PsGetProcessWin32Process(CsrProcess);
+ ppiCsr = PsGetProcessWin32Process(gpepCSRSS);
ListEntry = pdesk->PtiList.Flink;
while(ListEntry != &pdesk->PtiList)
/* FIXME: Do some more security checks here */
- /* FIXME: The first check is a reactos specific hack for system threads */
+ /* FIXME: HACK: 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);
+ TRACE("IntHookModuleUnloaded: sending message to PID %p, ppi=%p\n", PsGetProcessId(ptiCurrent->ppi->peProcess), ptiCurrent->ppi);
co_MsqSendMessageAsync( ptiCurrent,
0,
iHookID,
PPROCESSINFO ppiCsr;
pti = PsGetCurrentThreadWin32Thread();
- ppiCsr = PsGetProcessWin32Process(CsrProcess);
+ ppiCsr = PsGetProcessWin32Process(gpepCSRSS);
/* 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));
+ TRACE("UserRegisterUserApiHook. Server PID: %p\n", PsGetProcessId(pti->ppi->peProcess));
/* Register the api hook */
gpsi->dwSRVIFlags |= SRVINFO_APIHOOK;
return FALSE;
}
- ERR("UserUnregisterUserApiHook. Server PID: %d\n", PsGetProcessId(pti->ppi->peProcess));
+ TRACE("UserUnregisterUserApiHook. Server PID: %p\n", PsGetProcessId(pti->ppi->peProcess));
/* Unregister the api hook */
gpsi->dwSRVIFlags &= ~SRVINFO_APIHOOK;
BOOL Block = FALSE;
ULONG_PTR uResult = 0;
- if (Hook->Thread)
- pti = Hook->Thread->Tcb.Win32Thread;
+ if (Hook->ptiHooked)
+ pti = Hook->ptiHooked;
else
pti = Hook->head.pti;
/* FIXME: Should get timeout from
* HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
- Status = co_MsqSendMessage( pti->MessageQueue,
+ Status = co_MsqSendMessage( pti,
IntToPtr(Code), // hWnd
Hook->HookId, // Msg
wParam,
// Dispatch MsgQueue Hook Call processor!
//
LRESULT
-FASTCALL
+APIENTRY
co_CallHook( INT HookId,
INT Code,
WPARAM wParam,
LPARAM lParam)
{
- LRESULT Result;
+ LRESULT Result = 0;
PHOOK phk;
PHOOKPACK pHP = (PHOOKPACK)lParam;
{
case WH_JOURNALPLAYBACK:
case WH_JOURNALRECORD:
- case WH_KEYBOARD:
case WH_KEYBOARD_LL:
case WH_MOUSE_LL:
case WH_MOUSE:
lParam = (LPARAM)pHP->pHookStructs;
+ case WH_KEYBOARD:
break;
}
+ if (!UserObjectInDestroy(UserHMGetHandle(phk))) //// Fix CORE-10549.
+ {
/* The odds are high for this to be a Global call. */
Result = co_IntCallHookProc( HookId,
Code,
wParam,
lParam,
phk->Proc,
+ phk->ihmod,
+ phk->offPfn,
phk->Ansi,
&phk->ModuleName);
-
+ }
/* The odds so high, no one is waiting for the results. */
if (pHP->pHookStructs) ExFreePoolWithTag(pHP->pHookStructs, TAG_HOOK);
ExFreePoolWithTag(pHP, TAG_HOOK);
static
LRESULT
-FASTCALL
+APIENTRY
co_HOOK_CallHookNext( PHOOK Hook,
INT Code,
WPARAM wParam,
wParam,
lParam,
Hook->Proc,
+ Hook->ihmod,
+ Hook->offPfn,
Hook->Ansi,
&Hook->ModuleName);
}
static
LRESULT
-FASTCALL
+APIENTRY
co_UserCallNextHookEx(PHOOK Hook,
int Code,
WPARAM wParam,
if (!IS_ATOM(pcbtcww->lpcs->lpszClass))
{
- ProbeForRead( pcbtcww->lpcs->lpszClass,
+ _Analysis_assume_(pcbtcww->lpcs->lpszClass != NULL);
+ ProbeForRead(pcbtcww->lpcs->lpszClass,
sizeof(CHAR),
1);
}
if (!IS_ATOM(pcbtcww->lpcs->lpszClass))
{
- ProbeForRead( pcbtcww->lpcs->lpszClass,
+ _Analysis_assume_(pcbtcww->lpcs->lpszClass != NULL);
+ ProbeForRead(pcbtcww->lpcs->lpszClass,
sizeof(WCHAR),
1);
}
return NULL;
}
- Hook = (PHOOK)UserGetObject(gHandleTable, hHook, otHook);
+ Hook = (PHOOK)UserGetObject(gHandleTable, hHook, TYPE_HOOK);
if (!Hook)
{
EngSetLastError(ERROR_INVALID_HOOK_HANDLE);
++cHooks;
pList = ExAllocatePoolWithTag(PagedPool, (cHooks + 1) * sizeof(HHOOK), TAG_HOOK);
- if(!pList)
+ if (!pList)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
-}
+ }
for (pElem = pLastHead->Flink; pElem != pLastHead; pElem = pElem->Flink)
-{
+ {
pHook = CONTAINING_RECORD(pElem, HOOK, Chain);
+ NT_ASSERT(i < cHooks);
pList[i++] = pHook->head.h;
}
pList[i] = NULL;
PLIST_ENTRY pLastHead, pElem;
PTHREADINFO pti;
- if (Hook->Thread)
+ if (Hook->ptiHooked)
{
- pti = ((PTHREADINFO)Hook->Thread->Tcb.Win32Thread);
+ pti = Hook->ptiHooked;
pLastHead = &pti->aphkStart[HOOKID_TO_INDEX(HookId)];
}
else
Hook->ModuleName.Buffer = NULL;
}
/* Close handle */
- UserDeleteObject(UserHMGetHandle(Hook), otHook);
+ UserDeleteObject(UserHMGetHandle(Hook), TYPE_HOOK);
}
/* Remove a hook, freeing it from the chain */
-static
-VOID
-FASTCALL
-IntRemoveHook(PHOOK Hook)
+BOOLEAN
+IntRemoveHook(PVOID Object)
{
INT HookId;
- PTHREADINFO pti;
+ PTHREADINFO ptiHook, pti;
PDESKTOP pdo;
+ PHOOK Hook = Object;
+
+ NT_ASSERT(UserIsEnteredExclusive());
HookId = Hook->HookId;
+ pti = PsGetCurrentThreadWin32Thread();
- if (Hook->Thread) // Local
+ if (Hook->ptiHooked) // Local
{
- pti = ((PTHREADINFO)Hook->Thread->Tcb.Win32Thread);
+ ptiHook = Hook->ptiHooked;
- IntFreeHook( Hook);
+ IntFreeHook(Hook);
- if ( IsListEmpty(&pti->aphkStart[HOOKID_TO_INDEX(HookId)]) )
- {
- pti->fsHooks &= ~HOOKID_TO_FLAG(HookId);
- _SEH2_TRY
- {
- pti->pClientInfo->fsHooks = pti->fsHooks;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- }
- _SEH2_END;
+ if (IsListEmpty(&ptiHook->aphkStart[HOOKID_TO_INDEX(HookId)]))
+ {
+ BOOL bOtherProcess;
+ KAPC_STATE ApcState;
+
+ ptiHook->fsHooks &= ~HOOKID_TO_FLAG(HookId);
+ bOtherProcess = (ptiHook->ppi != pti->ppi);
+
+ if (bOtherProcess)
+ KeStackAttachProcess(&ptiHook->ppi->peProcess->Pcb, &ApcState);
+
+ _SEH2_TRY
+ {
+ ptiHook->pClientInfo->fsHooks = ptiHook->fsHooks;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Do nothing */
+ (void)0;
+ }
+ _SEH2_END;
+
+ if (bOtherProcess)
+ KeUnstackDetachProcess(&ApcState);
}
}
else // Global
{
- IntFreeHook( Hook);
+ IntFreeHook(Hook);
- pdo = IntGetActiveDesktop();
+ pdo = IntGetActiveDesktop();
- if ( pdo &&
- pdo->pDeskInfo &&
- IsListEmpty(&pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]) )
- {
- pdo->pDeskInfo->fsHooks &= ~HOOKID_TO_FLAG(HookId);
- }
+ if (pdo &&
+ pdo->pDeskInfo &&
+ IsListEmpty(&pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]))
+ {
+ pdo->pDeskInfo->fsHooks &= ~HOOKID_TO_FLAG(HookId);
+ }
}
-}
-VOID
-FASTCALL
-HOOK_DestroyThreadHooks(PETHREAD Thread)
-{
- PTHREADINFO pti;
- PDESKTOP pdo;
- int HookId;
- PHOOK HookObj;
- PLIST_ENTRY pElem;
-
- pti = Thread->Tcb.Win32Thread;
- pdo = IntGetActiveDesktop();
-
- if (!pti || !pdo)
- {
- ERR("Kill Thread Hooks pti 0x%x pdo 0x%x\n",pti,pdo);
- return;
- }
-
-// Local Thread cleanup.
- if (pti->fsHooks)
- {
- for (HookId = WH_MINHOOK; HookId <= WH_MAXHOOK; HookId++)
- {
- PLIST_ENTRY pLastHead = &pti->aphkStart[HOOKID_TO_INDEX(HookId)];
-
- pElem = pLastHead->Flink;
- while (pElem != pLastHead)
- {
- HookObj = CONTAINING_RECORD(pElem, HOOK, Chain);
- pElem = HookObj->Chain.Flink; // get next element before hook is destroyed
- IntRemoveHook(HookObj);
- }
- }
- pti->fsHooks = 0;
- pti->pClientInfo->fsHooks = 0;
- }
-// Global search based on Thread and cleanup.
- if (pdo->pDeskInfo->fsHooks)
- {
- for (HookId = WH_MINHOOK; HookId <= WH_MAXHOOK; HookId++)
- {
- PLIST_ENTRY pGLE = &pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)];
-
- pElem = pGLE->Flink;
- while (pElem != pGLE)
- {
- HookObj = CONTAINING_RECORD(pElem, HOOK, Chain);
- pElem = HookObj->Chain.Flink; // Get next element before hook is destroyed
- if (HookObj->head.pti == pti)
- {
- IntRemoveHook(HookObj);
- }
- }
- }
- }
- return;
+ return TRUE;
}
/*
Win32k Kernel Space Hook Caller.
*/
LRESULT
-FASTCALL
+APIENTRY
co_HOOK_CallHooks( INT HookId,
INT Code,
WPARAM wParam,
}
Hook = CONTAINING_RECORD(pLastHead->Flink, HOOK, Chain);
+ ObReferenceObject(pti->pEThread);
+ IntReferenceThreadInfo(pti);
UserRefObjectCo(Hook, &Ref);
ClientInfo = pti->pClientInfo;
wParam,
lParam,
Hook->Proc,
+ Hook->ihmod,
+ Hook->offPfn,
Hook->Ansi,
&Hook->ModuleName);
if (ClientInfo)
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
+ /* Do nothing */
+ (void)0;
}
_SEH2_END;
}
pti->sphkCurrent = SaveHook;
Hook->phkNext = NULL;
UserDerefObjectCo(Hook);
+ IntDereferenceThreadInfo(pti);
+ ObDereferenceObject(pti->pEThread);
}
if ( Global )
*/
for(i = 0; pHookHandles[i]; ++i)
{
- Hook = (PHOOK)UserGetObject(gHandleTable, pHookHandles[i], otHook);
+ Hook = (PHOOK)UserGetObject(gHandleTable, pHookHandles[i], TYPE_HOOK);
if(!Hook)
{
ERR("Invalid hook!\n");
continue;
}
- UserRefObjectCo(Hook, &Ref);
/* Hook->Thread is null, we hax around this with Hook->head.pti. */
ptiHook = Hook->head.pti;
if ( (pti->TIF_flags & TIF_DISABLEHOOKS) || (ptiHook->TIF_flags & TIF_INCLEANUP))
{
- TRACE("Next Hook 0x%x, 0x%x\n",ptiHook->rpdesk,pdo);
+ TRACE("Next Hook %p, %p\n", ptiHook->rpdesk, pdo);
continue;
}
+ UserRefObjectCo(Hook, &Ref);
if (ptiHook != pti )
{
TRACE("\nGlobal Hook posting to another Thread! %d\n",HookId );
Result = co_IntCallLowLevelHook(Hook, Code, wParam, lParam);
}
+ else if (ptiHook->ppi == pti->ppi)
+ {
+ TRACE("\nGlobal Hook calling to another Thread! %d\n",HookId );
+ ObReferenceObject(ptiHook->pEThread);
+ IntReferenceThreadInfo(ptiHook);
+ Result = co_IntCallHookProc( HookId,
+ Code,
+ wParam,
+ lParam,
+ Hook->Proc,
+ Hook->ihmod,
+ Hook->offPfn,
+ Hook->Ansi,
+ &Hook->ModuleName);
+ IntDereferenceThreadInfo(ptiHook);
+ ObDereferenceObject(ptiHook->pEThread);
+ }
}
else
{ /* Make the direct call. */
- TRACE("Local Hook calling to Thread! %d\n",HookId );
+ TRACE("Global going Local Hook calling to Thread! %d\n",HookId );
+ ObReferenceObject(pti->pEThread);
+ IntReferenceThreadInfo(pti);
Result = co_IntCallHookProc( HookId,
Code,
wParam,
lParam,
Hook->Proc,
+ Hook->ihmod,
+ Hook->offPfn,
Hook->Ansi,
&Hook->ModuleName);
+ IntDereferenceThreadInfo(pti);
+ ObDereferenceObject(pti->pEThread);
}
UserDerefObjectCo(Hook);
}
{
Hook = CONTAINING_RECORD(pElement, HOOK, Chain);
+ /* Get the next element now, we might free the hook in what follows */
+ pElement = Hook->Chain.Flink;
+
if (Hook->Proc == pfnFilterProc)
{
if (Hook->head.pti == pti)
{
IntRemoveHook(Hook);
- UserDereferenceObject(Hook);
return TRUE;
}
else
return FALSE;
}
}
-
- pElement = Hook->Chain.Flink;
}
}
return FALSE;
BOOL Ansi)
{
PWINSTATION_OBJECT WinStaObj;
- PHOOK Hook;
+ PHOOK Hook = NULL;
UNICODE_STRING ModuleName;
NTSTATUS Status;
HHOOK Handle;
- PETHREAD Thread = NULL;
PTHREADINFO pti, ptiHook = NULL;
DECLARE_RETURN(HHOOK);
HookId == WH_MOUSE_LL ||
HookId == WH_SYSMSGFILTER)
{
- ERR("Local hook installing Global HookId: %d\n",HookId);
+ TRACE("Local hook installing Global HookId: %d\n",HookId);
/* these can only be global */
EngSetLastError(ERROR_GLOBAL_ONLY_HOOK);
RETURN( NULL);
}
- if (!NT_SUCCESS(PsLookupThreadByThreadId((HANDLE)(DWORD_PTR) ThreadId, &Thread)))
+ if ( !(ptiHook = IntTID2PTI( UlongToHandle(ThreadId) )))
{
ERR("Invalid thread id 0x%x\n", ThreadId);
EngSetLastError(ERROR_INVALID_PARAMETER);
RETURN( NULL);
}
- ptiHook = Thread->Tcb.Win32Thread;
-
- ObDereferenceObject(Thread);
-
if ( ptiHook->rpdesk != pti->rpdesk) // gptiCurrent->rpdesk)
{
ERR("Local hook wrong desktop HookId: %d\n",HookId);
RETURN( NULL);
}
- if (Thread->ThreadsProcess != PsGetCurrentProcess())
+ if (ptiHook->ppi != pti->ppi)
{
if ( !Mod &&
(HookId == WH_GETMESSAGE ||
}
Status = IntValidateWindowStationHandle( PsGetCurrentProcess()->Win32WindowStation,
- KernelMode,
+ UserMode,
0,
- &WinStaObj);
+ &WinStaObj,
+ 0);
if (!NT_SUCCESS(Status))
{
}
ObDereferenceObject(WinStaObj);
- Hook = UserCreateObject(gHandleTable, NULL, NULL, (PHANDLE)&Handle, otHook, sizeof(HOOK));
+ Hook = UserCreateObject(gHandleTable, NULL, ptiHook, (PHANDLE)&Handle, TYPE_HOOK, sizeof(HOOK));
if (!Hook)
{
RETURN( NULL);
}
- Hook->ihmod = (INT)Mod; // Module Index from atom table, Do this for now.
- Hook->Thread = Thread; /* Set Thread, Null is Global. */
+ Hook->ihmod = (INT_PTR)Mod; // Module Index from atom table, Do this for now.
Hook->HookId = HookId;
Hook->rpdesk = ptiHook->rpdesk;
Hook->phkNext = NULL; /* Dont use as a chain! Use link lists for chaining. */
Hook->Proc = HookProc;
Hook->Ansi = Ansi;
- TRACE("Set Hook Desk 0x%x DeskInfo 0x%x Handle Desk 0x%x\n",pti->rpdesk, pti->pDeskInfo,Hook->head.rpdesk);
+ TRACE("Set Hook Desk %p DeskInfo %p Handle Desk %p\n", pti->rpdesk, pti->pDeskInfo, Hook->head.rpdesk);
if (ThreadId) /* Thread-local hook */
{
}
else
{
- KeAttachProcess(&ptiHook->ppi->peProcess->Pcb);
+ KAPC_STATE ApcState;
+
+ KeStackAttachProcess(&ptiHook->ppi->peProcess->Pcb, &ApcState);
_SEH2_TRY
{
ptiHook->pClientInfo->fsHooks = ptiHook->fsHooks;
ERR("Problem writing to Remote ClientInfo!\n");
}
_SEH2_END;
- KeDetachProcess();
+ KeUnstackDetachProcess(&ApcState);
}
}
}
}
Hook->ModuleName.Length = ModuleName.Length;
+ //// FIXME: Need to load from user32 to verify hMod before calling hook with hMod set!!!!
+ //// Mod + offPfn == new HookProc Justin Case module is from another process.
+ FIXME("NtUserSetWindowsHookEx Setting process hMod instance addressing.\n");
/* Make proc relative to the module base */
Hook->offPfn = (ULONG_PTR)((char *)HookProc - (char *)Mod);
}
RETURN( Handle);
CLEANUP:
- TRACE("Leave NtUserSetWindowsHookEx, ret=%i\n",_ret_);
+ if (Hook)
+ UserDereferenceObject(Hook);
+ TRACE("Leave NtUserSetWindowsHookEx, ret=%p\n", _ret_);
UserLeave();
END_CLEANUP;
}