tinus <o112w8r02(a)sneakemail.com>om>:
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;