blob: 0f8bb6a9d759aff6a0f5e1a4bb399d44e0edfa28 [file] [log] [blame]
/*
* 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' */
/* 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 = WIN_Handle16( 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 = WIN_Handle16(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 = WIN_Handle16( 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 = WIN_Handle16( 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 = WIN_Handle16( 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 = WIN_Handle16( 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 HANDLE16 HOOK_GetNextHook( HANDLE16 hook )
{
HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR( hook );
if (!data || !hook) return 0;
if (data->next) return data->next;
if (!data->ownerQueue) return 0; /* Already system hook */
/* Now start enumerating the system hooks */
return HOOK_systemHooks[data->id - WH_MINHOOK];
}
/***********************************************************************
* HOOK_GetHook
*
* Get the first hook for a given type.
*/
static HANDLE16 HOOK_GetHook( INT16 id )
{
MESSAGEQUEUE *queue;
HANDLE16 hook = 0;
if ((queue = QUEUE_Current()) != NULL)
hook = queue->hooks[id - WH_MINHOOK];
if (!hook) hook = HOOK_systemHooks[id - WH_MINHOOK];
return hook;
}
/***********************************************************************
* 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)( handle? MAKELONG( handle, HOOK_MAGIC ) : 0 );
}
/***********************************************************************
* HOOK_RemoveHook
*
* Remove a hook from the list.
*/
static BOOL HOOK_RemoveHook( HANDLE16 hook )
{
HOOKDATA *data;
HANDLE16 *prevHook;
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;
prevHook = &queue->hooks[data->id - WH_MINHOOK];
QUEUE_Unlock( queue );
}
else prevHook = &HOOK_systemHooks[data->id - WH_MINHOOK];
while (*prevHook && *prevHook != hook)
prevHook = &((HOOKDATA *)USER_HEAP_LIN_ADDR(*prevHook))->next;
if (!*prevHook) return FALSE;
*prevHook = data->next;
USER_HEAP_FREE( hook );
return TRUE;
}
/***********************************************************************
* HOOK_FindValidHook
*/
static HANDLE16 HOOK_FindValidHook( HANDLE16 hook )
{
HOOKDATA *data;
for (;;)
{
if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return 0;
if (data->proc) return hook;
hook = data->next;
}
}
/***********************************************************************
* HOOK_CallHook
*
* Call a hook procedure.
*/
static LRESULT HOOK_CallHook( HANDLE16 hook, INT fromtype, INT code,
WPARAM wParam, LPARAM lParam )
{
MESSAGEQUEUE *queue;
HANDLE16 prevHook;
HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
LRESULT ret;
if (!(queue = QUEUE_Current())) return 0;
prevHook = queue->hCurHook;
queue->hCurHook = 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 = prevHook;
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 )
{
HANDLE16 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 )
{
HANDLE16 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 )
{
HANDLE16 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;
HHOOK hook, next;
int id;
for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
{
hook = HOOK_systemHooks[id - WH_MINHOOK];
while( hook )
if( (hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook)) )
{
next = hptr->next;
if( hptr->ownerModule == hModule )
{
hptr->flags &= HOOK_MAPTYPE;
HOOK_RemoveHook(hook);
}
hook = next;
}
else hook = 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)
* 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 )
{
HANDLE16 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 UnhookWindowsHookEx( hhook );
}
/***********************************************************************
* UnhookWindowsHookEx (USER32.@)
*/
BOOL WINAPI UnhookWindowsHookEx( HHOOK hhook )
{
if (HIWORD(hhook) != HOOK_MAGIC) return FALSE; /* Not a new format hook */
return HOOK_RemoveHook( LOWORD(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 )
{
HANDLE16 next;
if (HIWORD(hhook) != HOOK_MAGIC) return 0; /* Not a new format hook */
if (!(next = HOOK_GetNextHook( LOWORD(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 )
{
HANDLE16 next;
INT fromtype; /* figure out Ansi/Unicode */
HOOKDATA *oldhook;
if (HIWORD(hhook) != HOOK_MAGIC) return 0; /* Not a new format hook */
if (!(next = HOOK_GetNextHook( LOWORD(hhook) ))) return 0;
oldhook = (HOOKDATA *)USER_HEAP_LIN_ADDR( LOWORD(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( 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 = WIN_Handle16( 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 );
}