Implement RegisterShellHookWindow

svn path=/trunk/; revision=14041
This commit is contained in:
Gé van Geldorp
2005-03-13 23:08:51 +00:00
parent f1fa92f6fc
commit fa4bd57bed
10 changed files with 283 additions and 7 deletions
+5
View File
@@ -103,6 +103,11 @@ NtUserBuildPropList(
DWORD BufferSize,
DWORD *Count);
enum {
HWND_ROUTINE_REGISTERSHELLHOOKWINDOW,
HWND_ROUTINE_DEREGISTERSHELLHOOKWINDOW
};
DWORD
STDCALL
NtUserCallHwnd(
+2 -4
View File
@@ -156,8 +156,7 @@ BOOL
STDCALL
DeregisterShellHookWindow(HWND hWnd)
{
UNIMPLEMENTED;
return FALSE;
return NtUserCallHwnd(HWND_ROUTINE_DEREGISTERSHELLHOOKWINDOW, (DWORD)hWnd);
}
/*
@@ -167,8 +166,7 @@ BOOL
STDCALL
RegisterShellHookWindow(HWND hWnd)
{
UNIMPLEMENTED;
return FALSE;
return NtUserCallHwnd(HWND_ROUTINE_REGISTERSHELLHOOKWINDOW, (DWORD)hWnd);
}
/*
+2
View File
@@ -68,6 +68,8 @@ typedef struct _DESKTOP_OBJECT
HANDLE PrevActiveWindow;
/* Thread blocking input */
PVOID BlockInputThread;
LIST_ENTRY ShellHookWindows;
} DESKTOP_OBJECT, *PDESKTOP_OBJECT;
+11
View File
@@ -14,6 +14,12 @@ extern PWNDCLASS_OBJECT DesktopWindowClass;
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 @@ IntParseDesktopPath(PEPROCESS Process,
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))
+3
View File
@@ -199,6 +199,9 @@ IntGetAncestor(PWINDOW_OBJECT Wnd, UINT Type);
PWINDOW_OBJECT FASTCALL
IntGetParent(PWINDOW_OBJECT Wnd);
PWINDOW_OBJECT FASTCALL
IntGetOwner(PWINDOW_OBJECT Wnd);
PWINDOW_OBJECT FASTCALL
IntGetParentObject(PWINDOW_OBJECT Wnd);
+21
View File
@@ -534,6 +534,8 @@ NtUserGetClassLong(HWND hWnd, DWORD Offset, BOOL Ansi)
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 @@ IntSetClassLong(PWINDOW_OBJECT WindowObject, ULONG Offset, LONG dwNewLong, BOOL
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;
+142
View File
@@ -92,6 +92,7 @@ IntDesktopObjectCreate(PVOID ObjectBody,
DPRINT("Creating desktop (0x%X) Name (%wZ)\n", Desktop, &UnicodeString);
KeInitializeSpinLock(&Desktop->Lock);
InitializeListHead(&Desktop->ShellHookWindows);
Desktop->WindowStation = (PWINSTATION_OBJECT)Parent;
@@ -540,6 +541,147 @@ IntHideDesktop(PDESKTOP_OBJECT Desktop)
#endif
}
/*
* 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
*
+18
View File
@@ -62,6 +62,8 @@ IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd)
VOID FASTCALL
IntSendActivateMessages(HWND hWndPrev, HWND hWnd, BOOL MouseActivate)
{
PWINDOW_OBJECT Window, Owner, Parent;
if (hWnd)
{
/* Send palette messages */
@@ -75,6 +77,22 @@ IntSendActivateMessages(HWND hWndPrev, HWND hWnd, BOOL MouseActivate)
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);
+11
View File
@@ -59,6 +59,17 @@ NtUserCallHwnd(
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;
+68 -3
View File
@@ -147,6 +147,17 @@ IntGetParent(PWINDOW_OBJECT Wnd)
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 @@ IntWinListChildren(PWINDOW_OBJECT Window)
*/
static void IntSendDestroyMsg(HWND Wnd)
{
PWINDOW_OBJECT Window, Owner, Parent;
#if 0 /* FIXME */
GUITHREADINFO info;
@@ -217,9 +230,28 @@ static void IntSendDestroyMsg(HWND Wnd)
}
#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 @@ static LRESULT IntDestroyWindow(PWINDOW_OBJECT Window,
IntUnLockThreadWindows(Window->OwnerThread->Tcb.Win32Thread);
BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
IntDeRegisterShellHookWindow(Window->Self);
if(SendMessages)
{
@@ -1417,6 +1451,8 @@ IntCreateWindowEx(DWORD dwExStyle,
BOOL MenuChanged;
BOOL ClassFound;
BOOL HasOwner;
ParentWindowHandle = PsGetWin32Thread()->Desktop->DesktopWindow;
OwnerWindowHandle = NULL;
@@ -1542,9 +1578,11 @@ IntCreateWindowEx(DWORD dwExStyle,
{
WindowObject->Owner = OwnerWindowHandle;
IntReleaseWindowObject(OwnerWindow);
}
else
HasOwner = TRUE;
} else {
WindowObject->Owner = NULL;
HasOwner = FALSE;
}
WindowObject->UserData = 0;
if ((((DWORD)ClassObject->lpfnWndProcA & 0xFFFF0000) != 0xFFFF0000)
&& (((DWORD)ClassObject->lpfnWndProcW & 0xFFFF0000) != 0xFFFF0000))
@@ -1969,6 +2007,13 @@ IntCreateWindowEx(DWORD dwExStyle,
(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 @@ NtUserWindowFromPoint(LONG X, LONG Y)
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 @@ NtUserDefSetText(HWND WindowHandle, PUNICODE_STRING WindowText)
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;