From 0286135de3986c4c8cfac1819b562372ca2633e8 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 29 Oct 2002 00:41:42 +0000 Subject: [PATCH] Rewrote hook support to store the hook chain in the server. Split off 16-bit hook functions and re-implemented them on top of the 32-bit ones; system-wide 16-bit hooks are no longer supported at this point. --- dlls/ttydrv/wnd.c | 22 +- dlls/user/Makefile.in | 3 +- dlls/user/focus.c | 17 +- dlls/user/hook.c | 518 +++++++++++++ dlls/user/hook16.c | 617 ++++++++++++++++ dlls/user/message.c | 58 +- dlls/user/msg16.c | 32 +- dlls/user/user.exe.spec | 4 +- dlls/user/user32.spec | 4 +- dlls/user/user_main.c | 4 +- dlls/x11drv/window.c | 27 +- dlls/x11drv/winpos.c | 6 +- include/hook.h | 45 -- include/queue.h | 8 +- include/user.h | 4 + include/wine/server_protocol.h | 91 ++- include/wine/winuser16.h | 4 +- server/Makefile.in | 1 + server/hook.c | 316 ++++++++ server/list.h | 28 + server/protocol.def | 47 ++ server/request.h | 10 + server/thread.c | 3 + server/thread.h | 2 + server/trace.c | 66 ++ server/user.h | 3 +- windows/hook.c | 1236 -------------------------------- windows/input.c | 5 +- windows/message.c | 79 +- windows/nonclient.c | 1 - windows/queue.c | 1 - windows/user.c | 3 +- windows/win.c | 7 +- 33 files changed, 1812 insertions(+), 1460 deletions(-) create mode 100644 dlls/user/hook.c create mode 100644 dlls/user/hook16.c delete mode 100644 include/hook.h create mode 100644 server/hook.c delete mode 100644 windows/hook.c diff --git a/dlls/ttydrv/wnd.c b/dlls/ttydrv/wnd.c index e45c9f4186d..8a5a8ee8f0a 100644 --- a/dlls/ttydrv/wnd.c +++ b/dlls/ttydrv/wnd.c @@ -26,7 +26,6 @@ #include "winpos.h" #include "wownt32.h" #include "wine/debug.h" -#include "hook.h" WINE_DEFAULT_DEBUG_CHANNEL(ttydrv); @@ -44,6 +43,7 @@ BOOL TTYDRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode ) { BOOL ret; HWND hwndLinkAfter; + CBT_CREATEWNDA cbtc; #ifdef WINE_CURSES WND *wndPtr = WIN_GetPtr( hwnd ); @@ -81,22 +81,12 @@ BOOL TTYDRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode ) hwndLinkAfter = ((cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD) ? HWND_BOTTOM : HWND_TOP; - if (HOOK_IsHooked( WH_CBT )) + cbtc.lpcs = cs; + cbtc.hwndInsertAfter = hwndLinkAfter; + if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) { - CBT_CREATEWNDA cbtc; - LRESULT lret; - - cbtc.lpcs = cs; - cbtc.hwndInsertAfter = hwndLinkAfter; - lret = (unicode) ? HOOK_CallHooksW(WH_CBT, HCBT_CREATEWND, - (WPARAM)hwnd, (LPARAM)&cbtc) - : HOOK_CallHooksA(WH_CBT, HCBT_CREATEWND, - (WPARAM)hwnd, (LPARAM)&cbtc); - if (lret) - { - TRACE("CBT-hook returned !0\n"); - return FALSE; - } + TRACE("CBT-hook returned !0\n"); + return FALSE; } if (unicode) diff --git a/dlls/user/Makefile.in b/dlls/user/Makefile.in index 4a7db41e8d1..ce9ef0e0537 100644 --- a/dlls/user/Makefile.in +++ b/dlls/user/Makefile.in @@ -30,7 +30,6 @@ C_SRCS = \ $(TOPOBJDIR)/windows/defwnd.c \ $(TOPOBJDIR)/windows/dialog.c \ $(TOPOBJDIR)/windows/driver.c \ - $(TOPOBJDIR)/windows/hook.c \ $(TOPOBJDIR)/windows/input.c \ $(TOPOBJDIR)/windows/keyboard.c \ $(TOPOBJDIR)/windows/mdi.c \ @@ -63,6 +62,7 @@ C_SRCS = \ display.c \ exticon.c \ focus.c \ + hook.c \ lstr.c \ message.c \ misc.c \ @@ -77,6 +77,7 @@ C_SRCS = \ C_SRCS16 = \ bidi16.c \ + hook16.c \ network.c \ user16.c \ wnd16.c diff --git a/dlls/user/focus.c b/dlls/user/focus.c index cceffa5a09c..a6e7de8e4c6 100644 --- a/dlls/user/focus.c +++ b/dlls/user/focus.c @@ -24,7 +24,6 @@ #include "winuser.h" #include "winerror.h" #include "win.h" -#include "hook.h" #include "message.h" #include "user.h" #include "wine/server.h" @@ -74,6 +73,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) HWND previous = GetActiveWindow(); BOOL ret; DWORD old_thread, new_thread; + CBTACTIVATESTRUCT cbt; if (previous == hwnd) { @@ -82,13 +82,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) } /* call CBT hook chain */ - if (HOOK_IsHooked( WH_CBT )) - { - CBTACTIVATESTRUCT cbt; - cbt.fMouse = mouse; - cbt.hWndActive = previous; - if (HOOK_CallHooksW( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt )) return FALSE; - } + cbt.fMouse = mouse; + cbt.hWndActive = previous; + if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) return FALSE; if (IsWindow(previous)) { @@ -265,7 +261,7 @@ HWND WINAPI SetFocus( HWND hwnd ) } /* call hooks */ - if (HOOK_CallHooksW( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous )) return 0; + if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous, TRUE )) return 0; /* activate hwndTop if needed. */ if (hwndTop != GetActiveWindow()) @@ -277,8 +273,7 @@ HWND WINAPI SetFocus( HWND hwnd ) else /* NULL hwnd passed in */ { if (!previous) return 0; /* nothing to do */ - if( HOOK_CallHooksW( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous ) ) - return 0; + if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous, TRUE )) return 0; } /* change focus and send messages */ diff --git a/dlls/user/hook.c b/dlls/user/hook.c new file mode 100644 index 00000000000..c60ff5e908e --- /dev/null +++ b/dlls/user/hook.c @@ -0,0 +1,518 @@ +/* + * Windows hook functions + * + * Copyright 2002 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES: + * Status of the various hooks: + * WH_MSGFILTER OK + * WH_JOURNALRECORD Partially implemented + * WH_JOURNALPLAYBACK Partially implemented + * WH_KEYBOARD OK + * WH_GETMESSAGE OK (FIXME: A/W mapping?) + * WH_CALLWNDPROC OK (FIXME: A/W mapping?) + * WH_CBT + * HCBT_MOVESIZE OK + * HCBT_MINMAX OK + * HCBT_QS OK + * HCBT_CREATEWND OK + * HCBT_DESTROYWND OK + * HCBT_ACTIVATE OK + * HCBT_CLICKSKIPPED OK + * HCBT_KEYSKIPPED OK + * HCBT_SYSCOMMAND Not implemented + * HCBT_SETFOCUS OK + * WH_SYSMSGFILTER OK + * WH_MOUSE OK + * WH_HARDWARE Not supported in Win32 + * WH_DEBUG Not implemented + * WH_SHELL + * HSHELL_WINDOWCREATED OK + * HSHELL_WINDOWDESTROYED OK + * HSHELL_ACTIVATESHELLWINDOW Not implemented + * HSHELL_WINDOWACTIVATED Not implemented + * HSHELL_GETMINRECT Not implemented + * HSHELL_REDRAW Not implemented + * HSHELL_TASKMAN Not implemented + * HSHELL_LANGUAGE Not implemented + * HSHELL_SYSMENU Not implemented + * HSHELL_ENDTASK Not implemented + * HSHELL_ACCESSIBILITYSTATE Not implemented + * HSHELL_APPCOMMAND Not implemented + * HSHELL_WINDOWREPLACED Not implemented + * HSHELL_WINDOWREPLACING Not implemented + * WH_FOREGROUNDIDLE Not implemented + * WH_CALLWNDPROCRET OK (FIXME: A/W mapping?) + * WH_KEYBOARD_LL Implemented but should use SendMessage instead + * WH_MOUSE_LL Implemented but should use SendMessage instead + */ + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winerror.h" +#include "heap.h" +#include "queue.h" +#include "win.h" +#include "wine/server.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(hook); +WINE_DECLARE_DEBUG_CHANNEL(relay); + +static const char * const hook_names[WH_MAXHOOK - WH_MINHOOK + 1] = +{ + "WH_MSGFILTER", + "WH_JOURNALRECORD", + "WH_JOURNALPLAYBACK", + "WH_KEYBOARD", + "WH_GETMESSAGE", + "WH_CALLWNDPROC", + "WH_CBT", + "WH_SYSMSGFILTER", + "WH_MOUSE", + "WH_HARDWARE", + "WH_DEBUG", + "WH_SHELL", + "WH_FOREGROUNDIDLE", + "WH_CALLWNDPROCRET", + "WH_KEYBOARD_LL", + "WH_MOUSE_LL" +}; + + +/*********************************************************************** + * set_windows_hook + * + * Implementation of SetWindowsHookExA and SetWindowsHookExW. + */ +static HHOOK set_windows_hook( INT id, HOOKPROC proc, HINSTANCE inst, DWORD tid, BOOL unicode ) +{ + HHOOK handle = 0; + + if (tid) /* thread-local hook */ + { + if (id == WH_JOURNALRECORD || + id == WH_JOURNALPLAYBACK || + id == WH_KEYBOARD_LL || + id == WH_MOUSE_LL || + id == WH_SYSMSGFILTER) + { + /* these can only be global */ + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + } + else /* system-global hook */ + { + if (!inst) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + FIXME( "system hook %s won't work right\n", hook_names[id-WH_MINHOOK] ); + } + + SERVER_START_REQ( set_hook ) + { + req->id = id; + req->tid = tid; + req->proc = proc; + req->unicode = unicode; + if (!wine_server_call_err( req )) handle = reply->handle; + } + SERVER_END_REQ; + + TRACE( "%s %p %lx -> %x\n", hook_names[id-WH_MINHOOK], proc, tid, handle ); + return handle; +} + + +/*********************************************************************** + * call_hook_AtoW + */ +static LRESULT call_hook_AtoW( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam ) +{ + LRESULT ret; + + if (id != WH_CBT || code != HCBT_CREATEWND) ret = proc( code, wparam, lparam ); + else + { + CBT_CREATEWNDA *cbtcwA = (CBT_CREATEWNDA *)lparam; + CBT_CREATEWNDW cbtcwW; + CREATESTRUCTW csW; + + cbtcwW.lpcs = &csW; + cbtcwW.hwndInsertAfter = cbtcwA->hwndInsertAfter; + csW = *(CREATESTRUCTW *)cbtcwA->lpcs; + + if (HIWORD(cbtcwA->lpcs->lpszName)) + csW.lpszName = HEAP_strdupAtoW( GetProcessHeap(), 0, cbtcwA->lpcs->lpszName ); + if (HIWORD(cbtcwA->lpcs->lpszClass)) + csW.lpszClass = HEAP_strdupAtoW( GetProcessHeap(), 0, cbtcwA->lpcs->lpszClass ); + ret = proc( code, wparam, (LPARAM)&cbtcwW ); + cbtcwA->hwndInsertAfter = cbtcwW.hwndInsertAfter; + if (HIWORD(csW.lpszName)) HeapFree( GetProcessHeap(), 0, (LPWSTR)csW.lpszName ); + if (HIWORD(csW.lpszClass)) HeapFree( GetProcessHeap(), 0, (LPWSTR)csW.lpszClass ); + } + return ret; +} + + +/*********************************************************************** + * call_hook_WtoA + */ +static LRESULT call_hook_WtoA( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam ) +{ + LRESULT ret; + + if (id != WH_CBT || code != HCBT_CREATEWND) ret = proc( code, wparam, lparam ); + else + { + CBT_CREATEWNDW *cbtcwW = (CBT_CREATEWNDW *)lparam; + CBT_CREATEWNDA cbtcwA; + CREATESTRUCTA csA; + + cbtcwA.lpcs = &csA; + cbtcwA.hwndInsertAfter = cbtcwW->hwndInsertAfter; + csA = *(CREATESTRUCTA *)cbtcwW->lpcs; + + if (HIWORD(cbtcwW->lpcs->lpszName)) + csA.lpszName = HEAP_strdupWtoA( GetProcessHeap(), 0, cbtcwW->lpcs->lpszName ); + if (HIWORD(cbtcwW->lpcs->lpszClass)) + csA.lpszClass = HEAP_strdupWtoA( GetProcessHeap(), 0, cbtcwW->lpcs->lpszClass ); + ret = proc( code, wparam, (LPARAM)&cbtcwA ); + cbtcwW->hwndInsertAfter = cbtcwA.hwndInsertAfter; + if (HIWORD(csA.lpszName)) HeapFree( GetProcessHeap(), 0, (LPSTR)csA.lpszName ); + if (HIWORD(csA.lpszClass)) HeapFree( GetProcessHeap(), 0, (LPSTR)csA.lpszClass ); + } + return ret; +} + + +/*********************************************************************** + * call_hook + */ +static LRESULT call_hook( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam, + BOOL prev_unicode, BOOL next_unicode ) +{ + LRESULT ret; + + if (TRACE_ON(relay)) + DPRINTF( "%08lx:Call hook proc %p (id=%s,code=%x,wp=%08x,lp=%08lx)\n", + GetCurrentThreadId(), proc, hook_names[id-WH_MINHOOK], code, wparam, lparam ); + + if (!prev_unicode == !next_unicode) ret = proc( code, wparam, lparam ); + else if (prev_unicode) ret = call_hook_WtoA( proc, id, code, wparam, lparam ); + else ret = call_hook_AtoW( proc, id, code, wparam, lparam ); + + if (TRACE_ON(relay)) + DPRINTF( "%08lx:Ret hook proc %p (id=%s,code=%x,wp=%08x,lp=%08lx) retval=%08lx\n", + GetCurrentThreadId(), proc, hook_names[id-WH_MINHOOK], code, wparam, lparam, ret ); + + return ret; +} + + +/*********************************************************************** + * HOOK_CallHooks + */ +LRESULT HOOK_CallHooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL unicode ) +{ + MESSAGEQUEUE *queue = QUEUE_Current(); + HOOKPROC proc = NULL; + HHOOK prev; + BOOL unicode_hook = FALSE; + LRESULT ret = 0; + int locks; + + if (!queue) return 0; + prev = queue->hook; + SERVER_START_REQ( start_hook_chain ) + { + req->id = id; + if (!wine_server_call_err( req )) + { + queue->hook = reply->handle; + proc = reply->proc; + unicode_hook = reply->unicode; + } + } + SERVER_END_REQ; + + if (proc) + { + TRACE( "calling hook %p %s code %x wp %x lp %lx\n", + proc, hook_names[id-WH_MINHOOK], code, wparam, lparam ); + + locks = WIN_SuspendWndsLock(); + ret = call_hook( proc, id, code, wparam, lparam, unicode, unicode_hook ); + WIN_RestoreWndsLock( locks ); + + SERVER_START_REQ( finish_hook_chain ) + { + req->id = id; + wine_server_call( req ); + } + SERVER_END_REQ; + } + + queue->hook = prev; + return ret; +} + + +/*********************************************************************** + * HOOK_IsHooked + */ +BOOL HOOK_IsHooked( INT id ) +{ + return TRUE; /* FIXME */ +} + + +/*********************************************************************** + * SetWindowsHookA (USER32.@) + */ +HHOOK WINAPI SetWindowsHookA( INT id, HOOKPROC proc ) +{ + return SetWindowsHookExA( id, proc, 0, GetCurrentThreadId() ); +} + + +/*********************************************************************** + * SetWindowsHookW (USER32.@) + */ +HHOOK WINAPI SetWindowsHookW( INT id, HOOKPROC proc ) +{ + return SetWindowsHookExW( id, proc, 0, GetCurrentThreadId() ); +} + + +/*********************************************************************** + * SetWindowsHookExA (USER32.@) + */ +HHOOK WINAPI SetWindowsHookExA( INT id, HOOKPROC proc, HINSTANCE inst, DWORD tid ) +{ + return set_windows_hook( id, proc, inst, tid, FALSE ); +} + +/*********************************************************************** + * SetWindowsHookExW (USER32.@) + */ +HHOOK WINAPI SetWindowsHookExW( INT id, HOOKPROC proc, HINSTANCE inst, DWORD tid ) +{ + return set_windows_hook( id, proc, inst, tid, TRUE ); +} + + +/*********************************************************************** + * UnhookWindowsHook (USER32.@) + */ +BOOL WINAPI UnhookWindowsHook( INT id, HOOKPROC proc ) +{ + BOOL ret; + + TRACE( "%s %p\n", hook_names[id-WH_MINHOOK], proc ); + + SERVER_START_REQ( remove_hook ) + { + req->id = id; + req->proc = proc; + ret = !wine_server_call_err( req ); + } + SERVER_END_REQ; + return ret; +} + + + +/*********************************************************************** + * UnhookWindowsHookEx (USER32.@) + */ +BOOL WINAPI UnhookWindowsHookEx( HHOOK hhook ) +{ + BOOL ret; + + TRACE( "%x\n", hhook ); + + SERVER_START_REQ( remove_hook ) + { + req->handle = hhook; + ret = !wine_server_call_err( req ); + } + SERVER_END_REQ; + return ret; +} + + +/*********************************************************************** + * CallNextHookEx (USER32.@) + */ +LRESULT WINAPI CallNextHookEx( HHOOK hhook, INT code, WPARAM wparam, LPARAM lparam ) +{ + MESSAGEQUEUE *queue = QUEUE_Current(); + HHOOK prev; + HOOKPROC proc = NULL; + INT id = 0; + BOOL prev_unicode = FALSE, next_unicode = FALSE; + LRESULT ret = 0; + + if (!queue) return 0; + prev = queue->hook; + SERVER_START_REQ( get_next_hook ) + { + req->handle = prev; + if (!wine_server_call_err( req )) + { + queue->hook = reply->next; + id = reply->id; + proc = reply->proc; + prev_unicode = reply->prev_unicode; + next_unicode = reply->next_unicode; + } + } + SERVER_END_REQ; + if (proc) + { + TRACE( "calling hook %p %s code %x wp %x lp %lx\n", + proc, hook_names[id-WH_MINHOOK], code, wparam, lparam ); + + return call_hook( proc, id, code, wparam, lparam, prev_unicode, next_unicode ); + } + queue->hook = prev; + return ret; +} + + +/*********************************************************************** + * CallMsgFilterA (USER32.@) + */ +BOOL WINAPI CallMsgFilterA( LPMSG msg, INT code ) +{ + if (HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)msg, FALSE )) return TRUE; + return HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)msg, FALSE ); +} + + +/*********************************************************************** + * CallMsgFilterW (USER32.@) + */ +BOOL WINAPI CallMsgFilterW( LPMSG msg, INT code ) +{ + if (HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)msg, TRUE )) return TRUE; + return HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)msg, TRUE ); +} + + +/*********************************************************************** + * SetWinEventHook [USER32.@] + * + * Set up an event hook for a set of events. + * + * PARAMS + * dwMin [I] Lowest event handled by pfnProc + * dwMax [I] Highest event handled by pfnProc + * hModule [I] DLL containing pfnProc + * pfnProc [I] Callback event hook function + * dwProcess [I] Process to get events from, or 0 for all processes + * dwThread [I] Thread to get events from, or 0 for all threads + * dwFlags [I] Flags indicating the status of pfnProc + * + * RETURNS + * Success: A handle representing the hook. + * Failure: A NULL handle. + * + * BUGS + * Not implemented. + */ +HWINEVENTHOOK WINAPI SetWinEventHook(DWORD dwMin, DWORD dwMax, HMODULE hModule, + WINEVENTPROC pfnProc, DWORD dwProcess, + DWORD dwThread, DWORD dwFlags) +{ + FIXME("(%ld,%ld,0x%08x,%p,%ld,%ld,0x%08lx)-stub!\n", dwMin, dwMax, hModule, + pfnProc, dwProcess, dwThread, dwFlags); + return 0; +} + + +/*********************************************************************** + * UnhookWinEvent [USER32.@] + * + * Remove an event hook for a set of events. + * + * PARAMS + * hEventHook [I] Event hook to remove + * + * RETURNS + * Success: TRUE. The event hook has been removed. + * Failure: FALSE, if hEventHook is invalid. + * + * BUGS + * Not implemented. + */ +BOOL WINAPI UnhookWinEvent(HWINEVENTHOOK hEventHook) +{ + FIXME("(%x)-stub!\n", hEventHook); + + return (hEventHook != 0); +} + + +/*********************************************************************** + * NotifyWinEvent [USER32.@] + * + * Inform the OS that an event has occurred. + * + * PARAMS + * dwEvent [I] Id of the event + * hWnd [I] Window holding the object that created the event + * nId [I] Type of object that created the event + * nChildId [I] Child object of nId, or CHILDID_SELF. + * + * RETURNS + * Nothing. + * + * BUGS + * Not implemented. + */ +void WINAPI NotifyWinEvent(DWORD dwEvent, HWND hWnd, LONG nId, LONG nChildId) +{ + FIXME("(%ld,0x%08x,%ld,%ld)-stub!\n", dwEvent, hWnd, nId, nChildId); +} + + +/*********************************************************************** + * IsWinEventHookInstalled [USER32.@] + * + * Determine if an event hook is installed for an event. + * + * PARAMS + * dwEvent [I] Id of the event + * + * RETURNS + * TRUE, If there are any hooks installed for the event. + * FALSE, Otherwise. + * + * BUGS + * Not implemented. + */ +BOOL WINAPI IsWinEventHookInstalled(DWORD dwEvent) +{ + FIXME("(%ld)-stub!\n", dwEvent); + return TRUE; +} diff --git a/dlls/user/hook16.c b/dlls/user/hook16.c new file mode 100644 index 00000000000..0b3a676edb8 --- /dev/null +++ b/dlls/user/hook16.c @@ -0,0 +1,617 @@ +/* + * Windows 16-bit hook functions + * + * Copyright 1994, 1995, 2002 Alexandre Julliard + * Copyright 1996 Andrew Lewycky + * + * Based on investigations by Alex Korobka + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "wownt32.h" +#include "wine/winuser16.h" +#include "queue.h" +#include "win.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(hook); + + +static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp ); +static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp ); +static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp ); +static LRESULT CALLBACK call_WH_CALLWNDPROC( INT code, WPARAM wp, LPARAM lp ); +static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp ); +static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp ); +static LRESULT CALLBACK call_WH_SHELL( INT code, WPARAM wp, LPARAM lp ); + +#define WH_MAXHOOK16 WH_SHELL /* Win16 only supports up to WH_SHELL */ +#define NB_HOOKS16 (WH_MAXHOOK16 - WH_MINHOOK + 1) + +static const HOOKPROC hook_procs[NB_HOOKS16] = +{ + call_WH_MSGFILTER, /* WH_MSGFILTER */ + NULL, /* WH_JOURNALRECORD */ + NULL, /* WH_JOURNALPLAYBACK */ + call_WH_KEYBOARD, /* WH_KEYBOARD */ + call_WH_GETMESSAGE, /* WH_GETMESSAGE */ + call_WH_CALLWNDPROC, /* WH_CALLWNDPROC */ + call_WH_CBT, /* WH_CBT */ + NULL, /* WH_SYSMSGFILTER */ + call_WH_MOUSE, /* WH_MOUSE */ + NULL, /* WH_HARDWARE */ + NULL, /* WH_DEBUG */ + call_WH_SHELL /* WH_SHELL */ +}; + + +/* this structure is stored in the thread queue */ +struct hook16_queue_info +{ + INT id; /* id of current hook */ + HHOOK hook[NB_HOOKS16]; /* Win32 hook handles */ + HOOKPROC16 proc[NB_HOOKS16]; /* 16-bit hook procedures */ +}; + + +/* ### start build ### */ +extern LONG CALLBACK HOOK_CallTo16_long_wwl(HOOKPROC16,WORD,WORD,LONG); +/* ### stop build ### */ + + +/*********************************************************************** + * map_msg_16_to_32 + */ +inline static void map_msg_16_to_32( const MSG16 *msg16, MSG *msg32 ) +{ + msg32->hwnd = WIN_Handle32(msg16->hwnd); + msg32->message = msg16->message; + msg32->wParam = msg16->wParam; + msg32->lParam = msg16->lParam; + msg32->time = msg16->time; + msg32->pt.x = msg16->pt.x; + msg32->pt.y = msg16->pt.y; +} + + +/*********************************************************************** + * map_msg_32_to_16 + */ +inline static void map_msg_32_to_16( const MSG *msg32, MSG16 *msg16 ) +{ + msg16->hwnd = HWND_16(msg32->hwnd); + msg16->message = msg32->message; + msg16->wParam = msg32->wParam; + msg16->lParam = msg32->lParam; + msg16->time = msg32->time; + msg16->pt.x = msg32->pt.x; + msg16->pt.y = msg32->pt.y; +} + + +/*********************************************************************** + * call_hook_16 + */ +static LRESULT call_hook_16( INT id, INT code, WPARAM wp, LPARAM lp ) +{ + struct hook16_queue_info *info = QUEUE_Current()->hook16_info; + LRESULT ret; + INT prev_id = info->id; + info->id = id; + ret = HOOK_CallTo16_long_wwl( info->proc[id - WH_MINHOOK], code, wp, lp ); + info->id = prev_id; + + /* Grrr. While the hook procedure is supposed to have an LRESULT return + value even in Win16, it seems that for those hook types where the + return value is interpreted as BOOL, Windows doesn't actually check + the HIWORD ... Some buggy Win16 programs, notably WINFILE, rely on + that, because they neglect to clear DX ... */ + if (id != WH_JOURNALPLAYBACK) ret = LOWORD( ret ); + return ret; +} + + +/*********************************************************************** + * call_WH_MSGFILTER + */ +static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp ) +{ + MSG *msg32 = (MSG *)lp; + MSG16 msg16; + LRESULT ret; + + map_msg_32_to_16( msg32, &msg16 ); + lp = MapLS( &msg16 ); + ret = call_hook_16( WH_MSGFILTER, code, wp, lp ); + UnMapLS( lp ); + return ret; +} + + +/*********************************************************************** + * call_WH_KEYBOARD + */ +static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp ) +{ + return call_hook_16( WH_KEYBOARD, code, wp, lp ); +} + + +/*********************************************************************** + * call_WH_GETMESSAGE + */ +static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp ) +{ + MSG *msg32 = (MSG *)lp; + MSG16 msg16; + LRESULT ret; + + map_msg_32_to_16( msg32, &msg16 ); + + lp = MapLS( &msg16 ); + ret = call_hook_16( WH_GETMESSAGE, code, wp, lp ); + UnMapLS( lp ); + + map_msg_16_to_32( &msg16, msg32 ); + return ret; +} + + +/*********************************************************************** + * call_WH_CALLWNDPROC + */ +static LRESULT CALLBACK call_WH_CALLWNDPROC( INT code, WPARAM wp, LPARAM lp ) +{ + CWPSTRUCT *cwp32 = (CWPSTRUCT *)lp; + CWPSTRUCT16 cwp16; + MSGPARAM16 mp16; + LRESULT ret; + + cwp16.hwnd = HWND_16(cwp32->hwnd); + cwp16.lParam = cwp32->lParam; + + WINPROC_MapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam, + &cwp16.message, &cwp16.wParam, &cwp16.lParam ); + + lp = MapLS( &cwp16 ); + ret = call_hook_16( WH_CALLWNDPROC, code, wp, lp ); + UnMapLS( lp ); + + mp16.wParam = cwp16.wParam; + mp16.lParam = cwp16.lParam; + mp16.lResult = 0; + WINPROC_UnmapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam, cwp32->lParam, &mp16 ); + return ret; +} + + +/*********************************************************************** + * call_WH_CBT + */ +static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp ) +{ + LRESULT ret = 0; + + switch (code) + { + case HCBT_CREATEWND: + { + CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lp; + CBT_CREATEWND16 cbtcw16; + CREATESTRUCT16 cs16; + + cs16.lpCreateParams = cbtcw32->lpcs->lpCreateParams; + cs16.hInstance = MapHModuleLS(cbtcw32->lpcs->hInstance); + cs16.hMenu = HMENU_16(cbtcw32->lpcs->hMenu); + cs16.hwndParent = HWND_16(cbtcw32->lpcs->hwndParent); + cs16.cy = cbtcw32->lpcs->cy; + cs16.cx = cbtcw32->lpcs->cx; + cs16.y = cbtcw32->lpcs->y; + cs16.x = cbtcw32->lpcs->x; + cs16.style = cbtcw32->lpcs->style; + cs16.lpszName = MapLS( cbtcw32->lpcs->lpszName ); + cs16.lpszClass = MapLS( cbtcw32->lpcs->lpszClass ); + cs16.dwExStyle = cbtcw32->lpcs->dwExStyle; + + cbtcw16.lpcs = (CREATESTRUCT16 *)MapLS( &cs16 ); + cbtcw16.hwndInsertAfter = HWND_16( cbtcw32->hwndInsertAfter ); + + lp = MapLS( &cbtcw16 ); + ret = call_hook_16( WH_CBT, code, wp, lp ); + UnMapLS( cs16.lpszName ); + UnMapLS( cs16.lpszClass ); + + cbtcw32->hwndInsertAfter = WIN_Handle32( cbtcw16.hwndInsertAfter ); + UnMapLS( (SEGPTR)cbtcw16.lpcs ); + UnMapLS( lp ); + break; + } + + case HCBT_ACTIVATE: + { + CBTACTIVATESTRUCT *cas32 = (CBTACTIVATESTRUCT *)lp; + CBTACTIVATESTRUCT16 cas16; + + cas16.fMouse = cas32->fMouse; + cas16.hWndActive = HWND_16( cas32->hWndActive ); + + lp = MapLS( &cas16 ); + ret = call_hook_16( WH_CBT, code, wp, lp ); + UnMapLS( lp ); + break; + } + case HCBT_CLICKSKIPPED: + { + MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp; + MOUSEHOOKSTRUCT16 ms16; + + ms16.pt.x = ms32->pt.x; + ms16.pt.y = ms32->pt.y; + ms16.hwnd = HWND_16( ms32->hwnd ); + ms16.wHitTestCode = ms32->wHitTestCode; + ms16.dwExtraInfo = ms32->dwExtraInfo; + + lp = MapLS( &ms16 ); + ret = call_hook_16( WH_CBT, code, wp, lp ); + UnMapLS( lp ); + break; + } + case HCBT_MOVESIZE: + { + RECT *rect32 = (RECT *)lp; + RECT16 rect16; + + CONV_RECT32TO16( rect32, &rect16 ); + lp = MapLS( &rect16 ); + ret = call_hook_16( WH_CBT, code, wp, lp ); + UnMapLS( lp ); + break; + } + } + return ret; +} + + +/*********************************************************************** + * call_WH_MOUSE + */ +static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp ) +{ + MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp; + MOUSEHOOKSTRUCT16 ms16; + LRESULT ret; + + ms16.pt.x = ms32->pt.x; + ms16.pt.y = ms32->pt.y; + ms16.hwnd = HWND_16( ms32->hwnd ); + ms16.wHitTestCode = ms32->wHitTestCode; + ms16.dwExtraInfo = ms32->dwExtraInfo; + + lp = MapLS( &ms16 ); + ret = call_hook_16( WH_MOUSE, code, wp, lp ); + UnMapLS( lp ); + return ret; +} + + +/*********************************************************************** + * call_WH_SHELL + */ +static LRESULT CALLBACK call_WH_SHELL( INT code, WPARAM wp, LPARAM lp ) +{ + return call_hook_16( WH_SHELL, code, wp, lp ); +} + + +/*********************************************************************** + * SetWindowsHook (USER.121) + */ +FARPROC16 WINAPI SetWindowsHook16( INT16 id, HOOKPROC16 proc ) +{ + HINSTANCE16 hInst = FarGetOwner16( HIWORD(proc) ); + + /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */ + HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0; + + return (FARPROC16)SetWindowsHookEx16( id, proc, hInst, hTask ); +} + + +/*********************************************************************** + * SetWindowsHookEx (USER.291) + */ +HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst, HTASK16 hTask ) +{ + MESSAGEQUEUE *queue = QUEUE_Current(); + struct hook16_queue_info *info; + HHOOK hook; + int index = id - WH_MINHOOK; + + if (!queue) return 0; + if (id < WH_MINHOOK || id > WH_MAXHOOK16) return 0; + if (!hook_procs[index]) + { + FIXME( "hook type %d broken in Win16\n", id ); + return 0; + } + if (!hTask) FIXME( "System-global hooks (%d) broken in Win16\n", id ); + else if (hTask != GetCurrentTask()) + { + FIXME( "setting hook (%d) on other task not supported\n", id ); + return 0; + } + + if (!(info = queue->hook16_info)) + { + if (!(info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*info) ))) return 0; + queue->hook16_info = info; + } + if (info->hook[index]) + { + FIXME( "Multiple hooks (%d) for the same task not supported yet\n", id ); + return 0; + } + if (!(hook = SetWindowsHookExA( id, hook_procs[index], 0, GetCurrentThreadId() ))) return 0; + info->hook[index] = hook; + info->proc[index] = proc; + return hook; +} + + +/*********************************************************************** + * UnhookWindowsHook (USER.234) + */ +BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc ) +{ + MESSAGEQUEUE *queue = QUEUE_Current(); + struct hook16_queue_info *info; + int index = id - WH_MINHOOK; + + if (id < WH_MINHOOK || id > WH_MAXHOOK16) return FALSE; + if (!queue || !(info = queue->hook16_info)) return FALSE; + if (info->proc[index] != proc) return FALSE; + if (!UnhookWindowsHookEx( info->hook[index] )) return FALSE; + info->hook[index] = 0; + info->proc[index] = 0; + return TRUE; +} + + +/*********************************************************************** + * UnhookWindowsHookEx (USER.292) + */ +BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook ) +{ + MESSAGEQUEUE *queue = QUEUE_Current(); + struct hook16_queue_info *info; + int index; + + if (!queue || !(info = queue->hook16_info)) return FALSE; + for (index = 0; index < NB_HOOKS16; index++) + { + if (info->hook[index] == hhook) + { + info->hook[index] = 0; + info->proc[index] = 0; + return UnhookWindowsHookEx( hhook ); + } + } + return FALSE; +} + + +/*********************************************************************** + * CallMsgFilter32 (USER.823) + */ +BOOL16 WINAPI CallMsgFilter32_16( MSG32_16 *lpmsg16_32, INT16 code, BOOL16 wHaveParamHigh ) +{ + MSG msg32; + BOOL16 ret; + + if (GetSysModalWindow16()) return FALSE; + msg32.hwnd = WIN_Handle32( lpmsg16_32->msg.hwnd ); + msg32.message = lpmsg16_32->msg.message; + msg32.lParam = lpmsg16_32->msg.lParam; + msg32.time = lpmsg16_32->msg.time; + msg32.pt.x = lpmsg16_32->msg.pt.x; + msg32.pt.y = lpmsg16_32->msg.pt.y; + if (wHaveParamHigh) msg32.wParam = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh); + else msg32.wParam = lpmsg16_32->msg.wParam; + + ret = (BOOL16)CallMsgFilterA(&msg32, code); + + lpmsg16_32->msg.hwnd = HWND_16( msg32.hwnd ); + lpmsg16_32->msg.message = msg32.message; + lpmsg16_32->msg.wParam = LOWORD(msg32.wParam); + lpmsg16_32->msg.lParam = msg32.lParam; + lpmsg16_32->msg.time = msg32.time; + lpmsg16_32->msg.pt.x = msg32.pt.x; + lpmsg16_32->msg.pt.y = msg32.pt.y; + if (wHaveParamHigh) lpmsg16_32->wParamHigh = HIWORD(msg32.wParam); + return ret; +} + + +/*********************************************************************** + * CallMsgFilter (USER.123) + */ +BOOL16 WINAPI CallMsgFilter16( MSG16 *msg, INT16 code ) +{ + return CallMsgFilter32_16( (MSG32_16 *)msg, code, FALSE ); +} + + +/*********************************************************************** + * CallNextHookEx (USER.293) + */ +LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wparam, LPARAM lparam ) +{ + MESSAGEQUEUE *queue = QUEUE_Current(); + struct hook16_queue_info *info; + LRESULT ret = 0; + + if (!queue || !(info = queue->hook16_info)) return 0; + + switch (info->id) + { + case WH_MSGFILTER: + { + MSG16 *msg16 = MapSL(lparam); + MSG msg32; + + map_msg_16_to_32( msg16, &msg32 ); + ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 ); + break; + } + + case WH_GETMESSAGE: + { + MSG16 *msg16 = MapSL(lparam); + MSG msg32; + + map_msg_16_to_32( msg16, &msg32 ); + ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 ); + map_msg_32_to_16( &msg32, msg16 ); + break; + } + + case WH_CALLWNDPROC: + { + CWPSTRUCT16 *cwp16 = MapSL(lparam); + CWPSTRUCT cwp32; + + cwp32.hwnd = WIN_Handle32(cwp16->hwnd); + cwp32.lParam = cwp16->lParam; + + WINPROC_MapMsg16To32A( cwp32.hwnd, cwp16->message, cwp16->wParam, + &cwp32.message, &cwp32.wParam, &cwp32.lParam ); + ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cwp32 ); + WINPROC_UnmapMsg16To32A( cwp32.hwnd, cwp32.message, cwp32.wParam, cwp32.lParam, 0 ); + break; + } + + case WH_CBT: + switch (code) + { + case HCBT_CREATEWND: + { + CBT_CREATEWNDA cbtcw32; + CREATESTRUCTA cs32; + CBT_CREATEWND16 *cbtcw16 = MapSL(lparam); + CREATESTRUCT16 *cs16 = MapSL( (SEGPTR)cbtcw16->lpcs ); + + cbtcw32.lpcs = &cs32; + cbtcw32.hwndInsertAfter = WIN_Handle32( cbtcw16->hwndInsertAfter ); + + cs32.lpCreateParams = cs16->lpCreateParams; + cs32.hInstance = MapHModuleSL(cs16->hInstance); + cs32.hMenu = HMENU_32(cs16->hMenu); + cs32.hwndParent = WIN_Handle32(cs16->hwndParent); + cs32.cy = cs16->cy; + cs32.cx = cs16->cx; + cs32.y = cs16->y; + cs32.x = cs16->x; + cs32.style = cs16->style; + cs32.lpszName = MapSL( cs16->lpszName ); + cs32.lpszClass = MapSL( cs16->lpszClass ); + cs32.dwExStyle = cs16->dwExStyle; + + ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cbtcw32 ); + cbtcw16->hwndInsertAfter = HWND_16( cbtcw32.hwndInsertAfter ); + break; + } + case HCBT_ACTIVATE: + { + CBTACTIVATESTRUCT16 *cas16 = MapSL(lparam); + CBTACTIVATESTRUCT cas32; + cas32.fMouse = cas16->fMouse; + cas32.hWndActive = WIN_Handle32(cas16->hWndActive); + ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cas32 ); + break; + } + case HCBT_CLICKSKIPPED: + { + MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam); + MOUSEHOOKSTRUCT ms32; + + ms32.pt.x = ms16->pt.x; + ms32.pt.y = ms16->pt.y; + /* wHitTestCode may be negative, so convince compiler to do + correct sign extension. Yay. :| */ + ms32.wHitTestCode = (INT)(INT16)ms16->wHitTestCode; + ms32.dwExtraInfo = ms16->dwExtraInfo; + ms32.hwnd = WIN_Handle32( ms16->hwnd ); + ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 ); + break; + } + case HCBT_MOVESIZE: + { + RECT16 *rect16 = MapSL(lparam); + RECT rect32; + + CONV_RECT16TO32( rect16, &rect32 ); + ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&rect32 ); + break; + } + } + break; + + case WH_MOUSE: + { + MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam); + MOUSEHOOKSTRUCT ms32; + + ms32.pt.x = ms16->pt.x; + ms32.pt.y = ms16->pt.y; + /* wHitTestCode may be negative, so convince compiler to do + correct sign extension. Yay. :| */ + ms32.wHitTestCode = (INT)((INT16)ms16->wHitTestCode); + ms32.dwExtraInfo = ms16->dwExtraInfo; + ms32.hwnd = WIN_Handle32(ms16->hwnd); + ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 ); + break; + } + + case WH_SHELL: + case WH_KEYBOARD: + ret = CallNextHookEx( hhook, code, wparam, lparam ); + break; + + case WH_HARDWARE: + case WH_FOREGROUNDIDLE: + case WH_CALLWNDPROCRET: + case WH_SYSMSGFILTER: + case WH_JOURNALRECORD: + case WH_JOURNALPLAYBACK: + default: + FIXME("\t[%i] 16to32 translation unimplemented\n", info->id); + ret = CallNextHookEx( hhook, code, wparam, lparam ); + break; + } + return ret; +} + + +/*********************************************************************** + * DefHookProc (USER.235) + */ +LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wparam, LPARAM lparam, HHOOK *hhook ) +{ + return CallNextHookEx16( *hhook, code, wparam, lparam ); +} diff --git a/dlls/user/message.c b/dlls/user/message.c index 1bcaf07fd17..c32249a4f40 100644 --- a/dlls/user/message.c +++ b/dlls/user/message.c @@ -32,7 +32,6 @@ #include "queue.h" #include "input.h" #include "message.h" -#include "hook.h" #include "spy.h" #include "user.h" #include "win.h" @@ -1339,10 +1338,13 @@ static BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM * * Call a window procedure and the corresponding hooks. */ -static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL unicode ) +static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, + BOOL unicode, BOOL same_thread ) { LRESULT result = 0; WNDPROC winproc; + CWPSTRUCT cwp; + CWPRETSTRUCT cwpret; MESSAGEQUEUE *queue = QUEUE_Current(); if (queue->recursion_count > MAX_SENDMSG_RECURSION) return 0; @@ -1355,20 +1357,12 @@ static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar } /* first the WH_CALLWNDPROC hook */ - if (HOOK_IsHooked( WH_CALLWNDPROC )) - { - CWPSTRUCT cwp; - cwp.lParam = lparam; - cwp.wParam = wparam; - cwp.message = msg; - cwp.hwnd = WIN_GetFullHandle( hwnd ); - if (unicode) HOOK_CallHooksW( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp ); - else HOOK_CallHooksA( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp ); - lparam = cwp.lParam; - wparam = cwp.wParam; - msg = cwp.message; - hwnd = cwp.hwnd; - } + hwnd = WIN_GetFullHandle( hwnd ); + cwp.lParam = lparam; + cwp.wParam = wparam; + cwp.message = msg; + cwp.hwnd = hwnd; + HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, same_thread, (LPARAM)&cwp, unicode ); /* now call the window procedure */ if (unicode) @@ -1383,17 +1377,12 @@ static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar } /* and finally the WH_CALLWNDPROCRET hook */ - if (HOOK_IsHooked( WH_CALLWNDPROCRET )) - { - CWPRETSTRUCT cwp; - cwp.lResult = result; - cwp.lParam = lparam; - cwp.wParam = wparam; - cwp.message = msg; - cwp.hwnd = WIN_GetFullHandle( hwnd ); - if (unicode) HOOK_CallHooksW( WH_CALLWNDPROCRET, HC_ACTION, 1, (LPARAM)&cwp ); - else HOOK_CallHooksA( WH_CALLWNDPROCRET, HC_ACTION, 1, (LPARAM)&cwp ); - } + cwpret.lResult = result; + cwpret.lParam = lparam; + cwpret.wParam = wparam; + cwpret.message = msg; + cwpret.hwnd = hwnd; + HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, same_thread, (LPARAM)&cwpret, unicode ); done: queue->recursion_count--; return result; @@ -1521,7 +1510,7 @@ BOOL MSG_peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, int flags ) old_info = queue->receive_info; queue->receive_info = &info; result = call_window_proc( info.msg.hwnd, info.msg.message, info.msg.wParam, - info.msg.lParam, (info.type != MSG_ASCII) ); + info.msg.lParam, (info.type != MSG_ASCII), FALSE ); reply_message( &info, result, TRUE ); queue->receive_info = old_info; next: @@ -1745,7 +1734,7 @@ LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM l if (dest_tid == GetCurrentThreadId()) { - result = call_window_proc( hwnd, msg, wparam, lparam, TRUE ); + result = call_window_proc( hwnd, msg, wparam, lparam, TRUE, TRUE ); ret = 1; } else @@ -1793,7 +1782,7 @@ LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM l if (dest_tid == GetCurrentThreadId()) { - result = call_window_proc( hwnd, msg, wparam, lparam, FALSE ); + result = call_window_proc( hwnd, msg, wparam, lparam, FALSE, TRUE ); ret = 1; } else if (dest_pid == GetCurrentProcessId()) @@ -1884,7 +1873,7 @@ BOOL WINAPI SendNotifyMessageW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara if (dest_tid == GetCurrentThreadId()) { - call_window_proc( hwnd, msg, wparam, lparam, TRUE ); + call_window_proc( hwnd, msg, wparam, lparam, TRUE, TRUE ); return TRUE; } return send_inter_thread_message( dest_tid, &info, &result ); @@ -1938,7 +1927,7 @@ BOOL WINAPI SendMessageCallbackW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa if (dest_tid == GetCurrentThreadId()) { - result = call_window_proc( hwnd, msg, wparam, lparam, TRUE ); + result = call_window_proc( hwnd, msg, wparam, lparam, TRUE, TRUE ); callback( hwnd, msg, data, result ); return TRUE; } @@ -2085,9 +2074,6 @@ BOOL WINAPI PeekMessageW( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT f if (!MSG_peek_message( &msg, hwnd, first, last, (flags & PM_REMOVE) ? GET_MSG_REMOVE : 0 )) { - /* FIXME: should be done before checking for hw events */ - MSG_JournalPlayBackMsg(); - if (!(flags & PM_NOYIELD)) { DWORD count; @@ -2119,7 +2105,7 @@ BOOL WINAPI PeekMessageW( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT f msg.pt.y = HIWORD( queue->GetMessagePosVal ); } - HOOK_CallHooksW( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)&msg ); + HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)&msg, TRUE ); /* copy back our internal safe copy of message data to msg_out. * msg_out is a variable from the *program*, so it can't be used diff --git a/dlls/user/msg16.c b/dlls/user/msg16.c index 935b53b23ac..243b23de04d 100644 --- a/dlls/user/msg16.c +++ b/dlls/user/msg16.c @@ -21,7 +21,6 @@ #include "wine/winuser16.h" #include "wownt32.h" #include "winerror.h" -#include "hook.h" #include "message.h" #include "spy.h" #include "thread.h" @@ -38,6 +37,8 @@ DWORD USER16_AlertableWait = 0; LRESULT WINAPI SendMessage16( HWND16 hwnd16, UINT16 msg, WPARAM16 wparam, LPARAM lparam ) { LRESULT result; + UINT msg32; + WPARAM wparam32; HWND hwnd = WIN_Handle32( hwnd16 ); if (hwnd != HWND_BROADCAST && WIN_IsCurrentThread(hwnd)) @@ -48,24 +49,20 @@ LRESULT WINAPI SendMessage16( HWND16 hwnd16, UINT16 msg, WPARAM16 wparam, LPARAM /* first the WH_CALLWNDPROC hook */ if (HOOK_IsHooked( WH_CALLWNDPROC )) { - CWPSTRUCT16 cwp; - SEGPTR seg_cwp; + LPARAM lparam32 = lparam; - cwp.hwnd = hwnd16; - cwp.message = msg; - cwp.wParam = wparam; - cwp.lParam = lparam; - seg_cwp = MapLS( &cwp ); - HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1, seg_cwp ); - UnMapLS( seg_cwp ); - if (cwp.hwnd != hwnd16) + if (WINPROC_MapMsg16To32A( hwnd, msg, wparam, &msg32, &wparam32, &lparam32 ) != -1) { - hwnd16 = cwp.hwnd; - hwnd = WIN_Handle32( hwnd16 ); + CWPSTRUCT cwp; + + cwp.hwnd = hwnd; + cwp.message = msg32; + cwp.wParam = wparam32; + cwp.lParam = lparam32; + HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp, FALSE ); + WINPROC_UnmapMsg16To32A( hwnd, msg32, wparam32, lparam32, 0 ); + /* FIXME: should reflect changes back into the message we send */ } - msg = cwp.message; - wparam = cwp.wParam; - lparam = cwp.lParam; } if (!(winproc = (WNDPROC16)GetWindowLong16( hwnd16, GWL_WNDPROC ))) return 0; @@ -76,9 +73,6 @@ LRESULT WINAPI SendMessage16( HWND16 hwnd16, UINT16 msg, WPARAM16 wparam, LPARAM } else /* map to 32-bit unicode for inter-thread/process message */ { - UINT msg32; - WPARAM wparam32; - if (WINPROC_MapMsg16To32W( hwnd, msg, wparam, &msg32, &wparam32, &lparam ) == -1) return 0; result = WINPROC_UnmapMsg16To32W( hwnd, msg32, wparam32, lparam, diff --git a/dlls/user/user.exe.spec b/dlls/user/user.exe.spec index c292fbc4bf2..bf533e5344e 100644 --- a/dlls/user/user.exe.spec +++ b/dlls/user/user.exe.spec @@ -121,7 +121,7 @@ rsrc resources/version16.res 120 pascal GetMessageTime() GetMessageTime 121 pascal SetWindowsHook(s_word segptr) SetWindowsHook16 122 pascal CallWindowProc(segptr word word word long) CallWindowProc16 -123 pascal16 CallMsgFilter(segptr s_word) CallMsgFilter16 +123 pascal16 CallMsgFilter(ptr s_word) CallMsgFilter16 124 pascal16 UpdateWindow(word) UpdateWindow16 125 pascal16 InvalidateRect(word ptr word) InvalidateRect16 126 pascal16 InvalidateRgn(word word word) InvalidateRgn16 @@ -531,7 +531,7 @@ rsrc resources/version16.res 821 pascal16 TranslateMessage32(ptr word) TranslateMessage32_16 #821 stub IsDialogMessage32 # FIXME: two ordinal 821??? 822 pascal DispatchMessage32(ptr word) DispatchMessage32_16 -823 pascal16 CallMsgFilter32(segptr word word) CallMsgFilter32_16 +823 pascal16 CallMsgFilter32(ptr word word) CallMsgFilter32_16 825 stub PostMessage32 826 stub PostThreadMessage32 827 pascal16 MessageBoxIndirect(ptr) MessageBoxIndirect16 diff --git a/dlls/user/user32.spec b/dlls/user/user32.spec index 1ecc0792f52..02d4af0a54b 100644 --- a/dlls/user/user32.spec +++ b/dlls/user/user32.spec @@ -686,9 +686,7 @@ init UserClientDllInitialize @ cdecl CLIPBOARD_LookupFormat(long) CLIPBOARD_LookupFormat @ cdecl CLIPBOARD_ReleaseOwner() CLIPBOARD_ReleaseOwner @ cdecl DCE_InvalidateDCE(long ptr) DCE_InvalidateDCE -@ cdecl HOOK_CallHooksA(long long long long) HOOK_CallHooksA -@ cdecl HOOK_CallHooksW(long long long long) HOOK_CallHooksW -@ cdecl HOOK_IsHooked(long) HOOK_IsHooked +@ cdecl HOOK_CallHooks(long long long long) HOOK_CallHooks @ cdecl NC_GetInsideRect(long ptr) NC_GetInsideRect @ cdecl NC_HandleNCHitTest(long long long) NC_HandleNCHitTest @ cdecl NC_HandleSetCursor(long long long) NC_HandleSetCursor diff --git a/dlls/user/user_main.c b/dlls/user/user_main.c index b883b671bc6..714898f4a98 100644 --- a/dlls/user/user_main.c +++ b/dlls/user/user_main.c @@ -31,7 +31,6 @@ #include "cursoricon.h" #include "global.h" #include "input.h" -#include "hook.h" #include "message.h" #include "queue.h" #include "spy.h" @@ -294,7 +293,6 @@ static void thread_detach(void) if (hQueue) { TIMER_RemoveThreadTimers(); - HOOK_FreeQueueHooks(); WIN_DestroyThreadWindows( GetDesktopWindow() ); QUEUE_DeleteMsgQueue(); } @@ -309,7 +307,7 @@ static void thread_detach(void) if (GetModuleUsage16( hModule ) <= 1) { /* ModuleUnload() in "Internals" */ - HOOK_FreeModuleHooks( hModule ); + /* HOOK_FreeModuleHooks( hModule ); */ CLASS_FreeModuleClasses( hModule ); CURSORICON_FreeModuleIcons( hModule ); } diff --git a/dlls/x11drv/window.c b/dlls/x11drv/window.c index 190bb19fd64..d2b75b091f0 100644 --- a/dlls/x11drv/window.c +++ b/dlls/x11drv/window.c @@ -39,7 +39,6 @@ #include "win.h" #include "winpos.h" #include "dce.h" -#include "hook.h" #include "mwm.h" WINE_DEFAULT_DEBUG_CHANNEL(x11drv); @@ -854,6 +853,7 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode ) WND *wndPtr; struct x11drv_win_data *data; RECT rect; + CBT_CREATEWNDA cbtc; BOOL ret = FALSE; if (cs->cx > 65535) @@ -897,29 +897,16 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode ) /* Call the WH_CBT hook */ - hwndLinkAfter = ((cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD) - ? HWND_BOTTOM : HWND_TOP; + hwndLinkAfter = ((cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD) ? HWND_BOTTOM : HWND_TOP; - if (HOOK_IsHooked( WH_CBT )) + cbtc.lpcs = cs; + cbtc.hwndInsertAfter = hwndLinkAfter; + if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) { - CBT_CREATEWNDA cbtc; - LRESULT lret; - - cbtc.lpcs = cs; - cbtc.hwndInsertAfter = hwndLinkAfter; - lret = (unicode) ? HOOK_CallHooksW(WH_CBT, HCBT_CREATEWND, - (WPARAM)hwnd, (LPARAM)&cbtc) - : HOOK_CallHooksA(WH_CBT, HCBT_CREATEWND, - (WPARAM)hwnd, (LPARAM)&cbtc); - if (lret) - { - TRACE("CBT-hook returned !0\n"); - goto failed; - } + TRACE("CBT-hook returned !0\n"); + goto failed; } - - /* Send the WM_GETMINMAXINFO message and fix the size if needed */ if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD))) { diff --git a/dlls/x11drv/winpos.c b/dlls/x11drv/winpos.c index 17f1189a1d5..5c2ee1c20d9 100644 --- a/dlls/x11drv/winpos.c +++ b/dlls/x11drv/winpos.c @@ -33,7 +33,6 @@ #include "winerror.h" #include "x11drv.h" -#include "hook.h" #include "win.h" #include "winpos.h" #include "dce.h" @@ -1122,7 +1121,7 @@ UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect ) wpl.length = sizeof(wpl); GetWindowPlacement( hwnd, &wpl ); - if (HOOK_CallHooksA( WH_CBT, HCBT_MINMAX, (WPARAM)hwnd, cmd )) + if (HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)hwnd, cmd, TRUE )) return SWP_NOSIZE | SWP_NOMOVE; if (IsIconic( hwnd )) @@ -2094,7 +2093,8 @@ void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam ) } wine_tsx11_unlock(); - if (HOOK_CallHooksA( WH_CBT, HCBT_MOVESIZE, (WPARAM)hwnd, (LPARAM)&sizingRect )) moved = FALSE; + if (HOOK_CallHooks( WH_CBT, HCBT_MOVESIZE, (WPARAM)hwnd, (LPARAM)&sizingRect, TRUE )) + moved = FALSE; SendMessageA( hwnd, WM_EXITSIZEMOVE, 0, 0 ); SendMessageA( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L); diff --git a/include/hook.h b/include/hook.h deleted file mode 100644 index c91edf12c7f..00000000000 --- a/include/hook.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Windows hook definitions - * - * Copyright 1994 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_HOOK_H -#define __WINE_HOOK_H - -#include "windef.h" - -#define HOOK_WIN16 0x00 -#define HOOK_WIN32A 0x01 -#define HOOK_WIN32W 0x02 -#define HOOK_INUSE 0x80 - - -/* hook type mask */ -#define HOOK_MAPTYPE (HOOK_WIN16 | HOOK_WIN32A | HOOK_WIN32W) - -extern BOOL HOOK_IsHooked( INT16 id ); -extern LRESULT HOOK_CallHooks16( INT16 id, INT16 code, WPARAM16 wParam, - LPARAM lParam ); -extern LRESULT HOOK_CallHooksA( INT id, INT code, WPARAM wParam, - LPARAM lParam ); -extern LRESULT HOOK_CallHooksW( INT id, INT code, WPARAM wParam, - LPARAM lParam ); -extern void HOOK_FreeModuleHooks( HMODULE16 hModule ); -extern void HOOK_FreeQueueHooks(void); - -#endif /* __WINE_HOOK_H */ diff --git a/include/queue.h b/include/queue.h index 1aeb917fa35..3b2f1d60d28 100644 --- a/include/queue.h +++ b/include/queue.h @@ -27,9 +27,8 @@ #include "winuser.h" #include "thread.h" -#define WH_NB_HOOKS (WH_MAXHOOK-WH_MINHOOK+1) - struct received_message_info; +struct hook16_queue_info; /* Message queue */ typedef struct tagMESSAGEQUEUE @@ -37,7 +36,9 @@ typedef struct tagMESSAGEQUEUE HQUEUE16 self; /* Handle to self (was: reserved) */ HANDLE server_queue; /* Handle to server-side queue */ DWORD recursion_count; /* Counter to prevent infinite SendMessage recursion */ + HHOOK hook; /* Current hook */ struct received_message_info *receive_info; /* Info about message being currently received */ + struct hook16_queue_info *hook16_info; /* Opaque pointer for 16-bit hook support */ DWORD magic; /* magic number should be QUEUE_MAGIC */ DWORD lockCount; /* reference counter */ @@ -48,9 +49,6 @@ typedef struct tagMESSAGEQUEUE HCURSOR cursor; /* current cursor */ INT cursor_count; /* cursor show count */ - - HANDLE16 hCurHook; /* Current hook */ - HANDLE16 hooks[WH_NB_HOOKS]; /* Task hooks list */ } MESSAGEQUEUE; diff --git a/include/user.h b/include/user.h index d8532f7ac0a..459db86f9b5 100644 --- a/include/user.h +++ b/include/user.h @@ -137,6 +137,10 @@ extern WINE_LOOK TWEAK_WineLook; /* gray brush cache */ extern HBRUSH CACHE_GetPattern55AABrush(void); +/* hook.c */ +extern LRESULT HOOK_CallHooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL unicode ); +extern BOOL HOOK_IsHooked( INT id ); + /* syscolor.c */ extern HPEN SYSCOLOR_GetPen( INT index ); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 92b3819c85f..122747c05e8 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2866,6 +2866,80 @@ struct set_caret_info_reply #define SET_CARET_STATE 0x04 + +struct set_hook_request +{ + struct request_header __header; + int id; + thread_id_t tid; + void* proc; + int unicode; +}; +struct set_hook_reply +{ + struct reply_header __header; + user_handle_t handle; +}; + + + +struct remove_hook_request +{ + struct request_header __header; + user_handle_t handle; + int id; + void* proc; +}; +struct remove_hook_reply +{ + struct reply_header __header; +}; + + + +struct start_hook_chain_request +{ + struct request_header __header; + int id; +}; +struct start_hook_chain_reply +{ + struct reply_header __header; + user_handle_t handle; + void* proc; + int unicode; +}; + + + +struct finish_hook_chain_request +{ + struct request_header __header; + int id; +}; +struct finish_hook_chain_reply +{ + struct reply_header __header; +}; + + + +struct get_next_hook_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct get_next_hook_reply +{ + struct reply_header __header; + user_handle_t next; + int id; + void* proc; + int prev_unicode; + int next_unicode; +}; + + enum request { REQ_new_process, @@ -3032,6 +3106,11 @@ enum request REQ_set_capture_window, REQ_set_caret_window, REQ_set_caret_info, + REQ_set_hook, + REQ_remove_hook, + REQ_start_hook_chain, + REQ_finish_hook_chain, + REQ_get_next_hook, REQ_NB_REQUESTS }; @@ -3203,6 +3282,11 @@ union generic_request struct set_capture_window_request set_capture_window_request; struct set_caret_window_request set_caret_window_request; struct set_caret_info_request set_caret_info_request; + struct set_hook_request set_hook_request; + struct remove_hook_request remove_hook_request; + struct start_hook_chain_request start_hook_chain_request; + struct finish_hook_chain_request finish_hook_chain_request; + struct get_next_hook_request get_next_hook_request; }; union generic_reply { @@ -3372,8 +3456,13 @@ union generic_reply struct set_capture_window_reply set_capture_window_reply; struct set_caret_window_reply set_caret_window_reply; struct set_caret_info_reply set_caret_info_reply; + struct set_hook_reply set_hook_reply; + struct remove_hook_reply remove_hook_reply; + struct start_hook_chain_reply start_hook_chain_reply; + struct finish_hook_chain_reply finish_hook_chain_reply; + struct get_next_hook_reply get_next_hook_reply; }; -#define SERVER_PROTOCOL_VERSION 88 +#define SERVER_PROTOCOL_VERSION 89 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/include/wine/winuser16.h b/include/wine/winuser16.h index bc95c637851..c53f2e76293 100644 --- a/include/wine/winuser16.h +++ b/include/wine/winuser16.h @@ -632,8 +632,8 @@ UINT16 WINAPI ArrangeIconicWindows16(HWND16); HDWP16 WINAPI BeginDeferWindowPos16(INT16); HDC16 WINAPI BeginPaint16(HWND16,LPPAINTSTRUCT16); BOOL16 WINAPI BringWindowToTop16(HWND16); -BOOL16 WINAPI CallMsgFilter16(SEGPTR,INT16); -BOOL16 WINAPI CallMsgFilter32_16(SEGPTR,INT16,BOOL16); +BOOL16 WINAPI CallMsgFilter16(MSG16*,INT16); +BOOL16 WINAPI CallMsgFilter32_16(MSG32_16*,INT16,BOOL16); LRESULT WINAPI CallNextHookEx16(HHOOK,INT16,WPARAM16,LPARAM); LRESULT WINAPI CallWindowProc16(WNDPROC16,HWND16,UINT16,WPARAM16,LPARAM); BOOL16 WINAPI ChangeClipboardChain16(HWND16,HWND16); diff --git a/server/Makefile.in b/server/Makefile.in index 6486a5d8aaa..91dde186829 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -18,6 +18,7 @@ C_SRCS = \ event.c \ file.c \ handle.c \ + hook.c \ main.c \ mapping.c \ mutex.c \ diff --git a/server/hook.c b/server/hook.c new file mode 100644 index 00000000000..aa1e493ab26 --- /dev/null +++ b/server/hook.c @@ -0,0 +1,316 @@ +/* + * Server-side window hooks support + * + * Copyright (C) 2002 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include + +#include "winbase.h" +#include "winuser.h" + +#include "object.h" +#include "request.h" +#include "user.h" + +struct hook_table; + +struct hook +{ + struct list chain; /* hook chain entry */ + user_handle_t handle; /* user handle for this hook */ + struct thread *thread; /* thread owning the hook */ + int index; /* hook table index */ + void *proc; /* hook function */ + int unicode; /* is it a unicode hook? */ +}; + +#define NB_HOOKS (WH_MAXHOOK-WH_MINHOOK+1) +#define HOOK_ENTRY(p) LIST_ENTRY( (p), struct hook, chain ) + +struct hook_table +{ + struct object obj; /* object header */ + struct list hooks[NB_HOOKS]; /* array of hook chains */ + int counts[NB_HOOKS]; /* use counts for each hook chain */ +}; + +static void hook_table_dump( struct object *obj, int verbose ); +static void hook_table_destroy( struct object *obj ); + +static const struct object_ops hook_table_ops = +{ + sizeof(struct hook_table), /* size */ + hook_table_dump, /* dump */ + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* satisfied */ + NULL, /* get_poll_events */ + NULL, /* poll_event */ + no_get_fd, /* get_fd */ + no_flush, /* flush */ + no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ + hook_table_destroy /* destroy */ +}; + + +/* create a new hook table */ +static struct hook_table *alloc_hook_table(void) +{ + struct hook_table *table; + int i; + + if ((table = alloc_object( &hook_table_ops, -1 ))) + { + for (i = 0; i < NB_HOOKS; i++) + { + list_init( &table->hooks[i] ); + table->counts[i] = 0; + } + } + return table; +} + +/* create a new hook and add it to the specified table */ +static struct hook *add_hook( struct thread *thread, int index ) +{ + struct hook *hook; + struct hook_table *table = thread->hooks; + + if (!table) + { + if (!(table = alloc_hook_table())) return NULL; + thread->hooks = table; + } + if (!(hook = mem_alloc( sizeof(*hook) ))) return NULL; + + if (!(hook->handle = alloc_user_handle( hook, USER_HOOK ))) + { + free( hook ); + return NULL; + } + hook->thread = thread ? (struct thread *)grab_object( thread ) : NULL; + hook->index = index; + list_add_head( &table->hooks[index], &hook->chain ); + return hook; +} + +/* free a hook, removing it from its chain */ +static void free_hook( struct hook *hook ) +{ + free_user_handle( hook->handle ); + if (hook->thread) release_object( hook->thread ); + list_remove( &hook->chain ); + free( hook ); +} + +/* find a hook from its index and proc */ +static struct hook *find_hook( struct thread *thread, int index, void *proc ) +{ + struct list *p; + struct hook_table *table = thread->hooks; + + if (table) + { + LIST_FOR_EACH( p, &table->hooks[index] ) + { + struct hook *hook = HOOK_ENTRY( p ); + if (hook->proc == proc) return hook; + } + } + return NULL; +} + +/* get the hook table that a given hook belongs to */ +inline static struct hook_table *get_table( struct hook *hook ) +{ + return hook->thread->hooks; +} + +/* get the first hook in the chain */ +inline static struct hook *get_first_hook( struct hook_table *table, int index ) +{ + struct list *elem = list_head( &table->hooks[index] ); + return elem ? HOOK_ENTRY( elem ) : NULL; +} + +/* find the next hook in the chain, skipping the deleted ones */ +static struct hook *get_next_hook( struct hook *hook ) +{ + struct hook_table *table = get_table( hook ); + struct hook *next; + + while ((next = HOOK_ENTRY( list_next( &table->hooks[hook->index], &hook->chain ) ))) + { + if (next->proc) break; + } + return next; +} + +static void hook_table_dump( struct object *obj, int verbose ) +{ +/* struct hook_table *table = (struct hook_table *)obj; */ + fprintf( stderr, "Hook table\n" ); +} + +static void hook_table_destroy( struct object *obj ) +{ + int i; + struct hook *hook; + struct hook_table *table = (struct hook_table *)obj; + + for (i = 0; i < NB_HOOKS; i++) + { + while ((hook = get_first_hook( table, i )) != NULL) free_hook( hook ); + } +} + +/* remove a hook, freeing it if the chain is not in use */ +static void remove_hook( struct hook *hook ) +{ + struct hook_table *table = get_table( hook ); + if (table->counts[hook->index]) + hook->proc = NULL; /* chain is in use, just mark it and return */ + else + free_hook( hook ); +} + +/* release a hook chain, removing deleted hooks if the use count drops to 0 */ +static void release_hook_chain( struct hook_table *table, int index ) +{ + if (!table->counts[index]) /* use count shouldn't already be 0 */ + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + if (!--table->counts[index]) + { + struct hook *hook = get_first_hook( table, index ); + while (hook) + { + struct hook *next = HOOK_ENTRY( list_next( &table->hooks[hook->index], &hook->chain ) ); + if (!hook->proc) free_hook( hook ); + hook = next; + } + } +} + + +/* set a window hook */ +DECL_HANDLER(set_hook) +{ + struct thread *thread; + struct hook *hook; + + if (!req->proc || req->id < WH_MINHOOK || req->id > WH_MAXHOOK) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + if (!(thread = get_thread_from_id( req->tid ))) return; + + if ((hook = add_hook( thread, req->id - WH_MINHOOK ))) + { + hook->proc = req->proc; + hook->unicode = req->unicode; + reply->handle = hook->handle; + } + release_object( thread ); +} + + +/* remove a window hook */ +DECL_HANDLER(remove_hook) +{ + struct hook *hook; + + if (req->handle) hook = get_user_object( req->handle, USER_HOOK ); + else + { + if (!req->proc || req->id < WH_MINHOOK || req->id > WH_MAXHOOK) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + if (!(hook = find_hook( current, req->id - WH_MINHOOK, req->proc ))) + set_error( STATUS_INVALID_PARAMETER ); + } + if (hook) remove_hook( hook ); +} + + +/* start calling a hook chain */ +DECL_HANDLER(start_hook_chain) +{ + struct hook *hook; + struct hook_table *table = current->hooks; + + if (req->id < WH_MINHOOK || req->id > WH_MAXHOOK) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + if (!table) return; /* no hook set */ + if (!(hook = get_first_hook( table, req->id - WH_MINHOOK ))) return; /* no hook set */ + reply->handle = hook->handle; + reply->proc = hook->proc; + reply->unicode = hook->unicode; + table->counts[hook->index]++; +} + + +/* finished calling a hook chain */ +DECL_HANDLER(finish_hook_chain) +{ + struct hook_table *table = current->hooks; + int index = req->id - WH_MINHOOK; + + if (req->id < WH_MINHOOK || req->id > WH_MAXHOOK) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + if (table) release_hook_chain( table, index ); +} + + +/* get the next hook to call */ +DECL_HANDLER(get_next_hook) +{ + struct hook *hook, *next; + + if (!(hook = get_user_object( req->handle, USER_HOOK ))) return; + if (hook->thread != current) + { + set_error( STATUS_INVALID_HANDLE ); + return; + } + if ((next = get_next_hook( hook ))) + { + reply->next = next->handle; + reply->id = next->index + WH_MINHOOK; + reply->proc = next->proc; + reply->prev_unicode = hook->unicode; + reply->next_unicode = next->unicode; + } +} diff --git a/server/list.h b/server/list.h index b4a4c1f743f..fcf687e3e66 100644 --- a/server/list.h +++ b/server/list.h @@ -52,6 +52,34 @@ inline static void list_remove( struct list *elem ) elem->prev->next = elem->next; } +/* get the next element */ +inline static struct list *list_next( struct list *list, struct list *elem ) +{ + struct list *ret = elem->next; + if (elem->next == list) ret = NULL; + return ret; +} + +/* get the previous element */ +inline static struct list *list_prev( struct list *list, struct list *elem ) +{ + struct list *ret = elem->prev; + if (elem->prev == list) ret = NULL; + return ret; +} + +/* get the first element */ +inline static struct list *list_head( struct list *list ) +{ + return list_next( list, list ); +} + +/* get the last element */ +inline static struct list *list_tail( struct list *list ) +{ + return list_prev( list, list ); +} + /* initialize a list */ inline static void list_init( struct list *list ) { diff --git a/server/protocol.def b/server/protocol.def index 325d62c4fda..38c91c40937 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2004,3 +2004,50 @@ enum message_type #define SET_CARET_POS 0x01 /* set the caret position from x,y */ #define SET_CARET_HIDE 0x02 /* increment the caret hide count */ #define SET_CARET_STATE 0x04 /* set the caret on/off state */ + + +/* Set a window hook */ +@REQ(set_hook) + int id; /* id of the hook */ + thread_id_t tid; /* id of thread to set the hook into */ + void* proc; /* hook procedure */ + int unicode; /* is it a unicode hook? */ +@REPLY + user_handle_t handle; /* handle to the hook */ +@END + + +/* Remove a window hook */ +@REQ(remove_hook) + user_handle_t handle; /* handle to the hook */ + int id; /* id of the hook if handle is 0 */ + void* proc; /* hook procedure if handle is 0 */ +@END + + +/* Start calling a hook chain */ +@REQ(start_hook_chain) + int id; /* id of the hook */ +@REPLY + user_handle_t handle; /* handle to the next hook */ + void* proc; /* hook procedure */ + int unicode; /* is it a unicode hook? */ +@END + + +/* Finished calling a hook chain */ +@REQ(finish_hook_chain) + int id; /* id of the hook */ +@END + + +/* Get the next hook to call */ +@REQ(get_next_hook) + user_handle_t handle; /* handle to the current hook */ +@REPLY + user_handle_t next; /* handle to the next hook */ + int id; /* id of the next hook */ + void* proc; /* next hook procedure */ + int prev_unicode; /* was the previous a unicode hook? */ + int next_unicode; /* is the next a unicode hook? */ +@END diff --git a/server/request.h b/server/request.h index 7051e889a0d..f5fd97d4d41 100644 --- a/server/request.h +++ b/server/request.h @@ -267,6 +267,11 @@ DECL_HANDLER(set_active_window); DECL_HANDLER(set_capture_window); DECL_HANDLER(set_caret_window); DECL_HANDLER(set_caret_info); +DECL_HANDLER(set_hook); +DECL_HANDLER(remove_hook); +DECL_HANDLER(start_hook_chain); +DECL_HANDLER(finish_hook_chain); +DECL_HANDLER(get_next_hook); #ifdef WANT_REQUEST_HANDLERS @@ -437,6 +442,11 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_set_capture_window, (req_handler)req_set_caret_window, (req_handler)req_set_caret_info, + (req_handler)req_set_hook, + (req_handler)req_remove_hook, + (req_handler)req_start_hook_chain, + (req_handler)req_finish_hook_chain, + (req_handler)req_get_next_hook, }; #endif /* WANT_REQUEST_HANDLERS */ diff --git a/server/thread.c b/server/thread.c index 0338b8b22c0..c29ba46dcf1 100644 --- a/server/thread.c +++ b/server/thread.c @@ -110,6 +110,7 @@ inline static void init_thread_structure( struct thread *thread ) thread->debug_ctx = NULL; thread->debug_event = NULL; thread->queue = NULL; + thread->hooks = NULL; thread->info = NULL; thread->wait = NULL; thread->system_apc.head = NULL; @@ -187,6 +188,7 @@ static void cleanup_thread( struct thread *thread ) if (thread->request_fd != -1) close( thread->request_fd ); if (thread->reply_fd != -1) close( thread->reply_fd ); if (thread->wait_fd != -1) close( thread->wait_fd ); + if (thread->hooks) release_object( thread->hooks ); free_msg_queue( thread ); destroy_thread_windows( thread ); for (i = 0; i < MAX_INFLIGHT_FDS; i++) @@ -202,6 +204,7 @@ static void cleanup_thread( struct thread *thread ) thread->request_fd = -1; thread->reply_fd = -1; thread->wait_fd = -1; + thread->hooks = NULL; if (thread == booting_thread) /* killing booting thread */ { diff --git a/server/thread.h b/server/thread.h index fed326b6076..0c029014d85 100644 --- a/server/thread.h +++ b/server/thread.h @@ -33,6 +33,7 @@ struct debug_ctx; struct debug_event; struct startup_info; struct msg_queue; +struct hook_table; enum run_state { @@ -66,6 +67,7 @@ struct thread struct debug_ctx *debug_ctx; /* debugger context if this thread is a debugger */ struct debug_event *debug_event; /* debug event being sent to debugger */ struct msg_queue *queue; /* message queue */ + struct hook_table *hooks; /* hooks table */ struct startup_info *info; /* startup info for child process */ struct thread_wait *wait; /* current wait condition if sleeping */ struct apc_queue system_apc; /* queue of system async procedure calls */ diff --git a/server/trace.c b/server/trace.c index f06d2b62165..9d89ef7e27e 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2282,6 +2282,57 @@ static void dump_set_caret_info_reply( const struct set_caret_info_reply *req ) fprintf( stderr, " old_state=%d", req->old_state ); } +static void dump_set_hook_request( const struct set_hook_request *req ) +{ + fprintf( stderr, " id=%d,", req->id ); + fprintf( stderr, " tid=%08x,", req->tid ); + fprintf( stderr, " proc=%p,", req->proc ); + fprintf( stderr, " unicode=%d", req->unicode ); +} + +static void dump_set_hook_reply( const struct set_hook_reply *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_remove_hook_request( const struct remove_hook_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " id=%d,", req->id ); + fprintf( stderr, " proc=%p", req->proc ); +} + +static void dump_start_hook_chain_request( const struct start_hook_chain_request *req ) +{ + fprintf( stderr, " id=%d", req->id ); +} + +static void dump_start_hook_chain_reply( const struct start_hook_chain_reply *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " proc=%p,", req->proc ); + fprintf( stderr, " unicode=%d", req->unicode ); +} + +static void dump_finish_hook_chain_request( const struct finish_hook_chain_request *req ) +{ + fprintf( stderr, " id=%d", req->id ); +} + +static void dump_get_next_hook_request( const struct get_next_hook_request *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_get_next_hook_reply( const struct get_next_hook_reply *req ) +{ + fprintf( stderr, " next=%p,", req->next ); + fprintf( stderr, " id=%d,", req->id ); + fprintf( stderr, " proc=%p,", req->proc ); + fprintf( stderr, " prev_unicode=%d,", req->prev_unicode ); + fprintf( stderr, " next_unicode=%d", req->next_unicode ); +} + static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_new_process_request, (dump_func)dump_get_new_process_info_request, @@ -2447,6 +2498,11 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_set_capture_window_request, (dump_func)dump_set_caret_window_request, (dump_func)dump_set_caret_info_request, + (dump_func)dump_set_hook_request, + (dump_func)dump_remove_hook_request, + (dump_func)dump_start_hook_chain_request, + (dump_func)dump_finish_hook_chain_request, + (dump_func)dump_get_next_hook_request, }; static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { @@ -2614,6 +2670,11 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_set_capture_window_reply, (dump_func)dump_set_caret_window_reply, (dump_func)dump_set_caret_info_reply, + (dump_func)dump_set_hook_reply, + (dump_func)0, + (dump_func)dump_start_hook_chain_reply, + (dump_func)0, + (dump_func)dump_get_next_hook_reply, }; static const char * const req_names[REQ_NB_REQUESTS] = { @@ -2781,6 +2842,11 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "set_capture_window", "set_caret_window", "set_caret_info", + "set_hook", + "remove_hook", + "start_hook_chain", + "finish_hook_chain", + "get_next_hook", }; /* ### make_requests end ### */ diff --git a/server/user.h b/server/user.h index c153d782d58..f70cfea241c 100644 --- a/server/user.h +++ b/server/user.h @@ -29,7 +29,8 @@ struct msg_queue; enum user_object { - USER_WINDOW = 1 + USER_WINDOW = 1, + USER_HOOK }; /* user handles functions */ diff --git a/windows/hook.c b/windows/hook.c deleted file mode 100644 index 1517e9188f8..00000000000 --- a/windows/hook.c +++ /dev/null @@ -1,1236 +0,0 @@ -/* - * Windows hook functions - * - * Copyright 1994, 1995 Alexandre Julliard - * 1996 Andrew Lewycky - * - * Based on investigations by Alex Korobka - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Warning! - * A HHOOK is a 32-bit handle for compatibility with Windows 3.0 where it was - * a pointer to the next function. Now it is in fact composed of a USER heap - * handle in the low 16 bits and of a HOOK_MAGIC value in the high 16 bits. - */ - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "wine/winuser16.h" -#include "wine/winbase16.h" -#include "wownt32.h" -#include "hook.h" -#include "win.h" -#include "queue.h" -#include "user.h" -#include "heap.h" -#include "struct32.h" -#include "winproc.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(hook); - -#include "pshpack1.h" - - /* Hook data (pointed to by a HHOOK) */ -typedef struct -{ - HANDLE16 next; /* 00 Next hook in chain */ - HOOKPROC proc; /* 02 Hook procedure (original) */ - INT16 id; /* 06 Hook id (WH_xxx) */ - HQUEUE16 ownerQueue; /* 08 Owner queue (0 for system hook) */ - HMODULE16 ownerModule; /* 0a Owner module */ - WORD flags; /* 0c flags */ -} HOOKDATA; - -#include "poppack.h" - -#define HOOK_MAGIC ((int)'H' | (int)'K' << 8) /* 'HK' */ -#define HHOOK_32(h) ((HHOOK)(h ? MAKELONG(h, HOOK_MAGIC) : 0)) -#define HHOOK_16(h) ((HANDLE16)((HIWORD(h) == HOOK_MAGIC) ? LOWORD(h) : 0)) - - /* This should probably reside in USER heap */ -static HANDLE16 HOOK_systemHooks[WH_NB_HOOKS] = { 0, }; - -/* ### start build ### */ -extern LONG CALLBACK HOOK_CallTo16_long_wwl(HOOKPROC16,WORD,WORD,LONG); -/* ### stop build ### */ - - -/*********************************************************************** - * call_hook_16 - */ -inline static LRESULT call_hook_16( HOOKPROC16 proc, INT id, INT code, WPARAM wparam, LPARAM lparam ) -{ - LRESULT ret = HOOK_CallTo16_long_wwl( proc, code, wparam, lparam ); - /* Grrr. While the hook procedure is supposed to have an LRESULT return - value even in Win16, it seems that for those hook types where the - return value is interpreted as BOOL, Windows doesn't actually check - the HIWORD ... Some buggy Win16 programs, notably WINFILE, rely on - that, because they neglect to clear DX ... */ - if (id != WH_JOURNALPLAYBACK) ret = LOWORD( ret ); - return ret; -} - - -/*********************************************************************** - * call_hook_16_to_32 - * - * Convert hook params to 32-bit and call 32-bit hook procedure - */ -static LRESULT call_hook_16_to_32( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam, - BOOL unicode ) -{ - LRESULT ret = 0; - - switch( id ) - { - case WH_MSGFILTER: - case WH_SYSMSGFILTER: - case WH_JOURNALRECORD: - { - MSG16 *msg16 = MapSL(lparam); - MSG msg32; - - STRUCT32_MSG16to32( msg16, &msg32 ); - ret = proc( code, wparam, (LPARAM)&msg32 ); - break; - } - - case WH_GETMESSAGE: - { - MSG16 *msg16 = MapSL(lparam); - MSG msg32; - - STRUCT32_MSG16to32( msg16, &msg32 ); - ret = proc( code, wparam, (LPARAM)&msg32 ); - STRUCT32_MSG32to16( &msg32, msg16 ); - break; - } - - case WH_JOURNALPLAYBACK: - { - EVENTMSG16 *em16 = MapSL(lparam); - EVENTMSG em32; - - em32.message = em16->message; - em32.paramL = em16->paramL; - em32.paramH = em16->paramH; - em32.time = em16->time; - em32.hwnd = 0; /* FIXME */ - ret = proc( code, wparam, (LPARAM)&em32 ); - break; - } - - case WH_CALLWNDPROC: - { - CWPSTRUCT16 *cwp16 = MapSL(lparam); - CWPSTRUCT cwp32; - - cwp32.hwnd = WIN_Handle32(cwp16->hwnd); - cwp32.lParam = cwp16->lParam; - - if (unicode) - WINPROC_MapMsg16To32W( cwp32.hwnd, cwp16->message, cwp16->wParam, - &cwp32.message, &cwp32.wParam, &cwp32.lParam ); - else - WINPROC_MapMsg16To32A( cwp32.hwnd, cwp16->message, cwp16->wParam, - &cwp32.message, &cwp32.wParam, &cwp32.lParam ); - - ret = proc( code, wparam, (LPARAM)&cwp32 ); - - if (unicode) - WINPROC_UnmapMsg16To32W( cwp32.hwnd, cwp32.message, cwp32.wParam, cwp32.lParam, 0 ); - else - WINPROC_UnmapMsg16To32A( cwp32.hwnd, cwp32.message, cwp32.wParam, cwp32.lParam, 0 ); - break; - } - - case WH_CBT: - switch (code) - { - case HCBT_CREATEWND: - { - CBT_CREATEWNDA cbtcw32; - CREATESTRUCTA cs32; - CBT_CREATEWND16 *cbtcw16 = MapSL(lparam); - CREATESTRUCT16 *cs16 = MapSL( (SEGPTR)cbtcw16->lpcs ); - - cbtcw32.lpcs = &cs32; - cbtcw32.hwndInsertAfter = WIN_Handle32( cbtcw16->hwndInsertAfter ); - STRUCT32_CREATESTRUCT16to32A( cs16, &cs32 ); - - if (unicode) - { - cs32.lpszName = (LPSTR)map_str_16_to_32W( cs16->lpszName ); - cs32.lpszClass = (LPSTR)map_str_16_to_32W( cs16->lpszClass ); - ret = proc( code, wparam, (LPARAM)&cbtcw32 ); - unmap_str_16_to_32W( (LPWSTR)cs32.lpszName ); - unmap_str_16_to_32W( (LPWSTR)cs32.lpszClass ); - } - else - { - cs32.lpszName = MapSL( cs16->lpszName ); - cs32.lpszClass = MapSL( cs16->lpszClass ); - ret = proc( code, wparam, (LPARAM)&cbtcw32 ); - } - cbtcw16->hwndInsertAfter = HWND_16( cbtcw32.hwndInsertAfter ); - break; - } - case HCBT_ACTIVATE: - { - CBTACTIVATESTRUCT16 *cas16 = MapSL(lparam); - CBTACTIVATESTRUCT cas32; - cas32.fMouse = cas16->fMouse; - cas32.hWndActive = WIN_Handle32(cas16->hWndActive); - ret = proc( code, wparam, (LPARAM)&cas32 ); - break; - } - case HCBT_CLICKSKIPPED: - { - MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam); - MOUSEHOOKSTRUCT ms32; - - ms32.pt.x = ms16->pt.x; - ms32.pt.y = ms16->pt.y; - /* wHitTestCode may be negative, so convince compiler to do - correct sign extension. Yay. :| */ - ms32.wHitTestCode = (INT)(INT16)ms16->wHitTestCode; - ms32.dwExtraInfo = ms16->dwExtraInfo; - ms32.hwnd = WIN_Handle32( ms16->hwnd ); - ret = proc( code, wparam, (LPARAM)&ms32 ); - break; - } - case HCBT_MOVESIZE: - { - RECT16 *rect16 = MapSL(lparam); - RECT rect32; - - CONV_RECT16TO32( rect16, &rect32 ); - ret = proc( code, wparam, (LPARAM)&rect32 ); - break; - } - } - break; - - case WH_MOUSE: - { - MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam); - MOUSEHOOKSTRUCT ms32; - - ms32.pt.x = ms16->pt.x; - ms32.pt.y = ms16->pt.y; - /* wHitTestCode may be negative, so convince compiler to do - correct sign extension. Yay. :| */ - ms32.wHitTestCode = (INT)((INT16)ms16->wHitTestCode); - ms32.dwExtraInfo = ms16->dwExtraInfo; - ms32.hwnd = WIN_Handle32(ms16->hwnd); - ret = proc( code, wparam, (LPARAM)&ms32 ); - break; - } - - case WH_DEBUG: - { - DEBUGHOOKINFO16 *dh16 = MapSL(lparam); - DEBUGHOOKINFO dh32; - - dh32.idThread = 0; /* FIXME */ - dh32.idThreadInstaller = 0; /* FIXME */ - dh32.lParam = dh16->lParam; /* FIXME Check for sign ext */ - dh32.wParam = dh16->wParam; - dh32.code = dh16->code; - - /* do sign extension if it was WH_MSGFILTER */ - if (wparam == 0xffff) wparam = WH_MSGFILTER; - ret = proc( code, wparam, (LPARAM)&dh32 ); - break; - } - - case WH_SHELL: - case WH_KEYBOARD: - ret = proc( code, wparam, lparam ); - break; - - case WH_HARDWARE: - case WH_FOREGROUNDIDLE: - case WH_CALLWNDPROCRET: - default: - FIXME("\t[%i] 16to32 translation unimplemented\n", id); - ret = proc( code, wparam, lparam ); - break; - } - return ret; -} - - -/*********************************************************************** - * call_hook_32_to_16 - * - * Convert hook params to 16-bit and call 16-bit hook procedure - */ -static LRESULT call_hook_32_to_16( HOOKPROC16 proc, INT id, INT code, WPARAM wparam, LPARAM lparam, - BOOL unicode ) -{ - LRESULT ret = 0; - - switch (id) - { - case WH_MSGFILTER: - case WH_SYSMSGFILTER: - case WH_JOURNALRECORD: - { - MSG *msg32 = (MSG *)lparam; - MSG16 msg16; - - STRUCT32_MSG32to16( msg32, &msg16 ); - lparam = MapLS( &msg16 ); - ret = call_hook_16( proc, id, code, wparam, lparam ); - UnMapLS( lparam ); - break; - } - - case WH_GETMESSAGE: - { - MSG *msg32 = (MSG *)lparam; - MSG16 msg16; - - STRUCT32_MSG32to16( msg32, &msg16 ); - lparam = MapLS( &msg16 ); - ret = call_hook_16( proc, id, code, wparam, lparam ); - UnMapLS( lparam ); - STRUCT32_MSG16to32( &msg16, msg32 ); - break; - } - - case WH_JOURNALPLAYBACK: - { - EVENTMSG *em32 = (EVENTMSG *)lparam; - EVENTMSG16 em16; - - em16.message = em32->message; - em16.paramL = em32->paramL; - em16.paramH = em32->paramH; - em16.time = em32->time; - lparam = MapLS( &em16 ); - ret = call_hook_16( proc, id, code, wparam, lparam ); - UnMapLS( lparam ); - break; - } - - case WH_CALLWNDPROC: - { - CWPSTRUCT *cwp32 = (CWPSTRUCT *)lparam; - CWPSTRUCT16 cwp16; - MSGPARAM16 mp16; - - cwp16.hwnd = HWND_16(cwp32->hwnd); - cwp16.lParam = cwp32->lParam; - - if (unicode) - WINPROC_MapMsg32WTo16( cwp32->hwnd, cwp32->message, cwp32->wParam, - &cwp16.message, &cwp16.wParam, &cwp16.lParam ); - else - WINPROC_MapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam, - &cwp16.message, &cwp16.wParam, &cwp16.lParam ); - - lparam = MapLS( &cwp16 ); - ret = call_hook_16( proc, id, code, wparam, lparam ); - UnMapLS( lparam ); - - mp16.wParam = cwp16.wParam; - mp16.lParam = cwp16.lParam; - mp16.lResult = 0; - if (unicode) - WINPROC_UnmapMsg32WTo16( cwp32->hwnd, cwp32->message, cwp32->wParam, - cwp32->lParam, &mp16 ); - else - WINPROC_UnmapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam, - cwp32->lParam, &mp16 ); - break; - } - - case WH_CBT: - switch (code) - { - case HCBT_CREATEWND: - { - CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lparam; - CBT_CREATEWND16 cbtcw16; - CREATESTRUCT16 cs16; - - STRUCT32_CREATESTRUCT32Ato16( cbtcw32->lpcs, &cs16 ); - cbtcw16.lpcs = (CREATESTRUCT16 *)MapLS( &cs16 ); - cbtcw16.hwndInsertAfter = HWND_16( cbtcw32->hwndInsertAfter ); - lparam = MapLS( &cbtcw16 ); - - if (unicode) - { - cs16.lpszName = map_str_32W_to_16( (LPWSTR)cbtcw32->lpcs->lpszName ); - cs16.lpszClass = map_str_32W_to_16( (LPWSTR)cbtcw32->lpcs->lpszClass ); - ret = call_hook_16( proc, id, code, wparam, lparam ); - unmap_str_32W_to_16( cs16.lpszName ); - unmap_str_32W_to_16( cs16.lpszClass ); - } - else - { - cs16.lpszName = MapLS( cbtcw32->lpcs->lpszName ); - cs16.lpszClass = MapLS( cbtcw32->lpcs->lpszClass ); - ret = call_hook_16( proc, id, code, wparam, lparam ); - UnMapLS( cs16.lpszName ); - UnMapLS( cs16.lpszClass ); - } - cbtcw32->hwndInsertAfter = WIN_Handle32( cbtcw16.hwndInsertAfter ); - UnMapLS( (SEGPTR)cbtcw16.lpcs ); - UnMapLS( lparam ); - break; - } - - case HCBT_ACTIVATE: - { - CBTACTIVATESTRUCT *cas32 = (CBTACTIVATESTRUCT *)lparam; - CBTACTIVATESTRUCT16 cas16; - - cas16.fMouse = cas32->fMouse; - cas16.hWndActive = HWND_16( cas32->hWndActive ); - - lparam = MapLS( &cas16 ); - ret = call_hook_16( proc, id, code, wparam, lparam ); - UnMapLS( lparam ); - break; - } - case HCBT_CLICKSKIPPED: - { - MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lparam; - MOUSEHOOKSTRUCT16 ms16; - - ms16.pt.x = ms32->pt.x; - ms16.pt.y = ms32->pt.y; - ms16.hwnd = HWND_16( ms32->hwnd ); - ms16.wHitTestCode = ms32->wHitTestCode; - ms16.dwExtraInfo = ms32->dwExtraInfo; - - lparam = MapLS( &ms16 ); - ret = call_hook_16( proc, id, code, wparam, lparam ); - UnMapLS( lparam ); - break; - } - case HCBT_MOVESIZE: - { - RECT *rect32 = (RECT *)lparam; - RECT16 rect16; - - CONV_RECT32TO16( rect32, &rect16 ); - lparam = MapLS( &rect16 ); - ret = call_hook_16( proc, id, code, wparam, lparam ); - UnMapLS( lparam ); - break; - } - } - break; - - case WH_MOUSE: - { - MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lparam; - MOUSEHOOKSTRUCT16 ms16; - - ms16.pt.x = ms32->pt.x; - ms16.pt.y = ms32->pt.y; - ms16.hwnd = HWND_16( ms32->hwnd ); - ms16.wHitTestCode = ms32->wHitTestCode; - ms16.dwExtraInfo = ms32->dwExtraInfo; - - lparam = MapLS( &ms16 ); - ret = call_hook_16( proc, id, code, wparam, lparam ); - UnMapLS( lparam ); - break; - } - - case WH_DEBUG: - { - DEBUGHOOKINFO *dh32 = (DEBUGHOOKINFO *)lparam; - DEBUGHOOKINFO16 dh16; - - dh16.hModuleHook = 0; /* FIXME */ - dh16.reserved = 0; - dh16.lParam = dh32->lParam; - dh16.wParam = dh32->wParam; - dh16.code = dh32->code; - - lparam = MapLS( &dh16 ); - ret = call_hook_16( proc, id, code, wparam, lparam ); - UnMapLS( lparam ); - break; - } - - case WH_SHELL: - case WH_KEYBOARD: - ret = call_hook_16( proc, id, code, wparam, lparam ); - break; - - case WH_HARDWARE: - case WH_FOREGROUNDIDLE: - case WH_CALLWNDPROCRET: - default: - FIXME("\t[%i] 32to16 translation unimplemented\n", id); - ret = call_hook_16( proc, id, code, wparam, lparam ); - break; - } - return ret; -} - - -/*********************************************************************** - * call_hook_32_to_32 - * - * Convert hook params to/from Unicode and call hook procedure - */ -static LRESULT call_hook_32_to_32( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam, - BOOL to_unicode ) -{ - if (id != WH_CBT || code != HCBT_CREATEWND) return proc( code, wparam, lparam ); - - if (to_unicode) /* ASCII to Unicode */ - { - CBT_CREATEWNDA *cbtcwA = (CBT_CREATEWNDA *)lparam; - CBT_CREATEWNDW cbtcwW; - CREATESTRUCTW csW; - LRESULT ret; - - cbtcwW.lpcs = &csW; - cbtcwW.hwndInsertAfter = cbtcwA->hwndInsertAfter; - csW = *(CREATESTRUCTW *)cbtcwA->lpcs; - - if (HIWORD(cbtcwA->lpcs->lpszName)) - csW.lpszName = HEAP_strdupAtoW( GetProcessHeap(), 0, cbtcwA->lpcs->lpszName ); - if (HIWORD(cbtcwA->lpcs->lpszClass)) - csW.lpszClass = HEAP_strdupAtoW( GetProcessHeap(), 0, cbtcwA->lpcs->lpszClass ); - ret = proc( code, wparam, (LPARAM)&cbtcwW ); - cbtcwA->hwndInsertAfter = cbtcwW.hwndInsertAfter; - if (HIWORD(csW.lpszName)) HeapFree( GetProcessHeap(), 0, (LPWSTR)csW.lpszName ); - if (HIWORD(csW.lpszClass)) HeapFree( GetProcessHeap(), 0, (LPWSTR)csW.lpszClass ); - return ret; - } - else /* Unicode to ASCII */ - { - CBT_CREATEWNDW *cbtcwW = (CBT_CREATEWNDW *)lparam; - CBT_CREATEWNDA cbtcwA; - CREATESTRUCTA csA; - LRESULT ret; - - cbtcwA.lpcs = &csA; - cbtcwA.hwndInsertAfter = cbtcwW->hwndInsertAfter; - csA = *(CREATESTRUCTA *)cbtcwW->lpcs; - - if (HIWORD(cbtcwW->lpcs->lpszName)) - csA.lpszName = HEAP_strdupWtoA( GetProcessHeap(), 0, cbtcwW->lpcs->lpszName ); - if (HIWORD(cbtcwW->lpcs->lpszClass)) - csA.lpszClass = HEAP_strdupWtoA( GetProcessHeap(), 0, cbtcwW->lpcs->lpszClass ); - ret = proc( code, wparam, (LPARAM)&cbtcwA ); - cbtcwW->hwndInsertAfter = cbtcwA.hwndInsertAfter; - if (HIWORD(csA.lpszName)) HeapFree( GetProcessHeap(), 0, (LPSTR)csA.lpszName ); - if (HIWORD(csA.lpszClass)) HeapFree( GetProcessHeap(), 0, (LPSTR)csA.lpszClass ); - return ret; - } -} - - -/*********************************************************************** - * call_hook - * - * Call a hook procedure. - */ -inline static LRESULT call_hook( HOOKDATA *data, INT fromtype, INT code, - WPARAM wparam, LPARAM lparam ) -{ - INT type = (data->flags & HOOK_MAPTYPE); - LRESULT ret; - - /* Suspend window structure locks before calling user code */ - int iWndsLocks = WIN_SuspendWndsLock(); - - if (type == HOOK_WIN16) - { - if (fromtype == HOOK_WIN16) /* 16->16 */ - ret = call_hook_16( (HOOKPROC16)data->proc, data->id, code, wparam, lparam ); - else /* 32->16 */ - ret = call_hook_32_to_16( (HOOKPROC16)data->proc, data->id, code, wparam, - lparam, (type == HOOK_WIN32W) ); - } - else if (fromtype == HOOK_WIN16) /* 16->32 */ - ret = call_hook_16_to_32( data->proc, data->id, code, wparam, - lparam, (type == HOOK_WIN32W) ); - else /* 32->32, check unicode */ - { - if (type == fromtype) - ret = data->proc( code, wparam, lparam ); - else - ret = call_hook_32_to_32( data->proc, data->id, code, wparam, - lparam, (type == HOOK_WIN32W) ); - } - WIN_RestoreWndsLock(iWndsLocks); - return ret; -} - - -/*********************************************************************** - * HOOK_GetNextHook - * - * Get the next hook of a given hook. - */ -static HHOOK HOOK_GetNextHook( HHOOK hook ) -{ - HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR( hook ); - - if (!data || !hook) return 0; - if (data->next) return HHOOK_32(data->next); - if (!data->ownerQueue) return 0; /* Already system hook */ - - /* Now start enumerating the system hooks */ - return HHOOK_32(HOOK_systemHooks[data->id - WH_MINHOOK]); -} - - -/*********************************************************************** - * HOOK_GetHook - * - * Get the first hook for a given type. - */ -static HHOOK HOOK_GetHook( INT16 id ) -{ - MESSAGEQUEUE *queue; - HANDLE16 handle = 0; - - if ((queue = QUEUE_Current()) != NULL) - handle = queue->hooks[id - WH_MINHOOK]; - if (!handle) handle = HOOK_systemHooks[id - WH_MINHOOK]; - return HHOOK_32(handle); -} - - -/*********************************************************************** - * HOOK_SetHook - * - * Install a given hook. - */ -static HHOOK HOOK_SetHook( INT16 id, LPVOID proc, INT type, - HMODULE16 hModule, DWORD dwThreadId ) -{ - HOOKDATA *data; - HANDLE16 handle; - HQUEUE16 hQueue = 0; - - if ((id < WH_MINHOOK) || (id > WH_MAXHOOK)) return 0; - - TRACE("Setting hook %d: %08x %04x %08lx\n", - id, (UINT)proc, hModule, dwThreadId ); - - /* Create task queue if none present */ - InitThreadInput16( 0, 0 ); - - if (id == WH_JOURNALPLAYBACK) EnableHardwareInput16(FALSE); - - if (dwThreadId) /* Task-specific hook */ - { - if ((id == WH_JOURNALRECORD) || (id == WH_JOURNALPLAYBACK) || - (id == WH_SYSMSGFILTER)) return 0; /* System-only hooks */ - if (!(hQueue = GetThreadQueue16( dwThreadId ))) - return 0; - } - - /* Create the hook structure */ - - if (!(handle = USER_HEAP_ALLOC( sizeof(HOOKDATA) ))) return 0; - data = (HOOKDATA *) USER_HEAP_LIN_ADDR( handle ); - data->proc = proc; - data->id = id; - data->ownerQueue = hQueue; - data->ownerModule = hModule; - data->flags = type; - - /* Insert it in the correct linked list */ - - if (hQueue) - { - MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ); - data->next = queue->hooks[id - WH_MINHOOK]; - queue->hooks[id - WH_MINHOOK] = handle; - QUEUE_Unlock( queue ); - } - else - { - data->next = HOOK_systemHooks[id - WH_MINHOOK]; - HOOK_systemHooks[id - WH_MINHOOK] = handle; - } - TRACE("Setting hook %d: ret=%04x [next=%04x]\n", - id, handle, data->next ); - - return HHOOK_32(handle); -} - - -/*********************************************************************** - * HOOK_RemoveHook - * - * Remove a hook from the list. - */ -static BOOL HOOK_RemoveHook( HHOOK hook ) -{ - HOOKDATA *data; - HANDLE16 *prevHandle; - - TRACE("Removing hook %04x\n", hook ); - - if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return FALSE; - if (data->flags & HOOK_INUSE) - { - /* Mark it for deletion later on */ - WARN("Hook still running, deletion delayed\n" ); - data->proc = (HOOKPROC)0; - return TRUE; - } - - if (data->id == WH_JOURNALPLAYBACK) EnableHardwareInput16(TRUE); - - /* Remove it from the linked list */ - - if (data->ownerQueue) - { - MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( data->ownerQueue ); - if (!queue) return FALSE; - prevHandle = &queue->hooks[data->id - WH_MINHOOK]; - QUEUE_Unlock( queue ); - } - else prevHandle = &HOOK_systemHooks[data->id - WH_MINHOOK]; - - while (*prevHandle && *prevHandle != HHOOK_16(hook)) - prevHandle = &((HOOKDATA *)USER_HEAP_LIN_ADDR(*prevHandle))->next; - - if (!*prevHandle) return FALSE; - *prevHandle = data->next; - - USER_HEAP_FREE( hook ); - return TRUE; -} - - -/*********************************************************************** - * HOOK_FindValidHook - */ -static HHOOK HOOK_FindValidHook( HHOOK hook ) -{ - HOOKDATA *data; - - for (;;) - { - if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR( hook ))) return 0; - if (data->proc) return hook; - hook = HHOOK_32(data->next); - } -} - -/*********************************************************************** - * HOOK_CallHook - * - * Call a hook procedure. - */ -static LRESULT HOOK_CallHook( HHOOK hook, INT fromtype, INT code, - WPARAM wParam, LPARAM lParam ) -{ - MESSAGEQUEUE *queue; - HANDLE16 prevHandle; - HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR( hook ); - LRESULT ret; - - if (!(queue = QUEUE_Current())) return 0; - prevHandle = queue->hCurHook; - queue->hCurHook = HHOOK_16(hook); - - TRACE("Calling hook %04x: %d %08x %08lx\n", hook, code, wParam, lParam ); - - data->flags |= HOOK_INUSE; - ret = call_hook( data, fromtype, code, wParam, lParam ); - data->flags &= ~HOOK_INUSE; - - TRACE("Ret hook %04x = %08lx\n", hook, ret ); - - queue->hCurHook = prevHandle; - if (!data->proc) HOOK_RemoveHook( hook ); - return ret; -} - -/*********************************************************************** - * Exported Functions & APIs - */ - -/*********************************************************************** - * HOOK_IsHooked - * - * Replacement for calling HOOK_GetHook from other modules. - */ -BOOL HOOK_IsHooked( INT16 id ) -{ - return HOOK_GetHook( id ) != 0; -} - - -/*********************************************************************** - * HOOK_CallHooks16 - * - * Call a hook chain. - */ -LRESULT HOOK_CallHooks16( INT16 id, INT16 code, WPARAM16 wParam, - LPARAM lParam ) -{ - HHOOK hook; - - if (!(hook = HOOK_GetHook( id ))) return 0; - if (!(hook = HOOK_FindValidHook(hook))) return 0; - return HOOK_CallHook( hook, HOOK_WIN16, code, wParam, lParam ); -} - -/*********************************************************************** - * HOOK_CallHooksA - * - * Call a hook chain. - */ -LRESULT HOOK_CallHooksA( INT id, INT code, WPARAM wParam, - LPARAM lParam ) -{ - HHOOK hook; - - if (!(hook = HOOK_GetHook( id ))) return 0; - if (!(hook = HOOK_FindValidHook(hook))) return 0; - return HOOK_CallHook( hook, HOOK_WIN32A, code, wParam, lParam ); -} - -/*********************************************************************** - * HOOK_CallHooksW - * - * Call a hook chain. - */ -LRESULT HOOK_CallHooksW( INT id, INT code, WPARAM wParam, - LPARAM lParam ) -{ - HHOOK hook; - - if (!(hook = HOOK_GetHook( id ))) return 0; - if (!(hook = HOOK_FindValidHook(hook))) return 0; - return HOOK_CallHook( hook, HOOK_WIN32W, code, wParam, - lParam ); -} - - -/*********************************************************************** - * HOOK_FreeModuleHooks - */ -void HOOK_FreeModuleHooks( HMODULE16 hModule ) -{ - /* remove all system hooks registered by this module */ - - HOOKDATA* hptr; - HANDLE16 handle, next; - int id; - - for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ ) - { - handle = HOOK_systemHooks[id - WH_MINHOOK]; - while( handle ) - if( (hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(handle)) ) - { - next = hptr->next; - if( hptr->ownerModule == hModule ) - { - hptr->flags &= HOOK_MAPTYPE; - HOOK_RemoveHook(HHOOK_32(handle)); - } - handle = next; - } - else handle = 0; - } -} - -/*********************************************************************** - * HOOK_FreeQueueHooks - */ -void HOOK_FreeQueueHooks(void) -{ - /* remove all hooks registered by the current queue */ - - HOOKDATA* hptr = NULL; - HHOOK hook, next; - int id; - - for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ ) - { - hook = HOOK_GetHook( id ); - while( hook ) - { - next = HOOK_GetNextHook(hook); - - hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR( hook ); - if( hptr && hptr->ownerQueue ) - { - hptr->flags &= HOOK_MAPTYPE; - HOOK_RemoveHook(hook); - } - hook = next; - } - } -} - - -/*********************************************************************** - * SetWindowsHook (USER.121) - */ -FARPROC16 WINAPI SetWindowsHook16( INT16 id, HOOKPROC16 proc ) -{ - HINSTANCE16 hInst = FarGetOwner16( HIWORD(proc) ); - - /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */ - HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0; - - return (FARPROC16)SetWindowsHookEx16( id, proc, hInst, hTask ); -} - -/*********************************************************************** - * SetWindowsHookA (USER32.@) - */ -HHOOK WINAPI SetWindowsHookA( INT id, HOOKPROC proc ) -{ - return SetWindowsHookExA( id, proc, 0, GetCurrentThreadId() ); -} - -/*********************************************************************** - * SetWindowsHookW (USER32.@) - */ -HHOOK WINAPI SetWindowsHookW( INT id, HOOKPROC proc ) -{ - return SetWindowsHookExW( id, proc, 0, GetCurrentThreadId() ); -} - - -/*********************************************************************** - * SetWindowsHookEx (USER.291) - */ -HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst, - HTASK16 hTask ) -{ - if (id == WH_DEBUG) - { - FIXME("WH_DEBUG is broken in 16-bit Windows.\n"); - return 0; - } - return HOOK_SetHook( id, proc, HOOK_WIN16, GetExePtr(hInst), (DWORD)hTask ); -} - -/*********************************************************************** - * SetWindowsHookExA (USER32.@) - */ -HHOOK WINAPI SetWindowsHookExA( INT id, HOOKPROC proc, HINSTANCE hInst, - DWORD dwThreadId ) -{ - return HOOK_SetHook( id, proc, HOOK_WIN32A, MapHModuleLS(hInst), dwThreadId ); -} - -/*********************************************************************** - * SetWindowsHookExW (USER32.@) - */ -HHOOK WINAPI SetWindowsHookExW( INT id, HOOKPROC proc, HINSTANCE hInst, - DWORD dwThreadId ) -{ - return HOOK_SetHook( id, proc, HOOK_WIN32W, MapHModuleLS(hInst), dwThreadId ); -} - - -/*********************************************************************** - * UnhookWindowsHook (USER.234) - */ -BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc ) -{ - return UnhookWindowsHook( id, (HOOKPROC)proc ); -} - -/*********************************************************************** - * UnhookWindowsHook (USER32.@) - */ -BOOL WINAPI UnhookWindowsHook( INT id, HOOKPROC proc ) -{ - HHOOK hook = HOOK_GetHook( id ); - - TRACE("%d %08lx\n", id, (DWORD)proc ); - - while (hook) - { - HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR( hook ); - if (data->proc == proc) break; - hook = HOOK_GetNextHook( hook ); - } - if (!hook) return FALSE; - return HOOK_RemoveHook( hook ); -} - - -/*********************************************************************** - * UnhookWindowsHookEx (USER.292) - */ -BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook ) -{ - return HOOK_RemoveHook(hhook); -} - -/*********************************************************************** - * UnhookWindowsHookEx (USER32.@) - */ -BOOL WINAPI UnhookWindowsHookEx( HHOOK hhook ) -{ - return HOOK_RemoveHook(hhook); -} - - -/*********************************************************************** - * CallNextHookEx (USER.293) - * - * I wouldn't have separated this into 16 and 32 bit versions, but I - * need a way to figure out if I need to do a mapping or not. - */ -LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wParam, - LPARAM lParam ) -{ - HHOOK next; - - if (!(next = HOOK_GetNextHook(hhook))) return 0; - - return HOOK_CallHook( next, HOOK_WIN16, code, wParam, lParam ); -} - - -/*********************************************************************** - * CallNextHookEx (USER32.@) - * - * There aren't ANSI and UNICODE versions of this. - */ -LRESULT WINAPI CallNextHookEx( HHOOK hhook, INT code, WPARAM wParam, - LPARAM lParam ) -{ - HHOOK next; - INT fromtype; /* figure out Ansi/Unicode */ - HOOKDATA *oldhook; - - if (!(next = HOOK_GetNextHook(hhook))) return 0; - - oldhook = (HOOKDATA *)USER_HEAP_LIN_ADDR( hhook ); - fromtype = oldhook->flags & HOOK_MAPTYPE; - - if (fromtype == HOOK_WIN16) - ERR("called from 16bit hook!\n"); - - return HOOK_CallHook( next, fromtype, code, wParam, lParam ); -} - - -/*********************************************************************** - * DefHookProc (USER.235) - */ -LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wParam, LPARAM lParam, - HHOOK *hhook ) -{ - /* Note: the *hhook parameter is never used, since we rely on the - * current hook value from the task queue to find the next hook. */ - MESSAGEQUEUE *queue; - - if (!(queue = QUEUE_Current())) return 0; - return CallNextHookEx16(HHOOK_32(queue->hCurHook), code, wParam, lParam); -} - - -/*********************************************************************** - * CallMsgFilter (USER.123) - */ -BOOL16 WINAPI CallMsgFilter16( SEGPTR msg, INT16 code ) -{ - if (HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) return TRUE; - return HOOK_CallHooks16( WH_MSGFILTER, code, 0, (LPARAM)msg ); -} - - -/*********************************************************************** - * CallMsgFilter32 (USER.823) - */ -BOOL16 WINAPI CallMsgFilter32_16( SEGPTR msg16_32, INT16 code, BOOL16 wHaveParamHigh ) -{ - MSG32_16 *lpmsg16_32 = MapSL(msg16_32); - - if (wHaveParamHigh == FALSE) - { - lpmsg16_32->wParamHigh = 0; - /* WARNING: msg16_32->msg has to be the first variable in the struct */ - return CallMsgFilter16(msg16_32, code); - } - else - { - MSG msg32; - BOOL16 ret; - - msg32.hwnd = WIN_Handle32( lpmsg16_32->msg.hwnd ); - msg32.message = lpmsg16_32->msg.message; - msg32.wParam = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh); - msg32.lParam = lpmsg16_32->msg.lParam; - msg32.time = lpmsg16_32->msg.time; - msg32.pt.x = lpmsg16_32->msg.pt.x; - msg32.pt.y = lpmsg16_32->msg.pt.y; - - ret = (BOOL16)CallMsgFilterA(&msg32, (INT)code); - - lpmsg16_32->msg.hwnd = HWND_16( msg32.hwnd ); - lpmsg16_32->msg.message = msg32.message; - lpmsg16_32->msg.wParam = LOWORD(msg32.wParam); - lpmsg16_32->msg.lParam = msg32.lParam; - lpmsg16_32->msg.time = msg32.time; - lpmsg16_32->msg.pt.x = msg32.pt.x; - lpmsg16_32->msg.pt.y = msg32.pt.y; - lpmsg16_32->wParamHigh = HIWORD(msg32.wParam); - - return ret; - } -} - - -/*********************************************************************** - * CallMsgFilterA (USER32.@) - * - * FIXME: There are ANSI and UNICODE versions of this, plus an unspecified - * version, plus USER (the 16bit one) has a CallMsgFilter32 function. - */ -BOOL WINAPI CallMsgFilterA( LPMSG msg, INT code ) -{ - if (HOOK_CallHooksA( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) - return TRUE; - return HOOK_CallHooksA( WH_MSGFILTER, code, 0, (LPARAM)msg ); -} - - -/*********************************************************************** - * CallMsgFilterW (USER32.@) - */ -BOOL WINAPI CallMsgFilterW( LPMSG msg, INT code ) -{ - if (HOOK_CallHooksW( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) - return TRUE; - return HOOK_CallHooksW( WH_MSGFILTER, code, 0, (LPARAM)msg ); -} - - -/*********************************************************************** - * SetWinEventHook [USER32.@] - * - * Set up an event hook for a set of events. - * - * PARAMS - * dwMin [I] Lowest event handled by pfnProc - * dwMax [I] Highest event handled by pfnProc - * hModule [I] DLL containing pfnProc - * pfnProc [I] Callback event hook function - * dwProcess [I] Process to get events from, or 0 for all processes - * dwThread [I] Thread to get events from, or 0 for all threads - * dwFlags [I] Flags indicating the status of pfnProc - * - * RETURNS - * Success: A handle representing the hook. - * Failure: A NULL handle. - * - * BUGS - * Not implemented. - */ -HWINEVENTHOOK WINAPI SetWinEventHook(DWORD dwMin, DWORD dwMax, HMODULE hModule, - WINEVENTPROC pfnProc, DWORD dwProcess, - DWORD dwThread, DWORD dwFlags) -{ - FIXME("(%ld,%ld,0x%08x,%p,%ld,%ld,0x%08lx)-stub!\n", dwMin, dwMax, hModule, - pfnProc, dwProcess, dwThread, dwFlags); - - return (HWINEVENTHOOK)0; -} - -/*********************************************************************** - * UnhookWinEvent [USER32.@] - * - * Remove an event hook for a set of events. - * - * PARAMS - * hEventHook [I] Event hook to remove - * - * RETURNS - * Success: TRUE. The event hook has been removed. - * Failure: FALSE, if hEventHook is invalid. - * - * BUGS - * Not implemented. - */ -BOOL WINAPI UnhookWinEvent(HWINEVENTHOOK hEventHook) -{ - FIXME("(%p)-stub!\n", (void*)hEventHook); - - if (!hEventHook) - return FALSE; - - return TRUE; -} - -/*********************************************************************** - * NotifyWinEvent [USER32.@] - * - * Inform the OS that an event has occurred. - * - * PARAMS - * dwEvent [I] Id of the event - * hWnd [I] Window holding the object that created the event - * nId [I] Type of object that created the event - * nChildId [I] Child object of nId, or CHILDID_SELF. - * - * RETURNS - * Nothing. - * - * BUGS - * Not implemented. - */ -VOID WINAPI NotifyWinEvent(DWORD dwEvent, HWND hWnd, LONG nId, LONG nChildId) -{ - FIXME("(%ld,0x%08x,%ld,%ld)-stub!\n", dwEvent, hWnd, nId, nChildId); -} - -/*********************************************************************** - * IsWinEventHookInstalled [USER32.@] - * - * Determine if an event hook is installed for an event. - * - * PARAMS - * dwEvent [I] Id of the event - * - * RETURNS - * TRUE, If there are any hooks installed for the event. - * FALSE, Otherwise. - * - * BUGS - * Not implemented. - */ -BOOL WINAPI IsWinEventHookInstalled(DWORD dwEvent) -{ - FIXME("(%ld)-stub!\n", dwEvent); - return TRUE; -} diff --git a/windows/input.c b/windows/input.c index a9d63c820d9..ce9aac9b02d 100644 --- a/windows/input.c +++ b/windows/input.c @@ -37,7 +37,6 @@ #include "wine/winuser16.h" #include "wine/server.h" #include "win.h" -#include "hook.h" #include "input.h" #include "message.h" #include "queue.h" @@ -181,7 +180,7 @@ static void queue_kbd_event( const KEYBDINPUT *ki, UINT injected_flags ) hook.flags = (keylp.lp2 >> 24) | injected_flags; hook.time = ki->time; hook.dwExtraInfo = ki->dwExtraInfo; - if (!HOOK_CallHooksW( WH_KEYBOARD_LL, HC_ACTION, message, (LPARAM)&hook )) + if (!HOOK_CallHooks( WH_KEYBOARD_LL, HC_ACTION, message, (LPARAM)&hook, TRUE )) queue_raw_hardware_message( message, ki->wVk, keylp.lp2, PosX, PosY, ki->time, ki->dwExtraInfo ); } @@ -201,7 +200,7 @@ static void queue_raw_mouse_message( UINT message, UINT flags, INT x, INT y, con hook.time = mi->time; hook.dwExtraInfo = mi->dwExtraInfo; - if (!HOOK_CallHooksW( WH_MOUSE_LL, HC_ACTION, message, (LPARAM)&hook )) + if (!HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, message, (LPARAM)&hook, TRUE )) queue_raw_hardware_message( message, MAKEWPARAM( get_key_state(), mi->mouseData ), 0, x, y, mi->time, mi->dwExtraInfo ); } diff --git a/windows/message.c b/windows/message.c index b5a1b8f22ea..6ed668f5a59 100644 --- a/windows/message.c +++ b/windows/message.c @@ -36,7 +36,6 @@ #include "wine/server.h" #include "win.h" #include "heap.h" -#include "hook.h" #include "input.h" #include "spy.h" #include "winpos.h" @@ -230,6 +229,8 @@ static void MSG_SendParentNotify( HWND hwnd, WORD event, WORD idChild, POINT pt } +#if 0 /* this is broken for now, will require proper support in the server */ + /*********************************************************************** * MSG_JournalPlayBackMsg * @@ -242,9 +243,7 @@ void MSG_JournalPlayBackMsg(void) LRESULT wtime; int keyDown,i; - if (!HOOK_IsHooked( WH_JOURNALPLAYBACK )) return; - - wtime=HOOK_CallHooksA( WH_JOURNALPLAYBACK, HC_GETNEXT, 0, (LPARAM)&tmpMsg ); + wtime=HOOK_CallHooks( WH_JOURNALPLAYBACK, HC_GETNEXT, 0, (LPARAM)&tmpMsg, TRUE ); /* TRACE(msg,"Playback wait time =%ld\n",wtime); */ if (wtime<=0) { @@ -316,15 +315,14 @@ void MSG_JournalPlayBackMsg(void) msg.pt.y = tmpMsg.paramH; queue_hardware_message( &msg, 0, MSG_HARDWARE_RAW ); } - HOOK_CallHooksA( WH_JOURNALPLAYBACK, HC_SKIP, 0, (LPARAM)&tmpMsg); + HOOK_CallHooks( WH_JOURNALPLAYBACK, HC_SKIP, 0, (LPARAM)&tmpMsg, TRUE ); } else { - if( tmpMsg.message == WM_QUEUESYNC ) - if (HOOK_IsHooked( WH_CBT )) - HOOK_CallHooksA( WH_CBT, HCBT_QS, 0, 0L); + if( tmpMsg.message == WM_QUEUESYNC ) HOOK_CallHooks( WH_CBT, HCBT_QS, 0, 0, TRUE ); } } +#endif /*********************************************************************** @@ -334,6 +332,8 @@ void MSG_JournalPlayBackMsg(void) */ static BOOL process_raw_keyboard_message( MSG *msg, ULONG_PTR extra_info ) { + EVENTMSG event; + if (!(msg->hwnd = GetFocus())) { /* Send the message to the active window instead, */ @@ -342,18 +342,13 @@ static BOOL process_raw_keyboard_message( MSG *msg, ULONG_PTR extra_info ) if (msg->message < WM_SYSKEYDOWN) msg->message += WM_SYSKEYDOWN - WM_KEYDOWN; } - if (HOOK_IsHooked( WH_JOURNALRECORD )) - { - EVENTMSG event; - - event.message = msg->message; - event.hwnd = msg->hwnd; - event.time = msg->time; - event.paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8); - event.paramH = msg->lParam & 0x7FFF; - if (HIWORD(msg->lParam) & 0x0100) event.paramH |= 0x8000; /* special_key - bit */ - HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event ); - } + event.message = msg->message; + event.hwnd = msg->hwnd; + event.time = msg->time; + event.paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8); + event.paramH = msg->lParam & 0x7FFF; + if (HIWORD(msg->lParam) & 0x0100) event.paramH |= 0x8000; /* special_key - bit */ + HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event, TRUE ); /* if we are going to throw away the message, update the queue state now */ if (!msg->hwnd) update_queue_key_state( msg->message, msg->wParam, msg->lParam ); @@ -390,11 +385,11 @@ static BOOL process_cooked_keyboard_message( MSG *msg, BOOL remove ) } } - if (HOOK_CallHooksA( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE, - LOWORD(msg->wParam), msg->lParam )) + if (HOOK_CallHooks( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE, + LOWORD(msg->wParam), msg->lParam, TRUE )) { /* skip this message */ - HOOK_CallHooksA( WH_CBT, HCBT_KEYSKIPPED, LOWORD(msg->wParam), msg->lParam ); + HOOK_CallHooks( WH_CBT, HCBT_KEYSKIPPED, LOWORD(msg->wParam), msg->lParam, TRUE ); return FALSE; } return TRUE; @@ -412,6 +407,7 @@ static BOOL process_raw_mouse_message( MSG *msg, ULONG_PTR extra_info ) POINT pt; INT hittest; + EVENTMSG event; GUITHREADINFO info; /* find the window to dispatch this mouse message to */ @@ -429,16 +425,12 @@ static BOOL process_raw_mouse_message( MSG *msg, ULONG_PTR extra_info ) msg->hwnd = GetDesktopWindow(); } - if (HOOK_IsHooked( WH_JOURNALRECORD )) - { - EVENTMSG event; - event.message = msg->message; - event.time = msg->time; - event.hwnd = msg->hwnd; - event.paramL = msg->pt.x; - event.paramH = msg->pt.y; - HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event ); - } + event.message = msg->message; + event.time = msg->time; + event.hwnd = msg->hwnd; + event.paramL = msg->pt.x; + event.paramH = msg->pt.y; + HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event, TRUE ); /* translate double clicks */ @@ -495,6 +487,7 @@ static BOOL process_raw_mouse_message( MSG *msg, ULONG_PTR extra_info ) */ static BOOL process_cooked_mouse_message( MSG *msg, ULONG_PTR extra_info, BOOL remove ) { + MOUSEHOOKSTRUCT hook; INT hittest = HTCLIENT; UINT raw_message = msg->message; BOOL eatMsg; @@ -513,23 +506,19 @@ static BOOL process_cooked_mouse_message( MSG *msg, ULONG_PTR extra_info, BOOL r if (remove) update_queue_key_state( raw_message, 0, 0 ); - if (HOOK_IsHooked( WH_MOUSE )) + hook.pt = msg->pt; + hook.hwnd = msg->hwnd; + hook.wHitTestCode = hittest; + hook.dwExtraInfo = extra_info; + if (HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE, + msg->message, (LPARAM)&hook, TRUE )) { - MOUSEHOOKSTRUCT hook; hook.pt = msg->pt; hook.hwnd = msg->hwnd; hook.wHitTestCode = hittest; hook.dwExtraInfo = extra_info; - if (HOOK_CallHooksA( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE, - msg->message, (LPARAM)&hook )) - { - hook.pt = msg->pt; - hook.hwnd = msg->hwnd; - hook.wHitTestCode = hittest; - hook.dwExtraInfo = extra_info; - HOOK_CallHooksA( WH_CBT, HCBT_CLICKSKIPPED, msg->message, (LPARAM)&hook ); - return FALSE; - } + HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, msg->message, (LPARAM)&hook, TRUE ); + return FALSE; } if ((hittest == HTERROR) || (hittest == HTNOWHERE)) diff --git a/windows/nonclient.c b/windows/nonclient.c index 180547bde0e..1f3e7654767 100644 --- a/windows/nonclient.c +++ b/windows/nonclient.c @@ -29,7 +29,6 @@ #include "controls.h" #include "cursoricon.h" #include "winpos.h" -#include "hook.h" #include "nonclient.h" #include "wine/debug.h" #include "shellapi.h" diff --git a/windows/queue.c b/windows/queue.c index 178efefac14..250b4ba97b8 100644 --- a/windows/queue.c +++ b/windows/queue.c @@ -29,7 +29,6 @@ #include "queue.h" #include "win.h" #include "user.h" -#include "hook.h" #include "thread.h" #include "wine/debug.h" #include "wine/server.h" diff --git a/windows/user.c b/windows/user.c index fe35ded5e8c..d758a1998a4 100644 --- a/windows/user.c +++ b/windows/user.c @@ -30,7 +30,6 @@ #include "win.h" #include "controls.h" #include "cursoricon.h" -#include "hook.h" #include "message.h" #include "miscemu.h" #include "sysmetrics.h" @@ -140,7 +139,7 @@ void USER_CheckNotLock(void) */ static void USER_ModuleUnload( HMODULE16 hModule ) { - HOOK_FreeModuleHooks( hModule ); + /* HOOK_FreeModuleHooks( hModule ); */ CLASS_FreeModuleClasses( hModule ); CURSORICON_FreeModuleIcons( hModule ); } diff --git a/windows/win.c b/windows/win.c index 714b1ffbfad..b2a135311f6 100644 --- a/windows/win.c +++ b/windows/win.c @@ -35,7 +35,6 @@ #include "dce.h" #include "controls.h" #include "cursoricon.h" -#include "hook.h" #include "message.h" #include "queue.h" #include "winpos.h" @@ -1188,7 +1187,7 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom, /* Call WH_SHELL hook */ if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER )) - HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0 ); + HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE ); TRACE("created window %04x\n", hwnd); return hwnd; @@ -1457,7 +1456,7 @@ BOOL WINAPI DestroyWindow( HWND hwnd ) /* Call hooks */ - if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0L) ) return FALSE; + if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE; is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0; @@ -1468,7 +1467,7 @@ BOOL WINAPI DestroyWindow( HWND hwnd ) } else if (!GetWindow( hwnd, GW_OWNER )) { - HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L ); + HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE ); /* FIXME: clean up palette - see "Internals" p.352 */ }