From 200c27535ef11657f00218e5a4dbee8e85c7bb30 Mon Sep 17 00:00:00 2001 From: James Tabor Date: Thu, 4 Nov 2010 23:45:34 +0000 Subject: [PATCH] [Win32k|User32] - This hook commit fixes the ros regression testing startup, but consider this a hax fix until more research in Global hooks has completed. More pointed Global hook tests are needed. Misc changes, removed unused storage pointers and reordering. For DosBOX, the mouse low level is now working and the keyboard low level should not be so intermittent as before, now sending messages from system desktop not from thread desktop, see bug 5670 for more details. svn path=/trunk/; revision=49472 --- reactos/dll/win32/user32/windows/hook.c | 92 +++---- reactos/include/reactos/win32k/callback.h | 2 - .../subsystems/win32/win32k/main/dllmain.c | 32 ++- .../subsystems/win32/win32k/ntuser/callback.c | 25 +- .../subsystems/win32/win32k/ntuser/desktop.c | 11 + reactos/subsystems/win32/win32k/ntuser/hook.c | 230 +++++++++++++----- .../subsystems/win32/win32k/ntuser/input.c | 22 +- .../subsystems/win32/win32k/ntuser/window.c | 75 ++++-- 8 files changed, 341 insertions(+), 148 deletions(-) diff --git a/reactos/dll/win32/user32/windows/hook.c b/reactos/dll/win32/user32/windows/hook.c index b848225741b..c2c8f3efd65 100644 --- a/reactos/dll/win32/user32/windows/hook.c +++ b/reactos/dll/win32/user32/windows/hook.c @@ -154,49 +154,18 @@ CallMsgFilterA( LPMSG lpMsg, int nCode) { - BOOL ret = FALSE; - - if (nCode != HCBT_CREATEWND) ret = NtUserCallMsgFilter((LPMSG) lpMsg, nCode); - else + MSG Msg; + if (NtCurrentTeb()->Win32ThreadInfo && IsThreadHooked(GetWin32ClientInfo())) + { + if ( lpMsg->message & ~WM_MAXIMUM ) { - UNICODE_STRING usBuffer; - CBT_CREATEWNDA *cbtcwA = (CBT_CREATEWNDA *)lpMsg->lParam; - CBT_CREATEWNDW cbtcwW; - CREATESTRUCTW csW; - MSG Msg; - - Msg.hwnd = lpMsg->hwnd; - Msg.message = lpMsg->message; - Msg.time = lpMsg->time; - Msg.pt = lpMsg->pt; - Msg.wParam = lpMsg->wParam; - - cbtcwW.lpcs = &csW; - cbtcwW.hwndInsertAfter = cbtcwA->hwndInsertAfter; - csW = *(CREATESTRUCTW *)cbtcwA->lpcs; - - if (HIWORD(cbtcwA->lpcs->lpszName)) - { - RtlCreateUnicodeStringFromAsciiz(&usBuffer,cbtcwA->lpcs->lpszName); - csW.lpszName = usBuffer.Buffer; - } - if (HIWORD(cbtcwA->lpcs->lpszClass)) - { - RtlCreateUnicodeStringFromAsciiz(&usBuffer,cbtcwA->lpcs->lpszClass); - csW.lpszClass = usBuffer.Buffer; - } - Msg.lParam =(LPARAM) &cbtcwW; - - ret = NtUserCallMsgFilter((LPMSG)&Msg, nCode); - - lpMsg->time = Msg.time; - lpMsg->pt = Msg.pt; - - cbtcwA->hwndInsertAfter = cbtcwW.hwndInsertAfter; - if (HIWORD(csW.lpszName)) HeapFree( GetProcessHeap(), 0, (LPWSTR)csW.lpszName ); - if (HIWORD(csW.lpszClass)) HeapFree( GetProcessHeap(), 0, (LPWSTR)csW.lpszClass ); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; } - return ret; + RtlCopyMemory(&Msg, lpMsg, sizeof(MSG)); + return NtUserCallMsgFilter( &Msg, nCode); + } + return FALSE; } @@ -209,7 +178,18 @@ CallMsgFilterW( LPMSG lpMsg, int nCode) { - return NtUserCallMsgFilter((LPMSG) lpMsg, nCode); + MSG Msg; + if (NtCurrentTeb()->Win32ThreadInfo && IsThreadHooked(GetWin32ClientInfo())) + { + if ( lpMsg->message & ~WM_MAXIMUM ) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + RtlCopyMemory(&Msg, lpMsg, sizeof(MSG)); + return NtUserCallMsgFilter( &Msg, nCode); + } + return FALSE; } @@ -454,7 +434,7 @@ User32CallHookProcFromKernel(PVOID Arguments, ULONG ArgumentLength) PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra = NULL; KBDLLHOOKSTRUCT KeyboardLlData, *pKeyboardLlData; MSLLHOOKSTRUCT MouseLlData, *pMouseLlData; - MSG Msg, *pMsg; + MSG *pcMsg, *pMsg; PMOUSEHOOKSTRUCT pMHook; CWPSTRUCT CWP, *pCWP; CWPRETSTRUCT CWPR, *pCWPR; @@ -476,13 +456,12 @@ User32CallHookProcFromKernel(PVOID Arguments, ULONG ArgumentLength) case HCBT_CREATEWND: CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS) ((PCHAR) Common + Common->lParam); - Csw = CbtCreatewndExtra->Cs; - Csw.lpszName = CbtCreatewndExtra->Cs.lpszName; - Csw.lpszClass = CbtCreatewndExtra->Cs.lpszClass; - wParam = Common->wParam; + RtlCopyMemory(&Csw, &CbtCreatewndExtra->Cs, sizeof(CREATESTRUCTW)); CbtCreatewndw.lpcs = &Csw; CbtCreatewndw.hwndInsertAfter = CbtCreatewndExtra->WndInsertAfter; + wParam = Common->wParam; lParam = (LPARAM) &CbtCreatewndw; + ERR("HCBT_CREATEWND: hWnd 0x%x Name 0x%x Class 0x%x\n", Common->wParam, Csw.lpszName, Csw.lpszClass); break; case HCBT_CLICKSKIPPED: pMHook = (PMOUSEHOOKSTRUCT)((PCHAR) Common + Common->lParam); @@ -524,7 +503,7 @@ User32CallHookProcFromKernel(PVOID Arguments, ULONG ArgumentLength) } else { - ERR("Common = 0x%x, Proc = 0x%x\n",Common,Common->Proc); + ERR("Null Proc! Common = 0x%x, Proc = 0x%x\n",Common,Common->Proc); } switch(Common->Code) { @@ -545,6 +524,7 @@ User32CallHookProcFromKernel(PVOID Arguments, ULONG ArgumentLength) Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) &KeyboardLlData); break; case WH_MOUSE_LL: + ERR("WH_MOUSE_LL: Code %d, wParam %d\n",Common->Code,Common->wParam); pMouseLlData = (PMSLLHOOKSTRUCT)((PCHAR) Common + Common->lParam); RtlCopyMemory(&MouseLlData, pMouseLlData, sizeof(MSLLHOOKSTRUCT)); Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) &MouseLlData); @@ -562,7 +542,7 @@ User32CallHookProcFromKernel(PVOID Arguments, ULONG ArgumentLength) _SEH2_END; break; case WH_CALLWNDPROC: - ERR("WH_CALLWNDPROC: Code %d, wParam %d\n",Common->Code,Common->wParam); +// ERR("WH_CALLWNDPROC: Code %d, wParam %d\n",Common->Code,Common->wParam); pCWP = (PCWPSTRUCT)((PCHAR) Common + Common->lParam); RtlCopyMemory(&CWP, pCWP, sizeof(CWPSTRUCT)); Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) &CWP); @@ -573,14 +553,15 @@ User32CallHookProcFromKernel(PVOID Arguments, ULONG ArgumentLength) Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) &CWPR); break; case WH_MSGFILTER: /* All SEH support */ - ERR("WH_MSGFILTER: Code %d, wParam %d\n",Common->Code,Common->wParam); case WH_SYSMSGFILTER: case WH_GETMESSAGE: pMsg = (PMSG)((PCHAR) Common + Common->lParam); - RtlCopyMemory(&Msg, pMsg, sizeof(MSG)); + pcMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MSG)); + RtlCopyMemory(pcMsg, pMsg, sizeof(MSG)); +// ERR("pMsg %d pcMsg %d\n",pMsg->message, pcMsg->message); _SEH2_TRY { - Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) &Msg); + Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) pcMsg); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { @@ -588,11 +569,14 @@ User32CallHookProcFromKernel(PVOID Arguments, ULONG ArgumentLength) } _SEH2_END; if (!Hit && Common->HookId == WH_GETMESSAGE) - RtlCopyMemory(pMsg, &Msg, sizeof(MSG)); + RtlCopyMemory(pMsg, pcMsg, sizeof(MSG)); + HeapFree( GetProcessHeap(), 0, pcMsg ); break; - case WH_FOREGROUNDIDLE: /* <-- SEH support */ case WH_KEYBOARD: case WH_SHELL: + Result = Common->Proc(Common->Code, Common->wParam, Common->lParam); + break; + case WH_FOREGROUNDIDLE: /* <-- SEH support */ _SEH2_TRY { Result = Common->Proc(Common->Code, Common->wParam, Common->lParam); diff --git a/reactos/include/reactos/win32k/callback.h b/reactos/include/reactos/win32k/callback.h index fc7c0bb95e2..76792380bd2 100644 --- a/reactos/include/reactos/win32k/callback.h +++ b/reactos/include/reactos/win32k/callback.h @@ -48,8 +48,6 @@ typedef struct _HOOKPROC_CALLBACK_ARGUMENTS LPARAM lParam; HOOKPROC Proc; BOOLEAN Ansi; - UINT ModuleNameLength; - WCHAR ModuleName[1]; } HOOKPROC_CALLBACK_ARGUMENTS, *PHOOKPROC_CALLBACK_ARGUMENTS; typedef struct _HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS diff --git a/reactos/subsystems/win32/win32k/main/dllmain.c b/reactos/subsystems/win32/win32k/main/dllmain.c index dd25b2efefe..42efcf9ea0e 100644 --- a/reactos/subsystems/win32/win32k/main/dllmain.c +++ b/reactos/subsystems/win32/win32k/main/dllmain.c @@ -252,17 +252,41 @@ Win32kThreadCallback(struct _ETHREAD *Thread, } } } + else + { + DPRINT1("No Desktop handle for this Thread!\n"); + } Win32Thread->TIF_flags &= ~TIF_INCLEANUP; co_IntDestroyCaret(Win32Thread); Win32Thread->ppi = PsGetCurrentProcessWin32Process(); - pTeb = NtCurrentTeb(); - if (pTeb) + if (Win32Thread->rpdesk && !Win32Thread->pDeskInfo) { - Win32Thread->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo; - Win32Thread->pClientInfo->pClientThreadInfo = NULL; + Win32Thread->pDeskInfo = Win32Thread->rpdesk->pDeskInfo; } Win32Thread->MessageQueue = MsqCreateMessageQueue(Thread); Win32Thread->KeyboardLayout = W32kGetDefaultKeyLayout(); + pTeb = NtCurrentTeb(); + if (pTeb) + { /* Attempt to startup client support which should have been initialized in IntSetThreadDesktop. */ + PCLIENTINFO pci = (PCLIENTINFO)pTeb->Win32ClientInfo; + Win32Thread->pClientInfo = pci; + pci->pClientThreadInfo = NULL; + pci->ppi = Win32Thread->ppi; + pci->fsHooks = Win32Thread->fsHooks; + if (Win32Thread->KeyboardLayout) pci->hKL = Win32Thread->KeyboardLayout->hkl; + pci->dwTIFlags = Win32Thread->TIF_flags; + /* CI may not have been initialized. */ + if (!pci->pDeskInfo && Win32Thread->pDeskInfo) + { + if (!pci->ulClientDelta) pci->ulClientDelta = DesktopHeapGetUserDelta(); + + pci->pDeskInfo = (PVOID)((ULONG_PTR)Win32Thread->pDeskInfo - pci->ulClientDelta); + } + } + else + { + DPRINT1("No TEB for this Thread!\n"); + } Win32Thread->pEThread = Thread; } else diff --git a/reactos/subsystems/win32/win32k/ntuser/callback.c b/reactos/subsystems/win32/win32k/ntuser/callback.c index 2b4f2409a8b..b683edd27b7 100644 --- a/reactos/subsystems/win32/win32k/ntuser/callback.c +++ b/reactos/subsystems/win32/win32k/ntuser/callback.c @@ -335,6 +335,7 @@ co_IntCallHookProc(INT HookId, PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra = NULL; PTHREADINFO pti; PWND pWnd; + PMSG pMsg = NULL; BOOL Hit = FALSE; ASSERT(Proc); @@ -346,8 +347,8 @@ co_IntCallHookProc(INT HookId, return 0; } - ArgumentLength = sizeof(HOOKPROC_CALLBACK_ARGUMENTS) - sizeof(WCHAR) - + ModuleName->Length; + ArgumentLength = sizeof(HOOKPROC_CALLBACK_ARGUMENTS); + switch(HookId) { case WH_CBT: @@ -360,6 +361,7 @@ co_IntCallHookProc(INT HookId, DPRINT1("WH_CBT HCBT_CREATEWND wParam bad hWnd!\n"); goto Fault_Exit; } + DPRINT1("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 @@ -432,24 +434,20 @@ co_IntCallHookProc(INT HookId, Common->lParam = lParam; Common->Proc = Proc; Common->Ansi = Ansi; - Common->ModuleNameLength = ModuleName->Length; - if (ModuleName->Buffer) - RtlCopyMemory(Common->ModuleName, ModuleName->Buffer, ModuleName->Length); - Extra = (PCHAR) Common->ModuleName + Common->ModuleNameLength; + 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: - Common->lParam = (LPARAM) (Extra - (PCHAR) Common); CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS) Extra; RtlCopyMemory( &CbtCreatewndExtra->Cs, CbtCreateWnd->lpcs, sizeof(CREATESTRUCTW) ); CbtCreatewndExtra->WndInsertAfter = CbtCreateWnd->hwndInsertAfter; - CbtCreatewndExtra->Cs.lpszClass = CbtCreateWnd->lpcs->lpszClass; // if Atom + CbtCreatewndExtra->Cs.lpszClass = CbtCreateWnd->lpcs->lpszClass; CbtCreatewndExtra->Cs.lpszName = CbtCreateWnd->lpcs->lpszName; - Extra = (PCHAR) (CbtCreatewndExtra + 1); + Common->lParam = (LPARAM) (Extra - (PCHAR) Common); break; case HCBT_CLICKSKIPPED: RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MOUSEHOOKSTRUCT)); @@ -488,7 +486,8 @@ co_IntCallHookProc(INT HookId, case WH_MSGFILTER: case WH_SYSMSGFILTER: case WH_GETMESSAGE: - RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSG)); + pMsg = (PMSG)lParam; + RtlCopyMemory(Extra, (PVOID) pMsg, sizeof(MSG)); Common->lParam = (LPARAM) (Extra - (PCHAR) Common); break; case WH_FOREGROUNDIDLE: @@ -548,9 +547,9 @@ co_IntCallHookProc(INT HookId, break; // "The GetMsgProc hook procedure can examine or modify the message." case WH_GETMESSAGE: - if (lParam) + if (pMsg) { - RtlCopyMemory((PVOID) lParam, Extra, sizeof(MSG)); + RtlCopyMemory((PVOID) pMsg, Extra, sizeof(MSG)); } break; } diff --git a/reactos/subsystems/win32/win32k/ntuser/desktop.c b/reactos/subsystems/win32/win32k/ntuser/desktop.c index 673fd452ae0..91b5a53224a 100644 --- a/reactos/subsystems/win32/win32k/ntuser/desktop.c +++ b/reactos/subsystems/win32/win32k/ntuser/desktop.c @@ -880,14 +880,24 @@ NtUserCreateDesktop( PUNICODE_STRING lpszDesktopName = NULL; UNICODE_STRING ClassName, MenuName; LARGE_STRING WindowName; + BOOL NoHooks = FALSE; PWND pWnd = NULL; CREATESTRUCTW Cs; INT i; + PTHREADINFO ptiCurrent; DECLARE_RETURN(HDESK); DPRINT("Enter NtUserCreateDesktop: %wZ\n", lpszDesktopName); UserEnterExclusive(); + ptiCurrent = PsGetCurrentThreadWin32Thread(); + if (ptiCurrent) + { + /* Turn off hooks when calling any CreateWindowEx from inside win32k. */ + NoHooks = (ptiCurrent->TIF_flags & TIF_DISABLEHOOKS); + ptiCurrent->TIF_flags |= TIF_DISABLEHOOKS; + } + _SEH2_TRY { ProbeForRead( poa, @@ -1102,6 +1112,7 @@ NtUserCreateDesktop( RETURN( Desktop); CLEANUP: + if (!NoHooks && ptiCurrent) ptiCurrent->TIF_flags &= ~TIF_DISABLEHOOKS; DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; diff --git a/reactos/subsystems/win32/win32k/ntuser/hook.c b/reactos/subsystems/win32/win32k/ntuser/hook.c index 810a7dfd759..4baee93a476 100644 --- a/reactos/subsystems/win32/win32k/ntuser/hook.c +++ b/reactos/subsystems/win32/win32k/ntuser/hook.c @@ -21,6 +21,7 @@ typedef struct _HOOKPACK { PHOOK pHk; LPARAM lParam; + PVOID pHookStructs; } HOOKPACK, *PHOOKPACK; /* PRIVATE FUNCTIONS *********************************************************/ @@ -36,6 +37,7 @@ IntCallLowLevelHook( PHOOK Hook, NTSTATUS Status; PTHREADINFO pti; PHOOKPACK pHP; + INT Size; ULONG_PTR uResult = 0; if (Hook->Thread) @@ -48,6 +50,56 @@ IntCallLowLevelHook( PHOOK Hook, pHP->pHk = Hook; pHP->lParam = lParam; + pHP->pHookStructs = NULL; + Size = 0; + +// Once the rest is enabled again, This prevents stack corruption from the caller. + switch(Hook->HookId) + { + case WH_CBT: + switch(Code) + { + case HCBT_CREATEWND: + Size = sizeof(CBT_CREATEWNDW); + break; + case HCBT_MOVESIZE: + Size = sizeof(RECTL); + break; + case HCBT_ACTIVATE: + Size = sizeof(CBTACTIVATESTRUCT); + break; + case HCBT_CLICKSKIPPED: + Size = sizeof(MOUSEHOOKSTRUCT); + break; + } + break; + case WH_KEYBOARD_LL: + Size = sizeof(KBDLLHOOKSTRUCT); + break; + case WH_MOUSE_LL: + Size = sizeof(MSLLHOOKSTRUCT); + break; + case WH_MOUSE: + Size = sizeof(MOUSEHOOKSTRUCT); + break; + case WH_CALLWNDPROC: + Size = sizeof(CWPSTRUCT); + break; + case WH_CALLWNDPROCRET: + Size = sizeof(CWPRETSTRUCT); + break; + case WH_MSGFILTER: + case WH_SYSMSGFILTER: + case WH_GETMESSAGE: + Size = sizeof(MSG); + break; + } + + if (Size) + { + pHP->pHookStructs = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_HOOK); + if (pHP->pHookStructs) RtlCopyMemory(pHP->pHookStructs, (PVOID)lParam, Size); + } /* FIXME should get timeout from * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */ @@ -63,11 +115,70 @@ IntCallLowLevelHook( PHOOK Hook, if (!NT_SUCCESS(Status)) { DPRINT1("Error Hook Call SendMsg. %d Status: 0x%x\n", Hook->HookId, Status); + if (pHP->pHookStructs) ExFreePoolWithTag(pHP->pHookStructs, TAG_HOOK); ExFreePoolWithTag(pHP, TAG_HOOK); } return NT_SUCCESS(Status) ? uResult : 0; } + +// +// Dispatch MsgQueue Hook Call processor! +// +LRESULT +FASTCALL +co_CallHook( INT HookId, + INT Code, + WPARAM wParam, + LPARAM lParam) +{ + LRESULT Result; + PHOOK phk; + PHOOKPACK pHP = (PHOOKPACK)lParam; + + phk = pHP->pHk; + lParam = pHP->lParam; + + switch(HookId) + { + case WH_CBT: + switch(Code) + { + case HCBT_CREATEWND: + case HCBT_MOVESIZE: + case HCBT_ACTIVATE: + case HCBT_CLICKSKIPPED: + lParam = (LPARAM)pHP->pHookStructs; + break; + } + break; + case WH_KEYBOARD_LL: + case WH_MOUSE_LL: + case WH_MOUSE: + case WH_CALLWNDPROC: + case WH_CALLWNDPROCRET: + case WH_MSGFILTER: + case WH_SYSMSGFILTER: + case WH_GETMESSAGE: + lParam = (LPARAM)pHP->pHookStructs; + break; + } + + /* The odds are high for this to be a Global call. */ + Result = co_IntCallHookProc( HookId, + Code, + wParam, + lParam, + phk->Proc, + 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); + return Result; +} + static LRESULT FASTCALL @@ -93,34 +204,6 @@ co_HOOK_CallHookNext( PHOOK Hook, &Hook->ModuleName); } -// -// Dispatch MsgQueue Hook Call processor! -// -LRESULT -FASTCALL -co_CallHook( INT HookId, - INT Code, - WPARAM wParam, - LPARAM lParam) -{ - LRESULT Result; - PHOOK phk; - PHOOKPACK pHP = (PHOOKPACK)lParam; - - phk = pHP->pHk; - /* The odds are high for this to be a Global call. */ - Result = co_IntCallHookProc( HookId, - Code, - wParam, - pHP->lParam, - phk->Proc, - phk->Ansi, - &phk->ModuleName); - - ExFreePoolWithTag(pHP, TAG_HOOK); - return Result; -} - LRESULT FASTCALL IntCallDebugHook( PHOOK Hook, @@ -704,6 +787,20 @@ IntGetFirstHook(PLIST_ENTRY Table) return Elem == Table ? NULL : CONTAINING_RECORD(Elem, HOOK, Chain); } +static +PHOOK +FASTCALL +IntGetNextGlobalHook(PHOOK Hook, PDESKTOP pdo) +{ + int HookId = Hook->HookId; + PLIST_ENTRY Elem; + + Elem = Hook->Chain.Flink; + if (Elem != &pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]) + return CONTAINING_RECORD(Elem, HOOK, Chain); + return NULL; +} + /* find the next hook in the chain */ PHOOK FASTCALL @@ -724,10 +821,7 @@ IntGetNextHook(PHOOK Hook) else { pti = PsGetCurrentThreadWin32Thread(); - - Elem = Hook->Chain.Flink; - if (Elem != &pti->rpdesk->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]) - return CONTAINING_RECORD(Elem, HOOK, Chain); + return IntGetNextGlobalHook(Hook, pti->rpdesk); } return NULL; } @@ -756,6 +850,7 @@ IntRemoveHook(PHOOK Hook) { INT HookId; PTHREADINFO pti; + PDESKTOP pdo; HookId = Hook->HookId; @@ -783,13 +878,13 @@ IntRemoveHook(PHOOK Hook) { IntFreeHook( Hook); - pti = PsGetCurrentThreadWin32Thread(); + pdo = IntGetActiveDesktop(); - if ( pti->rpdesk && - pti->rpdesk->pDeskInfo && - IsListEmpty(&pti->rpdesk->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]) ) + if ( pdo && + pdo->pDeskInfo && + IsListEmpty(&pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]) ) { - pti->rpdesk->pDeskInfo->fsHooks &= ~HOOKID_TO_FLAG(HookId); + pdo->pDeskInfo->fsHooks &= ~HOOKID_TO_FLAG(HookId); return TRUE; } } @@ -808,13 +903,13 @@ HOOK_DestroyThreadHooks(PETHREAD Thread) pti = Thread->Tcb.Win32Thread; pdo = IntGetActiveDesktop(); -DPRINT1("DestroyThreadHooks 1\n"); + if (!pti || !pdo) { DPRINT1("Kill Thread Hooks pti 0x%x pdo 0x%x\n",pti,pdo); return; } - ObReferenceObject(pti->pEThread); + ObReferenceObject(Thread); // Local Thread cleanup. if (pti->fsHooks) @@ -838,7 +933,6 @@ DPRINT1("DestroyThreadHooks 1\n"); } pti->fsHooks = 0; } -DPRINT1("DestroyThreadHooks 2\n"); // Global search based on Thread and cleanup. if (pdo->pDeskInfo->fsHooks) { @@ -854,7 +948,7 @@ DPRINT1("DestroyThreadHooks 2\n"); { if (!HookObj) break; if (HookObj->head.pti == pti) - { DPRINT1("Global Hook Removed\n"); + { if (IntRemoveHook(HookObj)) break; } pElem = HookObj->Chain.Flink; @@ -863,8 +957,7 @@ DPRINT1("DestroyThreadHooks 2\n"); while (pElem != pGLE); } } - ObDereferenceObject(pti->pEThread); -DPRINT1("DestroyThreadHooks 3\n"); + ObDereferenceObject(Thread); return; } @@ -882,6 +975,7 @@ co_HOOK_CallHooks( INT HookId, PTHREADINFO pti; PCLIENTINFO ClientInfo; PLIST_ENTRY pLLE, pGLE; + PDESKTOP pdo; BOOL Local = FALSE, Global = FALSE; LRESULT Result = 0; @@ -889,9 +983,20 @@ co_HOOK_CallHooks( INT HookId, pti = PsGetCurrentThreadWin32Thread(); if (!pti || !pti->rpdesk || !pti->rpdesk->pDeskInfo) - goto Exit; // Must have a desktop running for hooks. + { + pdo = IntGetActiveDesktop(); + /* If KeyboardThread|MouseThread|(RawInputThread or RIT) aka system threads, + pti->fsHooks most likely, is zero. So process KbT & MsT to "send" the message. + */ + if ( !pti || !pdo || (!(HookId == WH_KEYBOARD_LL) && !(HookId == WH_MOUSE_LL)) ) + goto Exit; + } + else + { + pdo = pti->rpdesk; + } - if ( pti->TIF_flags & TIF_INCLEANUP) + if ( pti->TIF_flags & (TIF_INCLEANUP|TIF_DISABLEHOOKS)) goto Exit; if ( ISITHOOKED(HookId) ) @@ -900,7 +1005,7 @@ co_HOOK_CallHooks( INT HookId, Local = TRUE; } - if ( pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(HookId) ) + if ( pdo->pDeskInfo->fsHooks & HOOKID_TO_FLAG(HookId) ) { DPRINT("Global Hooker %d\n", HookId); Global = TRUE; @@ -908,8 +1013,6 @@ co_HOOK_CallHooks( INT HookId, if ( !Local && !Global ) goto Exit; // No work! - pLLE = &pti->aphkStart[HOOKID_TO_INDEX(HookId)]; - pGLE = &pti->rpdesk->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]; Hook = NULL; /* SetWindowHookEx sorts out the Thread issue by placing the Hook to @@ -917,6 +1020,7 @@ co_HOOK_CallHooks( INT HookId, */ if ( Local ) { + pLLE = &pti->aphkStart[HOOKID_TO_INDEX(HookId)]; Hook = IntGetFirstHook(pLLE); if (!Hook) { @@ -970,6 +1074,7 @@ co_HOOK_CallHooks( INT HookId, { PTHREADINFO ptiHook; + pGLE = &pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]; Hook = IntGetFirstHook(pGLE); if (!Hook) { @@ -988,10 +1093,11 @@ co_HOOK_CallHooks( INT HookId, /* "Global hook monitors messages for all threads in the same desktop * as the calling thread." */ - if ( ptiHook->TIF_flags & TIF_INCLEANUP || - ptiHook->rpdesk != pti->rpdesk) + if ( ptiHook->TIF_flags & (TIF_INCLEANUP|TIF_DISABLEHOOKS) || + ptiHook->rpdesk != pdo) { - Hook = IntGetNextHook(Hook); + DPRINT("Next Hook 0x%x, 0x%x\n",ptiHook->rpdesk,pdo); + Hook = IntGetNextGlobalHook(Hook, pdo); if (!Hook) break; continue; } @@ -999,8 +1105,14 @@ co_HOOK_CallHooks( INT HookId, ObReferenceObject(ptiHook->pEThread); if (ptiHook != pti ) { - DPRINT("\nGlobal Hook posting to another Thread! %d\n",HookId ); - Result = IntCallLowLevelHook(Hook, Code, wParam, lParam); + /* This fixed the ros regtest. Wine does this too. Need more time + to investigate this. MSDN "Hooks Overview" can't be wrong? + */ + if (HookId == WH_KEYBOARD_LL || HookId == WH_MOUSE_LL) + { + DPRINT("\nGlobal Hook posting to another Thread! %d\n",HookId ); + Result = IntCallLowLevelHook(Hook, Code, wParam, lParam); + } } else { /* Make the direct call. */ @@ -1014,7 +1126,7 @@ co_HOOK_CallHooks( INT HookId, &Hook->ModuleName); } ObDereferenceObject(ptiHook->pEThread); - Hook = IntGetNextHook(Hook); + Hook = IntGetNextGlobalHook(Hook, pdo); } while ( Hook ); DPRINT("Ret: Global HookId %d Result 0x%x\n", HookId,Result); @@ -1248,7 +1360,7 @@ NtUserSetWindowsHookEx( HINSTANCE Mod, } } else /* system-global hook */ - { + { pti = ptiCurrent; // gptiCurrent; if ( !Mod && (HookId == WH_GETMESSAGE || @@ -1294,6 +1406,8 @@ NtUserSetWindowsHookEx( HINSTANCE Mod, Hook->Proc = HookProc; Hook->Ansi = Ansi; + DPRINT1("Set Hook Desk 0x%x DeskInfo 0x%x Handle Desk 0x%x\n",pti->rpdesk, pti->pDeskInfo,Hook->head.rpdesk); + if (ThreadId) /* thread-local hook */ { InsertHeadList(&pti->aphkStart[HOOKID_TO_INDEX(HookId)], &Hook->Chain); @@ -1343,10 +1457,10 @@ NtUserSetWindowsHookEx( HINSTANCE Mod, } else { - InsertHeadList(&pti->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)], &Hook->Chain); + InsertHeadList(&pti->rpdesk->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)], &Hook->Chain); Hook->ptiHooked = NULL; //gptiCurrent->pDeskInfo->fsHooks |= HOOKID_TO_FLAG(HookId); - pti->pDeskInfo->fsHooks |= HOOKID_TO_FLAG(HookId); + pti->rpdesk->pDeskInfo->fsHooks |= HOOKID_TO_FLAG(HookId); } RtlInitUnicodeString(&Hook->ModuleName, NULL); @@ -1393,7 +1507,7 @@ NtUserSetWindowsHookEx( HINSTANCE Mod, else Hook->offPfn = 0; - DPRINT1("Installing: HookId %d Global %s\n", HookId, !ThreadId ? "TRUE" : "FALSE"); + DPRINT("Installing: HookId %d Global %s\n", HookId, !ThreadId ? "TRUE" : "FALSE"); RETURN( Handle); CLEANUP: diff --git a/reactos/subsystems/win32/win32k/ntuser/input.c b/reactos/subsystems/win32/win32k/ntuser/input.c index 8919d57d6ad..4014e4edee9 100644 --- a/reactos/subsystems/win32/win32k/ntuser/input.c +++ b/reactos/subsystems/win32/win32k/ntuser/input.c @@ -22,6 +22,8 @@ extern NTSTATUS Win32kInitWin32Thread(PETHREAD Thread); /* GLOBALS *******************************************************************/ PTHREADINFO ptiRawInput; +PTHREADINFO ptiKeyboard; +PTHREADINFO ptiMouse; PKTIMER MasterTimer = NULL; PATTACHINFO gpai = NULL; @@ -234,6 +236,18 @@ MouseThreadMain(PVOID StartContext) FILE_SYNCHRONOUS_IO_ALERT); } while (!NT_SUCCESS(Status)); + /* Need to setup basic win32k for this thread to process WH_MOUSE_LL messages. */ + Status = Win32kInitWin32Thread(PsGetCurrentThread()); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Win32K: Failed making mouse thread a win32 thread.\n"); + return; //(Status); + } + + ptiMouse = PsGetCurrentThreadWin32Thread(); + ptiMouse->TIF_flags |= TIF_SYSTEMTHREAD; + DPRINT1("\nMouse Thread 0x%x \n", ptiMouse); + KeSetPriorityThread(&PsGetCurrentThread()->Tcb, LOW_REALTIME_PRIORITY + 3); @@ -530,6 +544,10 @@ KeyboardThreadMain(PVOID StartContext) return; //(Status); } + ptiKeyboard = PsGetCurrentThreadWin32Thread(); + ptiKeyboard->TIF_flags |= TIF_SYSTEMTHREAD; + DPRINT1("\nKeyboard Thread 0x%x \n", ptiKeyboard); + KeSetPriorityThread(&PsGetCurrentThread()->Tcb, LOW_REALTIME_PRIORITY + 3); @@ -890,8 +908,8 @@ RawInputThreadMain(PVOID StartContext) } ptiRawInput = PsGetCurrentThreadWin32Thread(); - DPRINT("\nRaw Input Thread 0x%x \n", ptiRawInput); - + ptiRawInput->TIF_flags |= TIF_SYSTEMTHREAD; + DPRINT1("\nRaw Input Thread 0x%x \n", ptiRawInput); KeSetPriorityThread(&PsGetCurrentThread()->Tcb, LOW_REALTIME_PRIORITY + 3); diff --git a/reactos/subsystems/win32/win32k/ntuser/window.c b/reactos/subsystems/win32/win32k/ntuser/window.c index e81ab4baef9..4233818e00d 100644 --- a/reactos/subsystems/win32/win32k/ntuser/window.c +++ b/reactos/subsystems/win32/win32k/ntuser/window.c @@ -1910,9 +1910,9 @@ co_UserCreateWindowEx(CREATESTRUCTW* Cs, LRESULT Result; USER_REFERENCE_ENTRY ParentRef, Ref; PTHREADINFO pti; - ANSI_STRING asClassName; DWORD dwShowMode = SW_SHOW; CREATESTRUCTW *pCsw; + PVOID pszClass = NULL, pszName = NULL; DECLARE_RETURN(PWND); /* Get the current window station and reference it */ @@ -1927,7 +1927,6 @@ co_UserCreateWindowEx(CREATESTRUCTW* Cs, pCsw = NULL; pCbtCreate = NULL; - RtlInitAnsiString(&asClassName, NULL); /* Get the class and reference it*/ Class = IntGetAndReferenceClass(ClassName, Cs->hInstance); @@ -2008,17 +2007,58 @@ co_UserCreateWindowEx(CREATESTRUCTW* Cs, pCsw->dwExStyle = Cs->dwExStyle; dwStyle = Cs->style; // Save it anyway. pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */ + pCsw->lpszName = Cs->lpszName; + pCsw->lpszClass = Cs->lpszClass; - pCsw->lpszName = (LPCWSTR) WindowName->Buffer; - pCsw->lpszClass = (LPCWSTR) ClassName->Buffer; - - if (Window->state & WNDS_ANSICREATOR) + // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes. + if (!IS_ATOM(ClassName->Buffer)) { - if (!IS_ATOM(ClassName->Buffer)) + if (Window->state & WNDS_ANSICREATOR) { - RtlUnicodeStringToAnsiString(&asClassName, ClassName, TRUE); - pCsw->lpszClass = (LPCWSTR) asClassName.Buffer; + ANSI_STRING AnsiString; + AnsiString.MaximumLength = RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR); + pszClass = UserHeapAlloc(AnsiString.MaximumLength); + RtlZeroMemory(pszClass, AnsiString.MaximumLength); + AnsiString.Buffer = (PCHAR)pszClass; + RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE); } + else + { + UNICODE_STRING UnicodeString; + UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL); + pszClass = UserHeapAlloc(UnicodeString.MaximumLength); + RtlZeroMemory(pszClass, UnicodeString.MaximumLength); + UnicodeString.Buffer = (PWSTR)pszClass; + RtlCopyUnicodeString(&UnicodeString, ClassName); + } + if (pszClass) pCsw->lpszClass = UserHeapAddressToUser(pszClass); + } + if (WindowName->Length) + { + UNICODE_STRING Name; + Name.Buffer = WindowName->Buffer; + Name.Length = WindowName->Length; + Name.MaximumLength = WindowName->MaximumLength; + + if (Window->state & WNDS_ANSICREATOR) + { + ANSI_STRING AnsiString; + AnsiString.MaximumLength = RtlUnicodeStringToAnsiSize(&Name)+sizeof(CHAR); + pszName = UserHeapAlloc(AnsiString.MaximumLength); + RtlZeroMemory(pszName, AnsiString.MaximumLength); + AnsiString.Buffer = (PCHAR)pszName; + RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE); + } + else + { + UNICODE_STRING UnicodeString; + UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL); + pszName = UserHeapAlloc(UnicodeString.MaximumLength); + RtlZeroMemory(pszName, UnicodeString.MaximumLength); + UnicodeString.Buffer = (PWSTR)pszName; + RtlCopyUnicodeString(&UnicodeString, &Name); + } + if (pszName) pCsw->lpszName = UserHeapAddressToUser(pszName); } pCbtCreate->lpcs = pCsw; @@ -2037,7 +2077,10 @@ co_UserCreateWindowEx(CREATESTRUCTW* Cs, Cs->y = pCsw->y; hwndInsertAfter = pCbtCreate->hwndInsertAfter; - Cs->style = dwStyle; /* NCCREATE and WM_NCCALCSIZE need the original values*/ + /* NCCREATE and WM_NCCALCSIZE need the original values */ + Cs->style = dwStyle; + Cs->lpszName = (LPCWSTR) WindowName; + Cs->lpszClass = (LPCWSTR) ClassName; /* Send the WM_GETMINMAXINFO message*/ Size.cx = Cs->cx; @@ -2187,7 +2230,8 @@ CLEANUP: if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK); if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK); - RtlFreeAnsiString(&asClassName); + if (pszName) UserHeapFree(pszName); + if (pszClass) UserHeapFree(pszClass); if (Window) { @@ -2337,10 +2381,11 @@ NtUserCreateWindowEx( Cs.cy = nHeight; Cs.x = x; Cs.y = y; -// Cs.lpszName = (LPCWSTR) WindowName->Buffer; -// Cs.lpszClass = (LPCWSTR) ClassName->Buffer; - Cs.lpszName = (LPCWSTR) plstrWindowName; - Cs.lpszClass = (LPCWSTR) &ustrClassName; + Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer; + if (IS_ATOM(plstrClassName)) + Cs.lpszClass = (LPCWSTR) plstrClassName; + else + Cs.lpszClass = (LPCWSTR) plstrClassName->Buffer; Cs.dwExStyle = dwExStyle; UserEnterExclusive();