2 * Windows 16-bit hook functions
4 * Copyright 1994, 1995, 2002 Alexandre Julliard
5 * Copyright 1996 Andrew Lewycky
7 * Based on investigations by Alex Korobka
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/winuser16.h"
31 #include "user_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(hook);
37 static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp );
38 static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp );
39 static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp );
40 static LRESULT CALLBACK call_WH_CALLWNDPROC( INT code, WPARAM wp, LPARAM lp );
41 static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp );
42 static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp );
43 static LRESULT CALLBACK call_WH_SHELL( INT code, WPARAM wp, LPARAM lp );
45 #define WH_MAXHOOK16 WH_SHELL /* Win16 only supports up to WH_SHELL */
46 #define NB_HOOKS16 (WH_MAXHOOK16 - WH_MINHOOK + 1)
48 static const HOOKPROC hook_procs[NB_HOOKS16] =
50 call_WH_MSGFILTER, /* WH_MSGFILTER */
51 NULL, /* WH_JOURNALRECORD */
52 NULL, /* WH_JOURNALPLAYBACK */
53 call_WH_KEYBOARD, /* WH_KEYBOARD */
54 call_WH_GETMESSAGE, /* WH_GETMESSAGE */
55 call_WH_CALLWNDPROC, /* WH_CALLWNDPROC */
56 call_WH_CBT, /* WH_CBT */
57 NULL, /* WH_SYSMSGFILTER */
58 call_WH_MOUSE, /* WH_MOUSE */
59 NULL, /* WH_HARDWARE */
61 call_WH_SHELL /* WH_SHELL */
65 struct hook16_queue_info
67 INT id; /* id of current hook */
68 HHOOK hook[NB_HOOKS16]; /* Win32 hook handles */
69 HOOKPROC16 proc[NB_HOOKS16]; /* 16-bit hook procedures */
72 static struct hook16_queue_info *get_hook_info( BOOL create )
74 static DWORD hook_tls = TLS_OUT_OF_INDEXES;
75 struct hook16_queue_info *info = TlsGetValue( hook_tls );
79 if (hook_tls == TLS_OUT_OF_INDEXES) hook_tls = TlsAlloc();
80 info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*info) );
81 TlsSetValue( hook_tls, info );
87 /***********************************************************************
90 static inline void map_msg_16_to_32( const MSG16 *msg16, MSG *msg32 )
92 msg32->hwnd = WIN_Handle32(msg16->hwnd);
93 msg32->message = msg16->message;
94 msg32->wParam = msg16->wParam;
95 msg32->lParam = msg16->lParam;
96 msg32->time = msg16->time;
97 msg32->pt.x = msg16->pt.x;
98 msg32->pt.y = msg16->pt.y;
102 /***********************************************************************
105 static inline void map_msg_32_to_16( const MSG *msg32, MSG16 *msg16 )
107 msg16->hwnd = HWND_16(msg32->hwnd);
108 msg16->message = msg32->message;
109 msg16->wParam = msg32->wParam;
110 msg16->lParam = msg32->lParam;
111 msg16->time = msg32->time;
112 msg16->pt.x = msg32->pt.x;
113 msg16->pt.y = msg32->pt.y;
117 /***********************************************************************
120 static LRESULT call_hook_16( INT id, INT code, WPARAM wp, LPARAM lp )
122 struct hook16_queue_info *info = get_hook_info( FALSE );
125 INT prev_id = info->id;
130 args[1] = HIWORD(lp);
131 args[0] = LOWORD(lp);
132 WOWCallback16Ex( (DWORD)info->proc[id - WH_MINHOOK], WCB16_PASCAL, sizeof(args), args, &ret );
136 /* Grrr. While the hook procedure is supposed to have an LRESULT return
137 value even in Win16, it seems that for those hook types where the
138 return value is interpreted as BOOL, Windows doesn't actually check
139 the HIWORD ... Some buggy Win16 programs, notably WINFILE, rely on
140 that, because they neglect to clear DX ... */
141 if (id != WH_JOURNALPLAYBACK) ret = LOWORD( ret );
146 struct wndproc_hook_params
153 /* callback for WINPROC_Call16To32A */
154 static LRESULT wndproc_hook_callback( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
155 LRESULT *result, void *arg )
157 struct wndproc_hook_params *params = arg;
165 return CallNextHookEx( params->hhook, params->code, params->wparam, (LPARAM)&cwp );
168 /* callback for WINPROC_Call32ATo16 */
169 static LRESULT wndproc_hook_callback16( HWND16 hwnd, UINT16 msg, WPARAM16 wp, LPARAM lp,
170 LRESULT *result, void *arg )
172 struct wndproc_hook_params *params = arg;
182 ret = call_hook_16( WH_CALLWNDPROC, params->code, params->wparam, lp );
189 /* helper for SendMessage16 */
190 void call_WH_CALLWNDPROC_hook( HWND16 hwnd, UINT16 msg, WPARAM16 wp, LPARAM lp )
193 struct hook16_queue_info *info = get_hook_info( FALSE );
195 if (!info || !info->proc[WH_CALLWNDPROC - WH_MINHOOK]) return;
203 call_hook_16( WH_CALLWNDPROC, HC_ACTION, 1, lp );
207 /***********************************************************************
210 static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp )
212 MSG *msg32 = (MSG *)lp;
216 map_msg_32_to_16( msg32, &msg16 );
217 lp = MapLS( &msg16 );
218 ret = call_hook_16( WH_MSGFILTER, code, wp, lp );
224 /***********************************************************************
227 static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp )
229 return call_hook_16( WH_KEYBOARD, code, wp, lp );
233 /***********************************************************************
236 static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp )
238 MSG *msg32 = (MSG *)lp;
242 map_msg_32_to_16( msg32, &msg16 );
244 lp = MapLS( &msg16 );
245 ret = call_hook_16( WH_GETMESSAGE, code, wp, lp );
248 map_msg_16_to_32( &msg16, msg32 );
253 /***********************************************************************
254 * call_WH_CALLWNDPROC
256 static LRESULT CALLBACK call_WH_CALLWNDPROC( INT code, WPARAM wp, LPARAM lp )
258 struct wndproc_hook_params params;
259 CWPSTRUCT *cwp32 = (CWPSTRUCT *)lp;
264 return WINPROC_CallProc32ATo16( wndproc_hook_callback16, cwp32->hwnd, cwp32->message,
265 cwp32->wParam, cwp32->lParam, &result, ¶ms );
269 /***********************************************************************
272 static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp )
280 CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lp;
281 CBT_CREATEWND16 cbtcw16;
284 cs16.lpCreateParams = (SEGPTR)cbtcw32->lpcs->lpCreateParams;
285 cs16.hInstance = HINSTANCE_16(cbtcw32->lpcs->hInstance);
286 cs16.hMenu = HMENU_16(cbtcw32->lpcs->hMenu);
287 cs16.hwndParent = HWND_16(cbtcw32->lpcs->hwndParent);
288 cs16.cy = cbtcw32->lpcs->cy;
289 cs16.cx = cbtcw32->lpcs->cx;
290 cs16.y = cbtcw32->lpcs->y;
291 cs16.x = cbtcw32->lpcs->x;
292 cs16.style = cbtcw32->lpcs->style;
293 cs16.lpszName = MapLS( cbtcw32->lpcs->lpszName );
294 cs16.lpszClass = MapLS( cbtcw32->lpcs->lpszClass );
295 cs16.dwExStyle = cbtcw32->lpcs->dwExStyle;
297 cbtcw16.lpcs = (CREATESTRUCT16 *)MapLS( &cs16 );
298 cbtcw16.hwndInsertAfter = HWND_16( cbtcw32->hwndInsertAfter );
300 lp = MapLS( &cbtcw16 );
301 ret = call_hook_16( WH_CBT, code, wp, lp );
302 UnMapLS( cs16.lpszName );
303 UnMapLS( cs16.lpszClass );
305 cbtcw32->hwndInsertAfter = WIN_Handle32( cbtcw16.hwndInsertAfter );
306 UnMapLS( (SEGPTR)cbtcw16.lpcs );
313 CBTACTIVATESTRUCT *cas32 = (CBTACTIVATESTRUCT *)lp;
314 CBTACTIVATESTRUCT16 cas16;
316 cas16.fMouse = cas32->fMouse;
317 cas16.hWndActive = HWND_16( cas32->hWndActive );
319 lp = MapLS( &cas16 );
320 ret = call_hook_16( WH_CBT, code, wp, lp );
324 case HCBT_CLICKSKIPPED:
326 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
327 MOUSEHOOKSTRUCT16 ms16;
329 ms16.pt.x = ms32->pt.x;
330 ms16.pt.y = ms32->pt.y;
331 ms16.hwnd = HWND_16( ms32->hwnd );
332 ms16.wHitTestCode = ms32->wHitTestCode;
333 ms16.dwExtraInfo = ms32->dwExtraInfo;
336 ret = call_hook_16( WH_CBT, code, wp, lp );
342 RECT *rect32 = (RECT *)lp;
345 rect16.left = rect32->left;
346 rect16.top = rect32->top;
347 rect16.right = rect32->right;
348 rect16.bottom = rect32->bottom;
349 lp = MapLS( &rect16 );
350 ret = call_hook_16( WH_CBT, code, wp, lp );
359 /***********************************************************************
362 static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp )
364 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
365 MOUSEHOOKSTRUCT16 ms16;
368 ms16.pt.x = ms32->pt.x;
369 ms16.pt.y = ms32->pt.y;
370 ms16.hwnd = HWND_16( ms32->hwnd );
371 ms16.wHitTestCode = ms32->wHitTestCode;
372 ms16.dwExtraInfo = ms32->dwExtraInfo;
375 ret = call_hook_16( WH_MOUSE, code, wp, lp );
381 /***********************************************************************
384 static LRESULT CALLBACK call_WH_SHELL( INT code, WPARAM wp, LPARAM lp )
386 return call_hook_16( WH_SHELL, code, wp, lp );
390 /***********************************************************************
391 * SetWindowsHook (USER.121)
393 FARPROC16 WINAPI SetWindowsHook16( INT16 id, HOOKPROC16 proc )
395 HINSTANCE16 hInst = FarGetOwner16( HIWORD(proc) );
397 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
398 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
400 return (FARPROC16)SetWindowsHookEx16( id, proc, hInst, hTask );
404 /***********************************************************************
405 * SetWindowsHookEx (USER.291)
407 HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst, HTASK16 hTask )
409 struct hook16_queue_info *info;
411 int index = id - WH_MINHOOK;
413 if (id < WH_MINHOOK || id > WH_MAXHOOK16) return 0;
414 if (!hook_procs[index])
416 FIXME( "hook type %d broken in Win16\n", id );
419 if (!hTask) FIXME( "System-global hooks (%d) broken in Win16\n", id );
420 else if (hTask != GetCurrentTask())
422 FIXME( "setting hook (%d) on other task not supported\n", id );
426 if (!(info = get_hook_info( TRUE ))) return 0;
427 if (info->hook[index])
429 FIXME( "Multiple hooks (%d) for the same task not supported yet\n", id );
432 if (!(hook = SetWindowsHookExA( id, hook_procs[index], 0, GetCurrentThreadId() ))) return 0;
433 info->hook[index] = hook;
434 info->proc[index] = proc;
439 /***********************************************************************
440 * UnhookWindowsHook (USER.234)
442 BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
444 struct hook16_queue_info *info;
445 int index = id - WH_MINHOOK;
447 if (id < WH_MINHOOK || id > WH_MAXHOOK16) return FALSE;
448 if (!(info = get_hook_info( FALSE ))) return FALSE;
449 if (info->proc[index] != proc) return FALSE;
450 if (!UnhookWindowsHookEx( info->hook[index] )) return FALSE;
451 info->hook[index] = 0;
452 info->proc[index] = 0;
457 /***********************************************************************
458 * UnhookWindowsHookEx (USER.292)
460 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
462 struct hook16_queue_info *info;
465 if (!(info = get_hook_info( FALSE ))) return FALSE;
466 for (index = 0; index < NB_HOOKS16; index++)
468 if (info->hook[index] == hhook)
470 info->hook[index] = 0;
471 info->proc[index] = 0;
472 return UnhookWindowsHookEx( hhook );
479 /***********************************************************************
480 * CallMsgFilter32 (USER.823)
482 BOOL16 WINAPI CallMsgFilter32_16( MSG32_16 *lpmsg16_32, INT16 code, BOOL16 wHaveParamHigh )
487 if (GetSysModalWindow16()) return FALSE;
488 msg32.hwnd = WIN_Handle32( lpmsg16_32->msg.hwnd );
489 msg32.message = lpmsg16_32->msg.message;
490 msg32.lParam = lpmsg16_32->msg.lParam;
491 msg32.time = lpmsg16_32->msg.time;
492 msg32.pt.x = lpmsg16_32->msg.pt.x;
493 msg32.pt.y = lpmsg16_32->msg.pt.y;
494 if (wHaveParamHigh) msg32.wParam = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh);
495 else msg32.wParam = lpmsg16_32->msg.wParam;
497 ret = (BOOL16)CallMsgFilterA(&msg32, code);
499 lpmsg16_32->msg.hwnd = HWND_16( msg32.hwnd );
500 lpmsg16_32->msg.message = msg32.message;
501 lpmsg16_32->msg.wParam = LOWORD(msg32.wParam);
502 lpmsg16_32->msg.lParam = msg32.lParam;
503 lpmsg16_32->msg.time = msg32.time;
504 lpmsg16_32->msg.pt.x = msg32.pt.x;
505 lpmsg16_32->msg.pt.y = msg32.pt.y;
506 if (wHaveParamHigh) lpmsg16_32->wParamHigh = HIWORD(msg32.wParam);
511 /***********************************************************************
512 * CallMsgFilter (USER.123)
514 BOOL16 WINAPI CallMsgFilter16( MSG16 *msg, INT16 code )
516 return CallMsgFilter32_16( (MSG32_16 *)msg, code, FALSE );
520 /***********************************************************************
521 * CallNextHookEx (USER.293)
523 LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wparam, LPARAM lparam )
525 struct hook16_queue_info *info;
528 if (!(info = get_hook_info( FALSE ))) return 0;
534 MSG16 *msg16 = MapSL(lparam);
537 map_msg_16_to_32( msg16, &msg32 );
538 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
544 MSG16 *msg16 = MapSL(lparam);
547 map_msg_16_to_32( msg16, &msg32 );
548 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
549 map_msg_32_to_16( &msg32, msg16 );
555 CWPSTRUCT16 *cwp16 = MapSL(lparam);
557 struct wndproc_hook_params params;
559 params.hhook = hhook;
561 params.wparam = wparam;
562 ret = WINPROC_CallProc16To32A( wndproc_hook_callback, cwp16->hwnd, cwp16->message,
563 cwp16->wParam, cwp16->lParam, &result, ¶ms );
572 CBT_CREATEWNDA cbtcw32;
574 CBT_CREATEWND16 *cbtcw16 = MapSL(lparam);
575 CREATESTRUCT16 *cs16 = MapSL( (SEGPTR)cbtcw16->lpcs );
577 cbtcw32.lpcs = &cs32;
578 cbtcw32.hwndInsertAfter = WIN_Handle32( cbtcw16->hwndInsertAfter );
580 cs32.lpCreateParams = (LPVOID)cs16->lpCreateParams;
581 cs32.hInstance = HINSTANCE_32(cs16->hInstance);
582 cs32.hMenu = HMENU_32(cs16->hMenu);
583 cs32.hwndParent = WIN_Handle32(cs16->hwndParent);
588 cs32.style = cs16->style;
589 cs32.lpszName = MapSL( cs16->lpszName );
590 cs32.lpszClass = MapSL( cs16->lpszClass );
591 cs32.dwExStyle = cs16->dwExStyle;
593 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cbtcw32 );
594 cbtcw16->hwndInsertAfter = HWND_16( cbtcw32.hwndInsertAfter );
599 CBTACTIVATESTRUCT16 *cas16 = MapSL(lparam);
600 CBTACTIVATESTRUCT cas32;
601 cas32.fMouse = cas16->fMouse;
602 cas32.hWndActive = WIN_Handle32(cas16->hWndActive);
603 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cas32 );
606 case HCBT_CLICKSKIPPED:
608 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
609 MOUSEHOOKSTRUCT ms32;
611 ms32.pt.x = ms16->pt.x;
612 ms32.pt.y = ms16->pt.y;
613 /* wHitTestCode may be negative, so convince compiler to do
614 correct sign extension. Yay. :| */
615 ms32.wHitTestCode = (INT)(INT16)ms16->wHitTestCode;
616 ms32.dwExtraInfo = ms16->dwExtraInfo;
617 ms32.hwnd = WIN_Handle32( ms16->hwnd );
618 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 );
623 RECT16 *rect16 = MapSL(lparam);
626 rect32.left = rect16->left;
627 rect32.top = rect16->top;
628 rect32.right = rect16->right;
629 rect32.bottom = rect16->bottom;
630 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&rect32 );
638 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
639 MOUSEHOOKSTRUCT ms32;
641 ms32.pt.x = ms16->pt.x;
642 ms32.pt.y = ms16->pt.y;
643 /* wHitTestCode may be negative, so convince compiler to do
644 correct sign extension. Yay. :| */
645 ms32.wHitTestCode = (INT)((INT16)ms16->wHitTestCode);
646 ms32.dwExtraInfo = ms16->dwExtraInfo;
647 ms32.hwnd = WIN_Handle32(ms16->hwnd);
648 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 );
654 ret = CallNextHookEx( hhook, code, wparam, lparam );
658 case WH_FOREGROUNDIDLE:
659 case WH_CALLWNDPROCRET:
660 case WH_SYSMSGFILTER:
661 case WH_JOURNALRECORD:
662 case WH_JOURNALPLAYBACK:
664 FIXME("\t[%i] 16to32 translation unimplemented\n", info->id);
665 ret = CallNextHookEx( hhook, code, wparam, lparam );
672 /***********************************************************************
673 * DefHookProc (USER.235)
675 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wparam, LPARAM lparam, HHOOK *hhook )
677 return CallNextHookEx16( *hhook, code, wparam, lparam );