tinus o112w8r02@sneakemail.com: Implement RegisterShellHookWindow Modified: trunk/reactos/include/win32k/ntuser.h Modified: trunk/reactos/lib/user32/windows/hook.c Modified: trunk/reactos/ntoskrnl/include/internal/ex.h Modified: trunk/reactos/subsys/win32k/include/desktop.h Modified: trunk/reactos/subsys/win32k/include/window.h Modified: trunk/reactos/subsys/win32k/ntuser/class.c Modified: trunk/reactos/subsys/win32k/ntuser/desktop.c Modified: trunk/reactos/subsys/win32k/ntuser/focus.c Modified: trunk/reactos/subsys/win32k/ntuser/stubs.c Modified: trunk/reactos/subsys/win32k/ntuser/window.c _____
Modified: trunk/reactos/include/win32k/ntuser.h --- trunk/reactos/include/win32k/ntuser.h 2005-03-13 23:03:31 UTC (rev 14040) +++ trunk/reactos/include/win32k/ntuser.h 2005-03-13 23:08:51 UTC (rev 14041) @@ -103,6 +103,11 @@
DWORD BufferSize, DWORD *Count);
+enum { + HWND_ROUTINE_REGISTERSHELLHOOKWINDOW, + HWND_ROUTINE_DEREGISTERSHELLHOOKWINDOW +}; + DWORD STDCALL NtUserCallHwnd( _____
Modified: trunk/reactos/lib/user32/windows/hook.c --- trunk/reactos/lib/user32/windows/hook.c 2005-03-13 23:03:31 UTC (rev 14040) +++ trunk/reactos/lib/user32/windows/hook.c 2005-03-13 23:08:51 UTC (rev 14041) @@ -156,8 +156,7 @@
STDCALL DeregisterShellHookWindow(HWND hWnd) { - UNIMPLEMENTED; - return FALSE; + return NtUserCallHwnd(HWND_ROUTINE_DEREGISTERSHELLHOOKWINDOW, (DWORD)hWnd); }
/* @@ -167,8 +166,7 @@ STDCALL RegisterShellHookWindow(HWND hWnd) { - UNIMPLEMENTED; - return FALSE; + return NtUserCallHwnd(HWND_ROUTINE_REGISTERSHELLHOOKWINDOW, (DWORD)hWnd); }
/* _____
Modified: trunk/reactos/ntoskrnl/include/internal/ex.h --- trunk/reactos/ntoskrnl/include/internal/ex.h 2005-03-13 23:03:31 UTC (rev 14040) +++ trunk/reactos/ntoskrnl/include/internal/ex.h 2005-03-13 23:08:51 UTC (rev 14041) @@ -68,6 +68,8 @@
HANDLE PrevActiveWindow; /* Thread blocking input */ PVOID BlockInputThread; + + LIST_ENTRY ShellHookWindows; } DESKTOP_OBJECT, *PDESKTOP_OBJECT;
_____
Modified: trunk/reactos/subsys/win32k/include/desktop.h --- trunk/reactos/subsys/win32k/include/desktop.h 2005-03-13 23:03:31 UTC (rev 14040) +++ trunk/reactos/subsys/win32k/include/desktop.h 2005-03-13 23:08:51 UTC (rev 14041) @@ -14,6 +14,12 @@
extern HDC ScreenDeviceContext; extern BOOL g_PaintDesktopVersion;
+typedef struct _SHELL_HOOK_WINDOW +{ + LIST_ENTRY ListEntry; + HWND hWnd; +} SHELL_HOOK_WINDOW, *PSHELL_HOOK_WINDOW; + NTSTATUS FASTCALL InitDesktopImpl(VOID);
@@ -79,6 +85,11 @@ BOOL FASTCALL IntDesktopUpdatePerUserSettings(BOOL bEnable);
+BOOL IntRegisterShellHookWindow(HWND hWnd); +BOOL IntDeRegisterShellHookWindow(HWND hWnd); + +VOID IntShellHookNotify(WPARAM Message, LPARAM lParam); + #define IntIsActiveDesktop(Desktop) \ ((Desktop)->WindowStation->ActiveDesktop == (Desktop))
_____
Modified: trunk/reactos/subsys/win32k/include/window.h --- trunk/reactos/subsys/win32k/include/window.h 2005-03-13 23:03:31 UTC (rev 14040) +++ trunk/reactos/subsys/win32k/include/window.h 2005-03-13 23:08:51 UTC (rev 14041) @@ -200,6 +200,9 @@
IntGetParent(PWINDOW_OBJECT Wnd);
PWINDOW_OBJECT FASTCALL +IntGetOwner(PWINDOW_OBJECT Wnd); + +PWINDOW_OBJECT FASTCALL IntGetParentObject(PWINDOW_OBJECT Wnd);
INT FASTCALL _____
Modified: trunk/reactos/subsys/win32k/ntuser/class.c --- trunk/reactos/subsys/win32k/ntuser/class.c 2005-03-13 23:03:31 UTC (rev 14040) +++ trunk/reactos/subsys/win32k/ntuser/class.c 2005-03-13 23:08:51 UTC (rev 14041) @@ -534,6 +534,8 @@
void FASTCALL IntSetClassLong(PWINDOW_OBJECT WindowObject, ULONG Offset, LONG dwNewLong, BOOL Ansi) { + PWINDOW_OBJECT Parent, Owner; + if ((int)Offset >= 0) { DPRINT("SetClassLong(%x, %d, %x)\n", WindowObject->Self, Offset, dwNewLong); @@ -562,6 +564,25 @@ break; case GCL_HICON: WindowObject->Class->hIcon = (HICON)dwNewLong; + Owner = IntGetOwner(WindowObject); + Parent = IntGetParent(WindowObject); + + if ((!Owner) && (!Parent)) + { + IntShellHookNotify(HSHELL_REDRAW, (LPARAM) WindowObject->Self); + } + + if (Parent) + { + IntReleaseWindowObject(Parent); + } + + if (Owner) + { + IntReleaseWindowObject(Owner); + } + + break; case GCL_HICONSM: WindowObject->Class->hIconSm = (HICON)dwNewLong; _____
Modified: trunk/reactos/subsys/win32k/ntuser/desktop.c --- trunk/reactos/subsys/win32k/ntuser/desktop.c 2005-03-13 23:03:31 UTC (rev 14040) +++ trunk/reactos/subsys/win32k/ntuser/desktop.c 2005-03-13 23:08:51 UTC (rev 14041) @@ -92,6 +92,7 @@
DPRINT("Creating desktop (0x%X) Name (%wZ)\n", Desktop, &UnicodeString);
KeInitializeSpinLock(&Desktop->Lock); + InitializeListHead(&Desktop->ShellHookWindows);
Desktop->WindowStation = (PWINSTATION_OBJECT)Parent;
@@ -541,6 +542,147 @@ }
/* + * Send the Message to the windows registered for ShellHook + * notifications. The lParam contents depend on the Message. See + * MSDN for more details (RegisterShellHookWindow) + */ +VOID IntShellHookNotify(WPARAM Message, LPARAM lParam) +{ + PDESKTOP_OBJECT Desktop = IntGetActiveDesktop(); + PLIST_ENTRY Entry, Entry2; + PSHELL_HOOK_WINDOW Current; + KIRQL OldLevel; + + static UINT MsgType = 0; + + if (!MsgType) { + + /* Too bad, this doesn't work.*/ +#if 0 + UNICODE_STRING Str; + RtlInitUnicodeString(&Str, L"SHELLHOOK"); + MsgType = NtUserRegisterWindowMessage(&Str); +#endif + MsgType = IntAddAtom(L"SHELLHOOK"); + + DPRINT("MsgType = %x\n", MsgType); + if (!MsgType) + DPRINT1("LastError: %x\n", GetLastNtError()); + } + + if (!Desktop) { + DPRINT1("IntShellHookNotify: No desktop!\n"); + return; + } + + /* We have to do some tricks because the list could change + * between calls, and we can't keep the lock during the call + */ + + KeAcquireSpinLock(&Desktop->Lock, &OldLevel); + Entry = Desktop->ShellHookWindows.Flink; + while (Entry != &Desktop->ShellHookWindows) { + Current = CONTAINING_RECORD(Entry, SHELL_HOOK_WINDOW, ListEntry); + KeReleaseSpinLock(&Desktop->Lock, OldLevel); + + DPRINT("Sending notify\n"); + IntPostOrSendMessage(Current->hWnd, + MsgType, + Message, + lParam); + + /* Loop again to find the window we were sending to. If it doesn't + * exist anymore, we just stop. This could leave an infinite loop + * if a window is removed and readded to the list. That's quite + * unlikely though. + */ + + KeAcquireSpinLock(&Desktop->Lock, &OldLevel); + Entry2 = Desktop->ShellHookWindows.Flink; + while (Entry2 != Entry && + Entry2 != &Desktop->ShellHookWindows) { + Entry2 = Entry2->Flink; + } + + if (Entry2 == Entry) + Entry = Entry->Flink; + else + break; + } + KeReleaseSpinLock(&Desktop->Lock, OldLevel); +} + +/* + * Add the window to the ShellHookWindows list. The windows + * on that list get notifications that are important to shell + * type applications. + * + * TODO: Validate the window? I'm not sure if sending these messages to + * an unsuspecting application that is not your own is a nice thing to do. + */ +BOOL IntRegisterShellHookWindow(HWND hWnd) +{ + PDESKTOP_OBJECT Desktop = PsGetWin32Thread()->Desktop; + PSHELL_HOOK_WINDOW Entry; + KIRQL OldLevel; + + DPRINT("IntRegisterShellHookWindow\n"); + + /* First deregister the window, so we can be sure it's never twice in the + * list. + */ + IntDeRegisterShellHookWindow(hWnd); + + Entry = ExAllocatePoolWithTag(NonPagedPool, + sizeof(SHELL_HOOK_WINDOW), + TAG_WINSTA); + /* We have to walk this structure with while holding a spinlock, so we + * need NonPagedPool */ + + if (!Entry) + return FALSE; + + Entry->hWnd = hWnd; + + KeAcquireSpinLock(&Desktop->Lock, &OldLevel); + InsertTailList(&Desktop->ShellHookWindows, &Entry->ListEntry); + KeReleaseSpinLock(&Desktop->Lock, OldLevel); + + return TRUE; +} + +/* + * Remove the window from the ShellHookWindows list. The windows + * on that list get notifications that are important to shell + * type applications. + */ +BOOL IntDeRegisterShellHookWindow(HWND hWnd) +{ + PDESKTOP_OBJECT Desktop = PsGetWin32Thread()->Desktop; + PLIST_ENTRY Entry; + PSHELL_HOOK_WINDOW Current; + KIRQL OldLevel; + + KeAcquireSpinLock(&Desktop->Lock, &OldLevel); + + Entry = Desktop->ShellHookWindows.Flink; + while (Entry != &Desktop->ShellHookWindows) { + Current = CONTAINING_RECORD(Entry, SHELL_HOOK_WINDOW, ListEntry); + if (Current->hWnd == hWnd) { + RemoveEntryList(Entry); + KeReleaseSpinLock(&Desktop->Lock, OldLevel); + ExFreePool(Entry); + return TRUE; + } + Entry = Entry->Flink; + } + + KeReleaseSpinLock(&Desktop->Lock, OldLevel); + + return FALSE; +} + +/* * NtUserCreateDesktop * * Creates a new desktop. _____
Modified: trunk/reactos/subsys/win32k/ntuser/focus.c --- trunk/reactos/subsys/win32k/ntuser/focus.c 2005-03-13 23:03:31 UTC (rev 14040) +++ trunk/reactos/subsys/win32k/ntuser/focus.c 2005-03-13 23:08:51 UTC (rev 14041) @@ -62,6 +62,8 @@
VOID FASTCALL IntSendActivateMessages(HWND hWndPrev, HWND hWnd, BOOL MouseActivate) { + PWINDOW_OBJECT Window, Owner, Parent; + if (hWnd) { /* Send palette messages */ @@ -75,6 +77,22 @@ WinPosSetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
+ Window = IntGetWindowObject(hWnd); + if (Window) { + Owner = IntGetOwner(Window); + if (!Owner) { + Parent = IntGetParent(Window); + if (!Parent) + IntShellHookNotify(HSHELL_WINDOWACTIVATED, (LPARAM) hWnd); + else + IntReleaseWindowObject(Parent); + } else { + IntReleaseWindowObject(Owner); + } + + IntReleaseWindowObject(Window); + } + /* FIXME: IntIsWindow */
IntPostOrSendMessage(hWnd, WM_NCACTIVATE, (WPARAM)(hWnd == NtUserGetForegroundWindow()), 0); _____
Modified: trunk/reactos/subsys/win32k/ntuser/stubs.c --- trunk/reactos/subsys/win32k/ntuser/stubs.c 2005-03-13 23:03:31 UTC (rev 14040) +++ trunk/reactos/subsys/win32k/ntuser/stubs.c 2005-03-13 23:08:51 UTC (rev 14041) @@ -59,6 +59,17 @@
DWORD Unknown0, DWORD Unknown1) { + switch (Unknown0) { + case HWND_ROUTINE_REGISTERSHELLHOOKWINDOW: + if (IntIsWindow((HWND) Unknown1)) + return IntRegisterShellHookWindow((HWND) Unknown1); + return FALSE; + break; + case HWND_ROUTINE_DEREGISTERSHELLHOOKWINDOW: + if (IntIsWindow((HWND) Unknown1)) + return IntDeRegisterShellHookWindow((HWND) Unknown1); + return FALSE; + } UNIMPLEMENTED
return 0; _____
Modified: trunk/reactos/subsys/win32k/ntuser/window.c --- trunk/reactos/subsys/win32k/ntuser/window.c 2005-03-13 23:03:31 UTC (rev 14040) +++ trunk/reactos/subsys/win32k/ntuser/window.c 2005-03-13 23:08:51 UTC (rev 14041) @@ -147,7 +147,18 @@
return NULL; }
+PWINDOW_OBJECT FASTCALL +IntGetOwner(PWINDOW_OBJECT Wnd) +{ + HWND hWnd;
+ IntLockRelatives(Wnd); + hWnd = Wnd->Owner; + IntUnLockRelatives(Wnd); + + return IntGetWindowObject(hWnd); +} + PWINDOW_OBJECT FASTCALL IntGetParentObject(PWINDOW_OBJECT Wnd) { @@ -205,6 +216,8 @@ */ static void IntSendDestroyMsg(HWND Wnd) { + + PWINDOW_OBJECT Window, Owner, Parent; #if 0 /* FIXME */ GUITHREADINFO info;
@@ -217,9 +230,28 @@ } #endif
+ Window = IntGetWindowObject(Wnd); + if (Window) { + Owner = IntGetOwner(Window); + if (!Owner) { + Parent = IntGetParent(Window); + if (!Parent) + IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM) Wnd); + else + IntReleaseWindowObject(Parent); + } else { + IntReleaseWindowObject(Owner); + } + + IntReleaseWindowObject(Window); + } + + /* The window could already be destroyed here */ + /* * Send the WM_DESTROY to the window. */ + IntSendMessage(Wnd, WM_DESTROY, 0, 0);
/* @@ -284,6 +316,8 @@ IntUnLockThreadWindows(Window->OwnerThread->Tcb.Win32Thread);
BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData); + + IntDeRegisterShellHookWindow(Window->Self);
if(SendMessages) { @@ -1417,6 +1451,8 @@ BOOL MenuChanged; BOOL ClassFound;
+ BOOL HasOwner; + ParentWindowHandle = PsGetWin32Thread()->Desktop->DesktopWindow; OwnerWindowHandle = NULL;
@@ -1542,9 +1578,11 @@ { WindowObject->Owner = OwnerWindowHandle; IntReleaseWindowObject(OwnerWindow); + HasOwner = TRUE; + } else { + WindowObject->Owner = NULL; + HasOwner = FALSE; } - else - WindowObject->Owner = NULL; WindowObject->UserData = 0; if ((((DWORD)ClassObject->lpfnWndProcA & 0xFFFF0000) != 0xFFFF0000) && (((DWORD)ClassObject->lpfnWndProcW & 0xFFFF0000) != 0xFFFF0000)) @@ -1969,6 +2007,13 @@ (LPARAM)WindowObject->Self); }
+ if ((!hWndParent) && (!HasOwner)) { + DPRINT("Sending CREATED notify\n"); + IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)Handle); + } else { + DPRINT("Not sending CREATED notify, %x %d\n", ParentWindow, HasOwner); + } + if (NULL != ParentWindow) { IntReleaseWindowObject(ParentWindow); @@ -4060,7 +4105,7 @@ BOOL STDCALL NtUserDefSetText(HWND WindowHandle, PUNICODE_STRING WindowText) { - PWINDOW_OBJECT WindowObject; + PWINDOW_OBJECT WindowObject, Parent, Owner; UNICODE_STRING SafeText; NTSTATUS Status;
@@ -4090,6 +4135,26 @@ RtlFreeUnicodeString(&WindowObject->WindowName);
WindowObject->WindowName = SafeText; + + /* Send shell notifications */ + + Owner = IntGetOwner(WindowObject); + Parent = IntGetParent(WindowObject); + + if ((!Owner) && (!Parent)) + { + IntShellHookNotify(HSHELL_REDRAW, (LPARAM) WindowHandle); + } + + if (Owner) + { + IntReleaseWindowObject(Owner); + } + + if (Parent) + { + IntReleaseWindowObject(Parent); + }
IntReleaseWindowObject(WindowObject); return TRUE;