reactos/win32ss/user/ntuser/callback.c
Joachim Henze 4ea9a8a667 [0.4.10][WIN32SS][RTL] Fix regression CORE-16769 + BSOD 0x50 CORE-13907
The main motivation to port all that back is to get rid of Win32K-BSODs 0x50 like CORE-13907
that could be triggered by user-mode-applications.
Technical reason was CORE-14857 "RtlImageNtHeaderEx needs SEH" and issues with hooks+callbacks.
All other tickets mentioned in here were regressions that we experienced on the long
journey towards perfecting the fixes on master head, and those were not happening yet in the older builds,
so they are mentioned in here only to allow tracking where that code went into.

Thanks to Jim Tabor, Mark Jansen & Thomas Faber
By squashed backmerge of the following commits:
0.4.15-dev-3440-g a89844f740
0.4.15-dev-3430-g 9cff384c22
0.4.14-dev-1287-g 568b6d0558
0.4.14-dev-1255-g 177ae91bf6
0.4.14-dev-1241-g 915a5764a9
0.4.14-dev-1240-g d8add40e89
0.4.14-dev-1002-g feb7df42b4

JIRA-tickets: CORE-13907, CORE-16769, CORE-14857, CORE-17856, CORE-17857, partially CORE-13019.
We also had some more dupes of CORE-13907 in JIRA, but I linked all of them (transitively)
towards the initial report, and resolved them without setting a fixVer for them.

In more detail:
--------------
[USER32] Fix BSOD 0x50 in 'WineVDM + Castle Of Winds' CORE-17856 CORE-17857

CORE-17856 BSOD 0x50 when starting Castle of the Winds second time, with WineVDM
CORE-17857 BSOD 0x50 on shutdown after closing Castle of the Winds with WineVDM

0.4.15-dev-3430-g 9cff384c22
0.4.15-dev-3440-g a89844f740
--------------
[NTUSER] Fix Strings and Format to Hooks

Allocate heap instead of data segment to be used for callbacks on user side.
Move and correct initial hook call out setup. Use it in more than one hook call.

This fixes issues with strings out of alignment and use of kernel pointers.

See CORE-13907 (HXD-portable BSOD) and CORE-16769 (HXD-portable exception)

Small wow update.

cherry picked from commit 0.4.14-dev-1287-g 568b6d0558
--------------
[RTL] Introduce RtlpImageNtHeader,
which implements the required functionality.
ntdll and ntoskrnl now have a wrapper for this, with SEH.
This protects the function against malformed / bad images,
whilst still being able to use the code in freeldr et al.
Idea from Thomas.
CORE-14857

cherry picked from commit 0.4.14-dev-1255-g 177ae91bf6
--------------
[WIN32SS] Form Sanity to Hook Callbacks

Fix WH_CALLWNDPROC/RET data to user hook calls.
Helps with CORE-13907 "(HXD-portable BSOD)"
Fixes the logging of "(win32ss/user/ntuser/callback.c:748) err: Failure to make Callback! Status 0xc00000fd" within CORE-13019, but not the whole ticket.

cherry picked from commit 0.4.14-dev-1241-g 915a5764a9
--------------
[USER32] Fix null return.

See CORE-16769 "HxD 1.7.7.0 portable unhandled exception"

cherry picked from commit 0.4.14-dev-1240-g d8add40e89
--------------
[WIN32SS] Fix a typo in dbg print

cherry picked from commit 0.4.14-dev-1002-g feb7df42b4
2022-03-17 14:01:19 +01:00

1235 lines
34 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Win32k subsystem
* PURPOSE: Callback to usermode support
* FILE: win32ss/user/ntuser/callback.c
* PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
* Thomas Weidenmueller (w3seek@users.sourceforge.net)
* NOTES: Please use the Callback Memory Management functions for
* callbacks to make sure, the memory is freed on thread
* termination!
*/
#include <win32k.h>
DBG_DEFAULT_CHANNEL(UserCallback);
/* CALLBACK MEMORY MANAGEMENT ************************************************/
typedef struct _INT_CALLBACK_HEADER
{
/* List entry in the THREADINFO structure */
LIST_ENTRY ListEntry;
}
INT_CALLBACK_HEADER, *PINT_CALLBACK_HEADER;
PVOID FASTCALL
IntCbAllocateMemory(ULONG Size)
{
PINT_CALLBACK_HEADER Mem;
PTHREADINFO W32Thread;
if(!(Mem = ExAllocatePoolWithTag(PagedPool, Size + sizeof(INT_CALLBACK_HEADER),
USERTAG_CALLBACK)))
{
return NULL;
}
W32Thread = PsGetCurrentThreadWin32Thread();
ASSERT(W32Thread);
/* Insert the callback memory into the thread's callback list */
InsertTailList(&W32Thread->W32CallbackListHead, &Mem->ListEntry);
return (Mem + 1);
}
VOID FASTCALL
IntCbFreeMemory(PVOID Data)
{
PINT_CALLBACK_HEADER Mem;
PTHREADINFO W32Thread;
W32Thread = PsGetCurrentThreadWin32Thread();
ASSERT(W32Thread);
if (W32Thread->TIF_flags & TIF_INCLEANUP)
{
ERR("CbFM Thread is already in cleanup\n");
return;
}
ASSERT(Data);
Mem = ((PINT_CALLBACK_HEADER)Data - 1);
/* Remove the memory block from the thread's callback list */
RemoveEntryList(&Mem->ListEntry);
/* Free memory */
ExFreePoolWithTag(Mem, USERTAG_CALLBACK);
}
VOID FASTCALL
IntCleanupThreadCallbacks(PTHREADINFO W32Thread)
{
PLIST_ENTRY CurrentEntry;
PINT_CALLBACK_HEADER Mem;
while (!IsListEmpty(&W32Thread->W32CallbackListHead))
{
CurrentEntry = RemoveHeadList(&W32Thread->W32CallbackListHead);
Mem = CONTAINING_RECORD(CurrentEntry, INT_CALLBACK_HEADER,
ListEntry);
/* Free memory */
ExFreePoolWithTag(Mem, USERTAG_CALLBACK);
}
}
//
// Pass the Current Window handle and pointer to the Client Callback.
// This will help user space programs speed up read access with the window object.
//
static VOID
IntSetTebWndCallback (HWND * hWnd, PWND * pWnd, PVOID * pActCtx)
{
HWND hWndS = *hWnd;
PWND Window = UserGetWindowObject(*hWnd);
PCLIENTINFO ClientInfo = GetWin32ClientInfo();
*hWnd = ClientInfo->CallbackWnd.hWnd;
*pWnd = ClientInfo->CallbackWnd.pWnd;
*pActCtx = ClientInfo->CallbackWnd.pActCtx;
if (Window)
{
ClientInfo->CallbackWnd.hWnd = hWndS;
ClientInfo->CallbackWnd.pWnd = DesktopHeapAddressToUser(Window);
ClientInfo->CallbackWnd.pActCtx = Window->pActCtx;
}
else //// What if Dispatching WM_SYS/TIMER with NULL window? Fix AbiWord Crash when sizing.
{
ClientInfo->CallbackWnd.hWnd = hWndS;
ClientInfo->CallbackWnd.pWnd = Window;
ClientInfo->CallbackWnd.pActCtx = 0;
}
}
static VOID
IntRestoreTebWndCallback (HWND hWnd, PWND pWnd, PVOID pActCtx)
{
PCLIENTINFO ClientInfo = GetWin32ClientInfo();
ClientInfo->CallbackWnd.hWnd = hWnd;
ClientInfo->CallbackWnd.pWnd = pWnd;
ClientInfo->CallbackWnd.pActCtx = pActCtx;
}
/* FUNCTIONS *****************************************************************/
/* Calls ClientLoadLibrary in user32 */
BOOL
NTAPI
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;
BOOL bResult;
ULONG_PTR pLibNameBuffer = 0, pInitFuncBuffer = 0;
/* Do not allow the desktop thread to do callback to user mode */
ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
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
{
/* Probe and copy the usermode result data */
ProbeForRead(ResultPointer, sizeof(HMODULE), 1);
bResult = *(BOOL*)ResultPointer;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
bResult = FALSE;
}
_SEH2_END;
return bResult;
}
VOID APIENTRY
co_IntCallSentMessageCallback(SENDASYNCPROC CompletionCallback,
HWND hWnd,
UINT Msg,
ULONG_PTR CompletionCallbackContext,
LRESULT Result)
{
SENDASYNCPROC_CALLBACK_ARGUMENTS Arguments;
PVOID ResultPointer, pActCtx;
PWND pWnd;
ULONG ResultLength;
NTSTATUS Status;
/* Do not allow the desktop thread to do callback to user mode */
ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
Arguments.Callback = CompletionCallback;
Arguments.Wnd = hWnd;
Arguments.Msg = Msg;
Arguments.Context = CompletionCallbackContext;
Arguments.Result = Result;
IntSetTebWndCallback (&hWnd, &pWnd, &pActCtx);
UserLeaveCo();
Status = KeUserModeCallback(USER32_CALLBACK_SENDASYNCPROC,
&Arguments,
sizeof(SENDASYNCPROC_CALLBACK_ARGUMENTS),
&ResultPointer,
&ResultLength);
UserEnterCo();
IntRestoreTebWndCallback (hWnd, pWnd, pActCtx);
if (!NT_SUCCESS(Status))
{
ERR("KeUserModeCallback failed with %lx\n", Status);
return;
}
return;
}
LRESULT APIENTRY
co_IntCallWindowProc(WNDPROC Proc,
BOOLEAN IsAnsiProc,
HWND Wnd,
UINT Message,
WPARAM wParam,
LPARAM lParam,
INT lParamBufferSize)
{
WINDOWPROC_CALLBACK_ARGUMENTS StackArguments;
PWINDOWPROC_CALLBACK_ARGUMENTS Arguments;
NTSTATUS Status;
PVOID ResultPointer, pActCtx;
PWND pWnd;
ULONG ResultLength;
ULONG ArgumentLength;
LRESULT Result;
TRACE("co_IntCallWindowProc(Proc %p, IsAnsiProc: %s, Wnd %p, Message %u, wParam %Iu, lParam %Id, lParamBufferSize %d)\n",
Proc, IsAnsiProc ? "TRUE" : "FALSE", Wnd, Message, wParam, lParam, lParamBufferSize);
/* Do not allow the desktop thread to do callback to user mode */
ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
if (lParamBufferSize != -1)
{
ArgumentLength = sizeof(WINDOWPROC_CALLBACK_ARGUMENTS) + lParamBufferSize;
Arguments = IntCbAllocateMemory(ArgumentLength);
if (NULL == Arguments)
{
ERR("Unable to allocate buffer for window proc callback\n");
return -1;
}
RtlMoveMemory((PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
(PVOID) lParam, lParamBufferSize);
}
else
{
Arguments = &StackArguments;
ArgumentLength = sizeof(WINDOWPROC_CALLBACK_ARGUMENTS);
}
Arguments->Proc = Proc;
Arguments->IsAnsiProc = IsAnsiProc;
Arguments->Wnd = Wnd;
Arguments->Msg = Message;
Arguments->wParam = wParam;
Arguments->lParam = lParam;
Arguments->lParamBufferSize = lParamBufferSize;
ResultPointer = NULL;
ResultLength = ArgumentLength;
IntSetTebWndCallback (&Wnd, &pWnd, &pActCtx);
UserLeaveCo();
Status = KeUserModeCallback(USER32_CALLBACK_WINDOWPROC,
Arguments,
ArgumentLength,
&ResultPointer,
&ResultLength);
if (!NT_SUCCESS(Status))
{
ERR("Error Callback to User space Status %lx Message %d\n",Status,Message);
UserEnterCo();
return 0;
}
_SEH2_TRY
{
/* Simulate old behaviour: copy into our local buffer */
RtlMoveMemory(Arguments, ResultPointer, ArgumentLength);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Failed to copy result from user mode, Message %u lParam size %d!\n", Message, lParamBufferSize);
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
UserEnterCo();
IntRestoreTebWndCallback (Wnd, pWnd, pActCtx);
if (!NT_SUCCESS(Status))
{
ERR("Call to user mode failed! 0x%08lx\n",Status);
if (lParamBufferSize != -1)
{
IntCbFreeMemory(Arguments);
}
return -1;
}
Result = Arguments->Result;
if (lParamBufferSize != -1)
{
PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
// Is this message being processed from inside kernel space?
BOOL InSendMessage = (pti->pcti->CTI_flags & CTI_INSENDMESSAGE);
TRACE("Copy lParam Message %u lParam %d!\n", Message, lParam);
switch (Message)
{
default:
TRACE("Don't copy lParam, Message %u Size %d lParam %d!\n", Message, lParamBufferSize, lParam);
break;
// Write back to user/kernel space. Also see g_MsgMemory.
case WM_CREATE:
case WM_GETMINMAXINFO:
case WM_GETTEXT:
case WM_NCCALCSIZE:
case WM_NCCREATE:
case WM_STYLECHANGING:
case WM_WINDOWPOSCHANGING:
case WM_SIZING:
case WM_MOVING:
case WM_MEASUREITEM:
case WM_NEXTMENU:
TRACE("Copy lParam, Message %u Size %d lParam %d!\n", Message, lParamBufferSize, lParam);
if (InSendMessage)
// Copy into kernel space.
RtlMoveMemory((PVOID) lParam,
(PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
lParamBufferSize);
else
{
_SEH2_TRY
{ // Copy into user space.
RtlMoveMemory((PVOID) lParam,
(PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
lParamBufferSize);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Failed to copy lParam to user space, Message %u!\n", Message);
}
_SEH2_END;
}
break;
}
IntCbFreeMemory(Arguments);
}
return Result;
}
HMENU APIENTRY
co_IntLoadSysMenuTemplate(VOID)
{
LRESULT Result = 0;
NTSTATUS Status;
PVOID ResultPointer;
ULONG ResultLength;
/* Do not allow the desktop thread to do callback to user mode */
ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
ResultPointer = NULL;
ResultLength = sizeof(LRESULT);
UserLeaveCo();
Status = KeUserModeCallback(USER32_CALLBACK_LOADSYSMENUTEMPLATE,
&ResultPointer,
0,
&ResultPointer,
&ResultLength);
if (NT_SUCCESS(Status))
{
/* Simulate old behaviour: copy into our local buffer */
_SEH2_TRY
{
ProbeForRead(ResultPointer, sizeof(LRESULT), 1);
Result = *(LRESULT*)ResultPointer;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Result = 0;
}
_SEH2_END;
}
UserEnterCo();
return (HMENU)Result;
}
extern HCURSOR gDesktopCursor;
BOOL APIENTRY
co_IntLoadDefaultCursors(VOID)
{
NTSTATUS Status;
PVOID ResultPointer;
ULONG ResultLength;
BOOL DefaultCursor = TRUE;
/* Do not allow the desktop thread to do callback to user mode */
ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
ResultPointer = NULL;
ResultLength = sizeof(HCURSOR);
UserLeaveCo();
Status = KeUserModeCallback(USER32_CALLBACK_LOADDEFAULTCURSORS,
&DefaultCursor,
sizeof(BOOL),
&ResultPointer,
&ResultLength);
UserEnterCo();
if (!NT_SUCCESS(Status))
{
return FALSE;
}
/* HACK: The desktop class doen't have a proper cursor yet, so set it here */
gDesktopCursor = *((HCURSOR*)ResultPointer);
return TRUE;
}
static INT iTheId = -2; // Set it out of range.
LRESULT APIENTRY
co_IntCallHookProc(INT HookId,
INT Code,
WPARAM wParam,
LPARAM lParam,
HOOKPROC Proc,
INT Mod,
ULONG_PTR offPfn,
BOOLEAN Ansi,
PUNICODE_STRING ModuleName)
{
ULONG ArgumentLength;
PVOID Argument = NULL;
LRESULT Result = 0;
NTSTATUS Status;
PVOID ResultPointer;
ULONG ResultLength;
PHOOKPROC_CALLBACK_ARGUMENTS Common;
CBT_CREATEWNDW *CbtCreateWnd = NULL;
PCHAR Extra;
PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra = NULL;
PTHREADINFO pti;
PWND pWnd;
PMSG pMsg = NULL;
BOOL Hit = FALSE;
UINT lParamSize = 0;
CWPSTRUCT* pCWP = NULL;
CWPRETSTRUCT* pCWPR = NULL;
ASSERT(Proc);
/* Do not allow the desktop thread to do callback to user mode */
ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
pti = PsGetCurrentThreadWin32Thread();
if (pti->TIF_flags & TIF_INCLEANUP)
{
ERR("Thread is in cleanup and trying to call hook %d\n", Code);
return 0;
}
ArgumentLength = sizeof(HOOKPROC_CALLBACK_ARGUMENTS);
switch(HookId)
{
case WH_CBT:
TRACE("WH_CBT: Code %d\n", Code);
switch(Code)
{
case HCBT_CREATEWND:
pWnd = UserGetWindowObject((HWND) wParam);
if (!pWnd)
{
ERR("WH_CBT HCBT_CREATEWND wParam bad hWnd!\n");
goto Fault_Exit;
}
TRACE("HCBT_CREATEWND AnsiCreator %s, AnsiHook %s\n", pWnd->state & WNDS_ANSICREATOR ? "True" : "False", Ansi ? "True" : "False");
// Due to KsStudio.exe, just pass the callers original pointers
// except class which point to kernel space if not an atom.
// Found by, Olaf Siejka
CbtCreateWnd = (CBT_CREATEWNDW *) lParam;
ArgumentLength += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS);
break;
case HCBT_MOVESIZE:
ArgumentLength += sizeof(RECTL);
break;
case HCBT_ACTIVATE:
ArgumentLength += sizeof(CBTACTIVATESTRUCT);
break;
case HCBT_CLICKSKIPPED:
ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
break;
/* ATM pass on */
case HCBT_KEYSKIPPED:
case HCBT_MINMAX:
case HCBT_SETFOCUS:
case HCBT_SYSCOMMAND:
/* These types pass through. */
case HCBT_DESTROYWND:
case HCBT_QS:
break;
default:
ERR("Trying to call unsupported CBT hook %d\n", Code);
goto Fault_Exit;
}
break;
case WH_KEYBOARD_LL:
ArgumentLength += sizeof(KBDLLHOOKSTRUCT);
break;
case WH_MOUSE_LL:
ArgumentLength += sizeof(MSLLHOOKSTRUCT);
break;
case WH_MOUSE:
ArgumentLength += sizeof(MOUSEHOOKSTRUCT);
break;
case WH_CALLWNDPROC:
{
pCWP = (CWPSTRUCT*) lParam;
ArgumentLength = sizeof(CWP_Struct);
if ( pCWP->message == WM_CREATE || pCWP->message == WM_NCCREATE )
{
lParamSize = sizeof(CREATESTRUCTW);
}
else
lParamSize = lParamMemorySize(pCWP->message, pCWP->wParam, pCWP->lParam);
ArgumentLength += lParamSize;
break;
}
case WH_CALLWNDPROCRET:
{
pCWPR = (CWPRETSTRUCT*) lParam;
ArgumentLength = sizeof(CWPR_Struct);
if ( pCWPR->message == WM_CREATE || pCWPR->message == WM_NCCREATE )
{
lParamSize = sizeof(CREATESTRUCTW);
}
else
lParamSize = lParamMemorySize(pCWPR->message, pCWPR->wParam, pCWPR->lParam);
ArgumentLength += lParamSize;
break;
}
case WH_MSGFILTER:
case WH_SYSMSGFILTER:
case WH_GETMESSAGE:
ArgumentLength += sizeof(MSG);
break;
case WH_FOREGROUNDIDLE:
case WH_KEYBOARD:
case WH_SHELL:
break;
default:
ERR("Trying to call unsupported window hook %d\n", HookId);
goto Fault_Exit;
}
Argument = IntCbAllocateMemory(ArgumentLength);
if (NULL == Argument)
{
ERR("HookProc callback %d failed: out of memory %d\n",HookId,ArgumentLength);
goto Fault_Exit;
}
Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Argument;
Common->HookId = HookId;
Common->Code = Code;
Common->wParam = wParam;
Common->lParam = lParam;
Common->Proc = Proc;
Common->Mod = Mod;
Common->offPfn = offPfn;
Common->Ansi = Ansi;
Common->lParamSize = lParamSize;
RtlZeroMemory(&Common->ModuleName, sizeof(Common->ModuleName));
if (ModuleName->Buffer && ModuleName->Length)
{
RtlCopyMemory(&Common->ModuleName, ModuleName->Buffer, ModuleName->Length);
// If ModuleName->Buffer NULL while in destroy,
// this will make User32:Hook.c complain about not loading the library module.
// Fix symptom for CORE-10549.
}
Extra = (PCHAR) Common + sizeof(HOOKPROC_CALLBACK_ARGUMENTS);
switch(HookId)
{
case WH_CBT:
switch(Code)
{ // Need to remember this is not the first time through! Call Next Hook?
case HCBT_CREATEWND:
CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS) Extra;
RtlCopyMemory( &CbtCreatewndExtra->Cs, CbtCreateWnd->lpcs, sizeof(CREATESTRUCTW) );
CbtCreatewndExtra->WndInsertAfter = CbtCreateWnd->hwndInsertAfter;
CbtCreatewndExtra->Cs.lpszClass = CbtCreateWnd->lpcs->lpszClass;
CbtCreatewndExtra->Cs.lpszName = CbtCreateWnd->lpcs->lpszName;
Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
//ERR("HCBT_CREATEWND: hWnd %p Csw %p Name %p Class %p\n", Common->wParam, CbtCreateWnd->lpcs, CbtCreateWnd->lpcs->lpszName, CbtCreateWnd->lpcs->lpszClass);
break;
case HCBT_CLICKSKIPPED:
RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
break;
case HCBT_MOVESIZE:
RtlCopyMemory(Extra, (PVOID) lParam, sizeof(RECTL));
Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
break;
case HCBT_ACTIVATE:
RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CBTACTIVATESTRUCT));
Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
break;
}
break;
case WH_KEYBOARD_LL:
RtlCopyMemory(Extra, (PVOID) lParam, sizeof(KBDLLHOOKSTRUCT));
Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
break;
case WH_MOUSE_LL:
RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSLLHOOKSTRUCT));
Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
break;
case WH_MOUSE:
RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT));
Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
break;
case WH_CALLWNDPROC:
{
PCWP_Struct pcwps = (PCWP_Struct)Common;
RtlCopyMemory( &pcwps->cwps, pCWP, sizeof(CWPSTRUCT));
/* For CALLWNDPROC and CALLWNDPROCRET, we must be wary of the fact that
* lParam could be a pointer to a buffer. This buffer must be exported
* to user space too */
if ( lParamSize )
{
RtlCopyMemory( &pcwps->Extra, (PVOID)pCWP->lParam, lParamSize );
}
}
break;
case WH_CALLWNDPROCRET:
{
PCWPR_Struct pcwprs = (PCWPR_Struct)Common;
RtlCopyMemory( &pcwprs->cwprs, pCWPR, sizeof(CWPRETSTRUCT));
if ( lParamSize )
{
RtlCopyMemory( &pcwprs->Extra, (PVOID)pCWPR->lParam, lParamSize );
}
}
break;
case WH_MSGFILTER:
case WH_SYSMSGFILTER:
case WH_GETMESSAGE:
pMsg = (PMSG)lParam;
RtlCopyMemory(Extra, (PVOID) pMsg, sizeof(MSG));
Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
break;
case WH_FOREGROUNDIDLE:
case WH_KEYBOARD:
case WH_SHELL:
break;
}
ResultPointer = NULL;
ResultLength = ArgumentLength;
UserLeaveCo();
Status = KeUserModeCallback(USER32_CALLBACK_HOOKPROC,
Argument,
ArgumentLength,
&ResultPointer,
&ResultLength);
UserEnterCo();
if (!NT_SUCCESS(Status))
{
if ( iTheId != HookId ) // Hook ID can change.
{
ERR("Failure to make Callback %d! Status 0x%x ArgumentLength %d\n",HookId,Status,ArgumentLength);
iTheId = HookId;
}
goto Fault_Exit;
}
if (ResultPointer)
{
_SEH2_TRY
{
/* Simulate old behaviour: copy into our local buffer */
RtlMoveMemory(Argument, ResultPointer, ArgumentLength);
Result = Common->Result;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Result = 0;
Hit = TRUE;
}
_SEH2_END;
}
else
{
ERR("ERROR: Hook %d Code %d ResultPointer 0x%p ResultLength %u\n",HookId,Code,ResultPointer,ResultLength);
}
/* Support write backs... SEH is in UserCallNextHookEx. */
switch (HookId)
{
case WH_CBT:
{
switch (Code)
{
case HCBT_CREATEWND:
if (CbtCreatewndExtra)
{/*
The parameters could have been changed, include the coordinates
and dimensions of the window. We copy it back.
*/
CbtCreateWnd->hwndInsertAfter = CbtCreatewndExtra->WndInsertAfter;
CbtCreateWnd->lpcs->x = CbtCreatewndExtra->Cs.x;
CbtCreateWnd->lpcs->y = CbtCreatewndExtra->Cs.y;
CbtCreateWnd->lpcs->cx = CbtCreatewndExtra->Cs.cx;
CbtCreateWnd->lpcs->cy = CbtCreatewndExtra->Cs.cy;
}
break;
case HCBT_MOVESIZE:
if (Extra && lParam)
{
RtlCopyMemory((PVOID) lParam, Extra, sizeof(RECTL));
}
break;
}
}
// "The GetMsgProc hook procedure can examine or modify the message."
case WH_GETMESSAGE:
if (pMsg)
{
RtlCopyMemory((PVOID) pMsg, Extra, sizeof(MSG));
}
break;
}
Fault_Exit:
if (Hit)
{
ERR("Exception CallHookProc HookId %d Code %d\n",HookId,Code);
}
if (Argument) IntCbFreeMemory(Argument);
return Result;
}
//
// Events are notifications w/o results.
//
LRESULT
APIENTRY
co_IntCallEventProc(HWINEVENTHOOK hook,
DWORD event,
HWND hWnd,
LONG idObject,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime,
WINEVENTPROC Proc,
INT Mod,
ULONG_PTR offPfn)
{
LRESULT Result = 0;
NTSTATUS Status;
PEVENTPROC_CALLBACK_ARGUMENTS Common;
ULONG ArgumentLength, ResultLength;
PVOID Argument, ResultPointer;
ArgumentLength = sizeof(EVENTPROC_CALLBACK_ARGUMENTS);
Argument = IntCbAllocateMemory(ArgumentLength);
if (NULL == Argument)
{
ERR("EventProc callback failed: out of memory\n");
return 0;
}
Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Argument;
Common->hook = hook;
Common->event = event;
Common->hwnd = hWnd;
Common->idObject = idObject;
Common->idChild = idChild;
Common->dwEventThread = dwEventThread;
Common->dwmsEventTime = dwmsEventTime;
Common->Proc = Proc;
Common->Mod = Mod;
Common->offPfn = offPfn;
ResultPointer = NULL;
ResultLength = sizeof(LRESULT);
UserLeaveCo();
Status = KeUserModeCallback(USER32_CALLBACK_EVENTPROC,
Argument,
ArgumentLength,
&ResultPointer,
&ResultLength);
UserEnterCo();
IntCbFreeMemory(Argument);
if (!NT_SUCCESS(Status))
{
return 0;
}
return Result;
}
//
// Callback Load Menu and results.
//
HMENU
APIENTRY
co_IntCallLoadMenu( HINSTANCE hModule,
PUNICODE_STRING pMenuName )
{
LRESULT Result = 0;
NTSTATUS Status;
PLOADMENU_CALLBACK_ARGUMENTS Common;
ULONG ArgumentLength, ResultLength;
PVOID Argument, ResultPointer;
ArgumentLength = sizeof(LOADMENU_CALLBACK_ARGUMENTS);
ArgumentLength += pMenuName->Length + sizeof(WCHAR);
Argument = IntCbAllocateMemory(ArgumentLength);
if (NULL == Argument)
{
ERR("LoadMenu callback failed: out of memory\n");
return 0;
}
Common = (PLOADMENU_CALLBACK_ARGUMENTS) Argument;
// Help Intersource check and MenuName is now 4 bytes + so zero it.
RtlZeroMemory(Common, ArgumentLength);
Common->hModule = hModule;
if (pMenuName->Length)
RtlCopyMemory(&Common->MenuName, pMenuName->Buffer, pMenuName->Length);
else
Common->InterSource = pMenuName->Buffer;
ResultPointer = NULL;
ResultLength = sizeof(LRESULT);
UserLeaveCo();
Status = KeUserModeCallback(USER32_CALLBACK_LOADMENU,
Argument,
ArgumentLength,
&ResultPointer,
&ResultLength);
UserEnterCo();
if (NT_SUCCESS(Status))
{
Result = *(LRESULT*)ResultPointer;
}
else
{
Result = 0;
}
IntCbFreeMemory(Argument);
return (HMENU)Result;
}
NTSTATUS
APIENTRY
co_IntClientThreadSetup(VOID)
{
NTSTATUS Status;
ULONG ArgumentLength, ResultLength;
PVOID Argument, ResultPointer;
/* Do not allow the desktop thread to do callback to user mode */
ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread);
ArgumentLength = ResultLength = 0;
Argument = ResultPointer = NULL;
UserLeaveCo();
Status = KeUserModeCallback(USER32_CALLBACK_CLIENTTHREADSTARTUP,
Argument,
ArgumentLength,
&ResultPointer,
&ResultLength);
UserEnterCo();
return Status;
}
HANDLE FASTCALL
co_IntCopyImage(HANDLE hnd, UINT type, INT desiredx, INT desiredy, UINT flags)
{
HANDLE Handle;
NTSTATUS Status;
ULONG ArgumentLength, ResultLength;
PVOID Argument, ResultPointer;
PCOPYIMAGE_CALLBACK_ARGUMENTS Common;
ArgumentLength = ResultLength = 0;
Argument = ResultPointer = NULL;
ArgumentLength = sizeof(COPYIMAGE_CALLBACK_ARGUMENTS);
Argument = IntCbAllocateMemory(ArgumentLength);
if (NULL == Argument)
{
ERR("CopyImage callback failed: out of memory\n");
return 0;
}
Common = (PCOPYIMAGE_CALLBACK_ARGUMENTS) Argument;
Common->hImage = hnd;
Common->uType = type;
Common->cxDesired = desiredx;
Common->cyDesired = desiredy;
Common->fuFlags = flags;
UserLeaveCo();
Status = KeUserModeCallback(USER32_CALLBACK_COPYIMAGE,
Argument,
ArgumentLength,
&ResultPointer,
&ResultLength);
UserEnterCo();
if (NT_SUCCESS(Status))
{
Handle = *(HANDLE*)ResultPointer;
}
else
{
ERR("CopyImage callback failed!\n");
Handle = NULL;
}
IntCbFreeMemory(Argument);
return Handle;
}
BOOL
APIENTRY
co_IntGetCharsetInfo(LCID Locale, PCHARSETINFO pCs)
{
NTSTATUS Status;
ULONG ArgumentLength, ResultLength;
PVOID Argument, ResultPointer;
PGET_CHARSET_INFO Common;
ArgumentLength = sizeof(GET_CHARSET_INFO);
Argument = IntCbAllocateMemory(ArgumentLength);
if (NULL == Argument)
{
ERR("GetCharsetInfo callback failed: out of memory\n");
return 0;
}
Common = (PGET_CHARSET_INFO) Argument;
Common->Locale = Locale;
ResultPointer = NULL;
ResultLength = ArgumentLength;
UserLeaveCo();
Status = KeUserModeCallback(USER32_CALLBACK_GETCHARSETINFO,
Argument,
ArgumentLength,
&ResultPointer,
&ResultLength);
if (NT_SUCCESS(Status))
{
_SEH2_TRY
{
/* Need to copy into our local buffer */
RtlMoveMemory(Argument, ResultPointer, ArgumentLength);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ERR("Failed to copy result from user mode!\n");
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
UserEnterCo();
RtlCopyMemory(pCs, &Common->Cs, sizeof(CHARSETINFO));
IntCbFreeMemory(Argument);
if (!NT_SUCCESS(Status))
{
ERR("GetCharsetInfo Failed!!\n");
return FALSE;
}
return TRUE;
}
BOOL FASTCALL
co_IntSetWndIcons(VOID)
{
NTSTATUS Status;
ULONG ArgumentLength, ResultLength;
PVOID Argument, ResultPointer;
PSETWNDICONS_CALLBACK_ARGUMENTS Common;
ResultPointer = NULL;
ResultLength = ArgumentLength = sizeof(SETWNDICONS_CALLBACK_ARGUMENTS);
Argument = IntCbAllocateMemory(ArgumentLength);
if (NULL == Argument)
{
ERR("Set Window Icons callback failed: out of memory\n");
return FALSE;
}
Common = (PSETWNDICONS_CALLBACK_ARGUMENTS) Argument;
UserLeaveCo();
Status = KeUserModeCallback(USER32_CALLBACK_SETWNDICONS,
Argument,
ArgumentLength,
&ResultPointer,
&ResultLength);
UserEnterCo();
if (!NT_SUCCESS(Status))
{
ERR("Set Window Icons callback failed!\n");
IntCbFreeMemory(Argument);
return FALSE;
}
RtlMoveMemory(Common, ResultPointer, ArgumentLength);
gpsi->hIconSmWindows = Common->hIconSmWindows;
gpsi->hIconWindows = Common->hIconWindows;
IntLoadSystenIcons(Common->hIconSample, OIC_SAMPLE);
IntLoadSystenIcons(Common->hIconHand, OIC_HAND);
IntLoadSystenIcons(Common->hIconQuestion, OIC_QUES);
IntLoadSystenIcons(Common->hIconBang, OIC_BANG);
IntLoadSystenIcons(Common->hIconNote, OIC_NOTE);
IntLoadSystenIcons(gpsi->hIconWindows, OIC_WINLOGO);
IntLoadSystenIcons(gpsi->hIconSmWindows, OIC_WINLOGO+1);
ERR("hIconSmWindows %p hIconWindows %p \n",gpsi->hIconSmWindows,gpsi->hIconWindows);
IntCbFreeMemory(Argument);
return TRUE;
}
VOID FASTCALL
co_IntDeliverUserAPC(VOID)
{
ULONG ResultLength;
PVOID ResultPointer;
NTSTATUS Status;
UserLeaveCo();
Status = KeUserModeCallback(USER32_CALLBACK_DELIVERUSERAPC,
0,
0,
&ResultPointer,
&ResultLength);
UserEnterCo();
if (!NT_SUCCESS(Status))
{
ERR("Delivering User APC callback failed!\n");
}
}
VOID FASTCALL
co_IntSetupOBM(VOID)
{
NTSTATUS Status;
ULONG ArgumentLength, ResultLength;
PVOID Argument, ResultPointer;
PSETOBM_CALLBACK_ARGUMENTS Common;
ResultPointer = NULL;
ResultLength = ArgumentLength = sizeof(SETOBM_CALLBACK_ARGUMENTS);
Argument = IntCbAllocateMemory(ArgumentLength);
if (NULL == Argument)
{
ERR("Set Window Icons callback failed: out of memory\n");
return;
}
Common = (PSETOBM_CALLBACK_ARGUMENTS) Argument;
UserLeaveCo();
Status = KeUserModeCallback(USER32_CALLBACK_SETOBM,
Argument,
ArgumentLength,
&ResultPointer,
&ResultLength);
UserEnterCo();
if (!NT_SUCCESS(Status))
{
ERR("Set Window Icons callback failed!\n");
IntCbFreeMemory(Argument);
return;
}
RtlMoveMemory(Common, ResultPointer, ArgumentLength);
RtlCopyMemory(gpsi->oembmi, Common->oembmi, sizeof(gpsi->oembmi));
IntCbFreeMemory(Argument);
}
/* EOF */