| /* |
| * 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 "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(HHOOK_16(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(HHOOK_16(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(HHOOK_16(hook)); |
| return TRUE; |
| } |
| |
| |
| /*********************************************************************** |
| * HOOK_FindValidHook |
| */ |
| static HHOOK HOOK_FindValidHook( HHOOK hook ) |
| { |
| HOOKDATA *data; |
| |
| for (;;) |
| { |
| if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(HHOOK_16(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(HHOOK_16(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(HHOOK_16(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) |
| * SetWindowsHookEx16 (USER32.@) |
| */ |
| 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(HHOOK_16(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) |
| * CallNextHookEx16 (USER32.@) |
| * |
| * 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_16(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 (GetSysModalWindow16()) return FALSE; |
| 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 (GetSysModalWindow16()) return FALSE; /* ??? */ |
| 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 (GetSysModalWindow16()) return FALSE; /* ??? */ |
| 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; |
| } |