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(); /* HACK: The desktop class doen't have a proper cursor yet, so set it here */ gDesktopCursor = *((HCURSOR*)ResultPointer); if (!NT_SUCCESS(Status)) { return FALSE; } return TRUE; }
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)) { return; } return; }
HMENU APIENTRY co_IntLoadSysMenuTemplate() { 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; }
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; /* 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); _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 %d 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!\n"); 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 %d lParam %d!\n", Message, lParam); switch (Message) { default: TRACE("Don't copy lParam, Message %d 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: TRACE("Copy lParam, Message %d 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 %d!\n", Message); } _SEH2_END; } break; } IntCbFreeMemory(Arguments); }
/* 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; }
/* * Function copied from ntdll/csr/connect.c::CsrClientCallServer * and adapted for kernel-mode. * * NOTE: This is really a co_* function! */ NTSTATUS NTAPI CsrClientCallServer(IN OUT PCSR_API_MESSAGE ApiMessage, IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer OPTIONAL, IN CSR_API_NUMBER ApiNumber, IN ULONG DataLength) { NTSTATUS Status; #if 0 ULONG PointerCount; PULONG_PTR OffsetPointer; #endif /* Do we have a connection to CSR yet? */ if (!CsrApiPort) return STATUS_INVALID_PORT_HANDLE; /* Fill out the Port Message Header */ ApiMessage->Header.u2.ZeroInit = 0; ApiMessage->Header.u1.s1.TotalLength = DataLength + sizeof(CSR_API_MESSAGE) - sizeof(ApiMessage->Data); // FIELD_OFFSET(CSR_API_MESSAGE, Data) + DataLength; ApiMessage->Header.u1.s1.DataLength = DataLength + FIELD_OFFSET(CSR_API_MESSAGE, Data) - sizeof(ApiMessage->Header); // ApiMessage->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE); /* Fill out the CSR Header */ ApiMessage->ApiNumber = ApiNumber; ApiMessage->CsrCaptureData = NULL; TRACE("API: %lx, u1.s1.DataLength: %x, u1.s1.TotalLength: %x\n", ApiNumber, ApiMessage->Header.u1.s1.DataLength, ApiMessage->Header.u1.s1.TotalLength); #if 0 /* Check if we got a Capture Buffer */ if (CaptureBuffer) { /* * We have to convert from our local (client) view * to the remote (server) view. */ ApiMessage->CsrCaptureData = (PCSR_CAPTURE_BUFFER) ((ULONG_PTR)CaptureBuffer + CsrPortMemoryDelta); /* Lock the buffer. */ CaptureBuffer->BufferEnd = NULL; /* * Each client pointer inside the CSR message is converted into * a server pointer, and each pointer to these message pointers * is converted into an offset. */ PointerCount = CaptureBuffer->PointerCount; OffsetPointer = CaptureBuffer->PointerOffsetsArray; while (PointerCount--) { if (*OffsetPointer != 0) { *(PULONG_PTR)*OffsetPointer += CsrPortMemoryDelta; *OffsetPointer -= (ULONG_PTR)ApiMessage; } ++OffsetPointer; } } #endif UserLeaveCo(); /* Send the LPC Message */ // The wait logic below is subject to change in the future. One can // imagine adding an external parameter to CsrClientCallServer, or write // two versions of CsrClientCallServer, synchronous and asynchronous. if (PsGetCurrentProcess() == gpepCSRSS) { Status = LpcRequestPort(CsrApiPort, &ApiMessage->Header); } else { Status = LpcRequestWaitReplyPort(CsrApiPort, &ApiMessage->Header, &ApiMessage->Header); } UserEnterCo(); #if 0 /* Check if we got a Capture Buffer */ if (CaptureBuffer) { /* * We have to convert back from the remote (server) view * to our local (client) view. */ ApiMessage->CsrCaptureData = (PCSR_CAPTURE_BUFFER) ((ULONG_PTR)ApiMessage->CsrCaptureData - CsrPortMemoryDelta); /* * Convert back the offsets into pointers to CSR message * pointers, and convert back these message server pointers * into client pointers. */ PointerCount = CaptureBuffer->PointerCount; OffsetPointer = CaptureBuffer->PointerOffsetsArray; while (PointerCount--) { if (*OffsetPointer != 0) { *OffsetPointer += (ULONG_PTR)ApiMessage; *(PULONG_PTR)*OffsetPointer -= CsrPortMemoryDelta; } ++OffsetPointer; } } #endif /* Check for success */ if (!NT_SUCCESS(Status)) { /* We failed. Overwrite the return value with the failure. */ ERR("LPC Failed: %lx\n", Status); ApiMessage->Status = Status; } /* Return the CSR Result */ TRACE("Got back: 0x%lx\n", ApiMessage->Status); return ApiMessage->Status; }
LRESULT APIENTRY co_IntCallHookProc(INT HookId, INT Code, WPARAM wParam, LPARAM lParam, HOOKPROC Proc, 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; 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: { CWPSTRUCT* pCWP = (CWPSTRUCT*) lParam; ArgumentLength += sizeof(CWPSTRUCT); lParamSize = lParamMemorySize(pCWP->message, pCWP->wParam, pCWP->lParam); ArgumentLength += lParamSize; break; } case WH_CALLWNDPROCRET: { CWPRETSTRUCT* pCWPR = (CWPRETSTRUCT*) lParam; ArgumentLength += sizeof(CWPRETSTRUCT); 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 failed: out of memory\n"); goto Fault_Exit; } Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Argument; Common->HookId = HookId; Common->Code = Code; Common->wParam = wParam; Common->lParam = lParam; Common->Proc = Proc; Common->Ansi = Ansi; 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); 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: /* 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 */ RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPSTRUCT)); Common->lParam = (LPARAM) (Extra - (PCHAR) Common); if(lParamSize) { RtlCopyMemory(Extra + sizeof(CWPSTRUCT), (PVOID)((CWPSTRUCT*)lParam)->lParam, lParamSize); ((CWPSTRUCT*)Extra)->lParam = (LPARAM)lParamSize; } break; case WH_CALLWNDPROCRET: RtlCopyMemory(Extra, (PVOID) lParam, sizeof(CWPRETSTRUCT)); Common->lParam = (LPARAM) (Extra - (PCHAR) Common); if(lParamSize) { RtlCopyMemory(Extra + sizeof(CWPRETSTRUCT), (PVOID)((CWPRETSTRUCT*)lParam)->lParam, lParamSize); ((CWPRETSTRUCT*)Extra)->lParam = (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 = sizeof(LRESULT); UserLeaveCo(); Status = KeUserModeCallback(USER32_CALLBACK_HOOKPROC, Argument, ArgumentLength, &ResultPointer, &ResultLength); UserEnterCo(); if (ResultPointer) { _SEH2_TRY { ProbeForRead(ResultPointer, sizeof(LRESULT), 1); /* Simulate old behaviour: copy into our local buffer */ Result = *(LRESULT*)ResultPointer; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Result = 0; Hit = TRUE; } _SEH2_END; } else {
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; /* Do not allow the desktop thread to do callback to user mode */ ASSERT(PsGetCurrentThreadWin32Thread() != gptiDesktopThread); if (0 < lParamBufferSize) { 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); _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!\n"); Status = _SEH2_GetExceptionCode(); } _SEH2_END; UserEnterCo(); IntRestoreTebWndCallback (Wnd, pWnd, pActCtx); if (!NT_SUCCESS(Status)) { ERR("Call to user mode failed!\n"); if (0 < lParamBufferSize) { IntCbFreeMemory(Arguments); } return -1; } Result = Arguments->Result; if (0 < lParamBufferSize) { RtlMoveMemory((PVOID) lParam, (PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)), lParamBufferSize); IntCbFreeMemory(Arguments); } return Result; }