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 );
190 /***********************************************************************
193 static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp )
195 MSG *msg32 = (MSG *)lp;
199 map_msg_32_to_16( msg32, &msg16 );
200 lp = MapLS( &msg16 );
201 ret = call_hook_16( WH_MSGFILTER, code, wp, lp );
207 /***********************************************************************
210 static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp )
212 return call_hook_16( WH_KEYBOARD, code, wp, lp );
216 /***********************************************************************
219 static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp )
221 MSG *msg32 = (MSG *)lp;
225 map_msg_32_to_16( msg32, &msg16 );
227 lp = MapLS( &msg16 );
228 ret = call_hook_16( WH_GETMESSAGE, code, wp, lp );
231 map_msg_16_to_32( &msg16, msg32 );
236 /***********************************************************************
237 * call_WH_CALLWNDPROC
239 static LRESULT CALLBACK call_WH_CALLWNDPROC( INT code, WPARAM wp, LPARAM lp )
241 struct wndproc_hook_params params;
242 CWPSTRUCT *cwp32 = (CWPSTRUCT *)lp;
247 return WINPROC_CallProc32ATo16( wndproc_hook_callback16, cwp32->hwnd, cwp32->message,
248 cwp32->wParam, cwp32->lParam, &result, ¶ms );
252 /***********************************************************************
255 static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp )
263 CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lp;
264 CBT_CREATEWND16 cbtcw16;
267 cs16.lpCreateParams = (SEGPTR)cbtcw32->lpcs->lpCreateParams;
268 cs16.hInstance = HINSTANCE_16(cbtcw32->lpcs->hInstance);
269 cs16.hMenu = HMENU_16(cbtcw32->lpcs->hMenu);
270 cs16.hwndParent = HWND_16(cbtcw32->lpcs->hwndParent);
271 cs16.cy = cbtcw32->lpcs->cy;
272 cs16.cx = cbtcw32->lpcs->cx;
273 cs16.y = cbtcw32->lpcs->y;
274 cs16.x = cbtcw32->lpcs->x;
275 cs16.style = cbtcw32->lpcs->style;
276 cs16.lpszName = MapLS( cbtcw32->lpcs->lpszName );
277 cs16.lpszClass = MapLS( cbtcw32->lpcs->lpszClass );
278 cs16.dwExStyle = cbtcw32->lpcs->dwExStyle;
280 cbtcw16.lpcs = (CREATESTRUCT16 *)MapLS( &cs16 );
281 cbtcw16.hwndInsertAfter = HWND_16( cbtcw32->hwndInsertAfter );
283 lp = MapLS( &cbtcw16 );
284 ret = call_hook_16( WH_CBT, code, wp, lp );
285 UnMapLS( cs16.lpszName );
286 UnMapLS( cs16.lpszClass );
288 cbtcw32->hwndInsertAfter = WIN_Handle32( cbtcw16.hwndInsertAfter );
289 UnMapLS( (SEGPTR)cbtcw16.lpcs );
296 CBTACTIVATESTRUCT *cas32 = (CBTACTIVATESTRUCT *)lp;
297 CBTACTIVATESTRUCT16 cas16;
299 cas16.fMouse = cas32->fMouse;
300 cas16.hWndActive = HWND_16( cas32->hWndActive );
302 lp = MapLS( &cas16 );
303 ret = call_hook_16( WH_CBT, code, wp, lp );
307 case HCBT_CLICKSKIPPED:
309 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
310 MOUSEHOOKSTRUCT16 ms16;
312 ms16.pt.x = ms32->pt.x;
313 ms16.pt.y = ms32->pt.y;
314 ms16.hwnd = HWND_16( ms32->hwnd );
315 ms16.wHitTestCode = ms32->wHitTestCode;
316 ms16.dwExtraInfo = ms32->dwExtraInfo;
319 ret = call_hook_16( WH_CBT, code, wp, lp );
325 RECT *rect32 = (RECT *)lp;
328 rect16.left = rect32->left;
329 rect16.top = rect32->top;
330 rect16.right = rect32->right;
331 rect16.bottom = rect32->bottom;
332 lp = MapLS( &rect16 );
333 ret = call_hook_16( WH_CBT, code, wp, lp );
342 /***********************************************************************
345 static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp )
347 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
348 MOUSEHOOKSTRUCT16 ms16;
351 ms16.pt.x = ms32->pt.x;
352 ms16.pt.y = ms32->pt.y;
353 ms16.hwnd = HWND_16( ms32->hwnd );
354 ms16.wHitTestCode = ms32->wHitTestCode;
355 ms16.dwExtraInfo = ms32->dwExtraInfo;
358 ret = call_hook_16( WH_MOUSE, code, wp, lp );
364 /***********************************************************************
367 static LRESULT CALLBACK call_WH_SHELL( INT code, WPARAM wp, LPARAM lp )
369 return call_hook_16( WH_SHELL, code, wp, lp );
373 /***********************************************************************
374 * SetWindowsHook (USER.121)
376 FARPROC16 WINAPI SetWindowsHook16( INT16 id, HOOKPROC16 proc )
378 HINSTANCE16 hInst = FarGetOwner16( HIWORD(proc) );
380 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
381 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
383 return (FARPROC16)SetWindowsHookEx16( id, proc, hInst, hTask );
387 /***********************************************************************
388 * SetWindowsHookEx (USER.291)
390 HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst, HTASK16 hTask )
392 struct hook16_queue_info *info;
394 int index = id - WH_MINHOOK;
396 if (id < WH_MINHOOK || id > WH_MAXHOOK16) return 0;
397 if (!hook_procs[index])
399 FIXME( "hook type %d broken in Win16\n", id );
402 if (!hTask) FIXME( "System-global hooks (%d) broken in Win16\n", id );
403 else if (hTask != GetCurrentTask())
405 FIXME( "setting hook (%d) on other task not supported\n", id );
409 if (!(info = get_hook_info( TRUE ))) return 0;
410 if (info->hook[index])
412 FIXME( "Multiple hooks (%d) for the same task not supported yet\n", id );
415 if (!(hook = SetWindowsHookExA( id, hook_procs[index], 0, GetCurrentThreadId() ))) return 0;
416 info->hook[index] = hook;
417 info->proc[index] = proc;
422 /***********************************************************************
423 * UnhookWindowsHook (USER.234)
425 BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
427 struct hook16_queue_info *info;
428 int index = id - WH_MINHOOK;
430 if (id < WH_MINHOOK || id > WH_MAXHOOK16) return FALSE;
431 if (!(info = get_hook_info( FALSE ))) return FALSE;
432 if (info->proc[index] != proc) return FALSE;
433 if (!UnhookWindowsHookEx( info->hook[index] )) return FALSE;
434 info->hook[index] = 0;
435 info->proc[index] = 0;
440 /***********************************************************************
441 * UnhookWindowsHookEx (USER.292)
443 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
445 struct hook16_queue_info *info;
448 if (!(info = get_hook_info( FALSE ))) return FALSE;
449 for (index = 0; index < NB_HOOKS16; index++)
451 if (info->hook[index] == hhook)
453 info->hook[index] = 0;
454 info->proc[index] = 0;
455 return UnhookWindowsHookEx( hhook );
462 /***********************************************************************
463 * CallMsgFilter32 (USER.823)
465 BOOL16 WINAPI CallMsgFilter32_16( MSG32_16 *lpmsg16_32, INT16 code, BOOL16 wHaveParamHigh )
470 if (GetSysModalWindow16()) return FALSE;
471 msg32.hwnd = WIN_Handle32( lpmsg16_32->msg.hwnd );
472 msg32.message = lpmsg16_32->msg.message;
473 msg32.lParam = lpmsg16_32->msg.lParam;
474 msg32.time = lpmsg16_32->msg.time;
475 msg32.pt.x = lpmsg16_32->msg.pt.x;
476 msg32.pt.y = lpmsg16_32->msg.pt.y;
477 if (wHaveParamHigh) msg32.wParam = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh);
478 else msg32.wParam = lpmsg16_32->msg.wParam;
480 ret = (BOOL16)CallMsgFilterA(&msg32, code);
482 lpmsg16_32->msg.hwnd = HWND_16( msg32.hwnd );
483 lpmsg16_32->msg.message = msg32.message;
484 lpmsg16_32->msg.wParam = LOWORD(msg32.wParam);
485 lpmsg16_32->msg.lParam = msg32.lParam;
486 lpmsg16_32->msg.time = msg32.time;
487 lpmsg16_32->msg.pt.x = msg32.pt.x;
488 lpmsg16_32->msg.pt.y = msg32.pt.y;
489 if (wHaveParamHigh) lpmsg16_32->wParamHigh = HIWORD(msg32.wParam);
494 /***********************************************************************
495 * CallMsgFilter (USER.123)
497 BOOL16 WINAPI CallMsgFilter16( MSG16 *msg, INT16 code )
499 return CallMsgFilter32_16( (MSG32_16 *)msg, code, FALSE );
503 /***********************************************************************
504 * CallNextHookEx (USER.293)
506 LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wparam, LPARAM lparam )
508 struct hook16_queue_info *info;
511 if (!(info = get_hook_info( FALSE ))) return 0;
517 MSG16 *msg16 = MapSL(lparam);
520 map_msg_16_to_32( msg16, &msg32 );
521 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
527 MSG16 *msg16 = MapSL(lparam);
530 map_msg_16_to_32( msg16, &msg32 );
531 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
532 map_msg_32_to_16( &msg32, msg16 );
538 CWPSTRUCT16 *cwp16 = MapSL(lparam);
540 struct wndproc_hook_params params;
542 params.hhook = hhook;
544 params.wparam = wparam;
545 ret = WINPROC_CallProc16To32A( wndproc_hook_callback, cwp16->hwnd, cwp16->message,
546 cwp16->wParam, cwp16->lParam, &result, ¶ms );
555 CBT_CREATEWNDA cbtcw32;
557 CBT_CREATEWND16 *cbtcw16 = MapSL(lparam);
558 CREATESTRUCT16 *cs16 = MapSL( (SEGPTR)cbtcw16->lpcs );
560 cbtcw32.lpcs = &cs32;
561 cbtcw32.hwndInsertAfter = WIN_Handle32( cbtcw16->hwndInsertAfter );
563 cs32.lpCreateParams = (LPVOID)cs16->lpCreateParams;
564 cs32.hInstance = HINSTANCE_32(cs16->hInstance);
565 cs32.hMenu = HMENU_32(cs16->hMenu);
566 cs32.hwndParent = WIN_Handle32(cs16->hwndParent);
571 cs32.style = cs16->style;
572 cs32.lpszName = MapSL( cs16->lpszName );
573 cs32.lpszClass = MapSL( cs16->lpszClass );
574 cs32.dwExStyle = cs16->dwExStyle;
576 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cbtcw32 );
577 cbtcw16->hwndInsertAfter = HWND_16( cbtcw32.hwndInsertAfter );
582 CBTACTIVATESTRUCT16 *cas16 = MapSL(lparam);
583 CBTACTIVATESTRUCT cas32;
584 cas32.fMouse = cas16->fMouse;
585 cas32.hWndActive = WIN_Handle32(cas16->hWndActive);
586 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cas32 );
589 case HCBT_CLICKSKIPPED:
591 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
592 MOUSEHOOKSTRUCT ms32;
594 ms32.pt.x = ms16->pt.x;
595 ms32.pt.y = ms16->pt.y;
596 /* wHitTestCode may be negative, so convince compiler to do
597 correct sign extension. Yay. :| */
598 ms32.wHitTestCode = (INT)(INT16)ms16->wHitTestCode;
599 ms32.dwExtraInfo = ms16->dwExtraInfo;
600 ms32.hwnd = WIN_Handle32( ms16->hwnd );
601 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 );
606 RECT16 *rect16 = MapSL(lparam);
609 rect32.left = rect16->left;
610 rect32.top = rect16->top;
611 rect32.right = rect16->right;
612 rect32.bottom = rect16->bottom;
613 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&rect32 );
621 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
622 MOUSEHOOKSTRUCT ms32;
624 ms32.pt.x = ms16->pt.x;
625 ms32.pt.y = ms16->pt.y;
626 /* wHitTestCode may be negative, so convince compiler to do
627 correct sign extension. Yay. :| */
628 ms32.wHitTestCode = (INT)((INT16)ms16->wHitTestCode);
629 ms32.dwExtraInfo = ms16->dwExtraInfo;
630 ms32.hwnd = WIN_Handle32(ms16->hwnd);
631 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 );
637 ret = CallNextHookEx( hhook, code, wparam, lparam );
641 case WH_FOREGROUNDIDLE:
642 case WH_CALLWNDPROCRET:
643 case WH_SYSMSGFILTER:
644 case WH_JOURNALRECORD:
645 case WH_JOURNALPLAYBACK:
647 FIXME("\t[%i] 16to32 translation unimplemented\n", info->id);
648 ret = CallNextHookEx( hhook, code, wparam, lparam );
655 /***********************************************************************
656 * DefHookProc (USER.235)
658 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wparam, LPARAM lparam, HHOOK *hhook )
660 return CallNextHookEx16( *hhook, code, wparam, lparam );