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"
32 #include "user_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(hook);
38 static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp );
39 static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp );
40 static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp );
41 static LRESULT CALLBACK call_WH_CALLWNDPROC( INT code, WPARAM wp, LPARAM lp );
42 static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp );
43 static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp );
44 static LRESULT CALLBACK call_WH_SHELL( INT code, WPARAM wp, LPARAM lp );
46 #define WH_MAXHOOK16 WH_SHELL /* Win16 only supports up to WH_SHELL */
47 #define NB_HOOKS16 (WH_MAXHOOK16 - WH_MINHOOK + 1)
49 static const HOOKPROC hook_procs[NB_HOOKS16] =
51 call_WH_MSGFILTER, /* WH_MSGFILTER */
52 NULL, /* WH_JOURNALRECORD */
53 NULL, /* WH_JOURNALPLAYBACK */
54 call_WH_KEYBOARD, /* WH_KEYBOARD */
55 call_WH_GETMESSAGE, /* WH_GETMESSAGE */
56 call_WH_CALLWNDPROC, /* WH_CALLWNDPROC */
57 call_WH_CBT, /* WH_CBT */
58 NULL, /* WH_SYSMSGFILTER */
59 call_WH_MOUSE, /* WH_MOUSE */
60 NULL, /* WH_HARDWARE */
62 call_WH_SHELL /* WH_SHELL */
66 /* this structure is stored in the thread queue */
67 struct hook16_queue_info
69 INT id; /* id of current hook */
70 HHOOK hook[NB_HOOKS16]; /* Win32 hook handles */
71 HOOKPROC16 proc[NB_HOOKS16]; /* 16-bit hook procedures */
76 /***********************************************************************
79 static inline void map_msg_16_to_32( const MSG16 *msg16, MSG *msg32 )
81 msg32->hwnd = WIN_Handle32(msg16->hwnd);
82 msg32->message = msg16->message;
83 msg32->wParam = msg16->wParam;
84 msg32->lParam = msg16->lParam;
85 msg32->time = msg16->time;
86 msg32->pt.x = msg16->pt.x;
87 msg32->pt.y = msg16->pt.y;
91 /***********************************************************************
94 static inline void map_msg_32_to_16( const MSG *msg32, MSG16 *msg16 )
96 msg16->hwnd = HWND_16(msg32->hwnd);
97 msg16->message = msg32->message;
98 msg16->wParam = msg32->wParam;
99 msg16->lParam = msg32->lParam;
100 msg16->time = msg32->time;
101 msg16->pt.x = msg32->pt.x;
102 msg16->pt.y = msg32->pt.y;
106 /***********************************************************************
109 static LRESULT call_hook_16( INT id, INT code, WPARAM wp, LPARAM lp )
111 struct hook16_queue_info *info = get_user_thread_info()->hook16_info;
114 INT prev_id = info->id;
119 args[1] = HIWORD(lp);
120 args[0] = LOWORD(lp);
121 WOWCallback16Ex( (DWORD)info->proc[id - WH_MINHOOK], WCB16_PASCAL, sizeof(args), args, &ret );
125 /* Grrr. While the hook procedure is supposed to have an LRESULT return
126 value even in Win16, it seems that for those hook types where the
127 return value is interpreted as BOOL, Windows doesn't actually check
128 the HIWORD ... Some buggy Win16 programs, notably WINFILE, rely on
129 that, because they neglect to clear DX ... */
130 if (id != WH_JOURNALPLAYBACK) ret = LOWORD( ret );
135 struct wndproc_hook_params
142 /* callback for WINPROC_Call16To32A */
143 static LRESULT wndproc_hook_callback( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
144 LRESULT *result, void *arg )
146 struct wndproc_hook_params *params = arg;
154 return CallNextHookEx( params->hhook, params->code, params->wparam, (LPARAM)&cwp );
157 /* callback for WINPROC_Call32ATo16 */
158 static LRESULT wndproc_hook_callback16( HWND16 hwnd, UINT16 msg, WPARAM16 wp, LPARAM lp,
159 LRESULT *result, void *arg )
161 struct wndproc_hook_params *params = arg;
171 ret = call_hook_16( WH_CALLWNDPROC, params->code, params->wparam, lp );
179 /***********************************************************************
182 static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp )
184 MSG *msg32 = (MSG *)lp;
188 map_msg_32_to_16( msg32, &msg16 );
189 lp = MapLS( &msg16 );
190 ret = call_hook_16( WH_MSGFILTER, code, wp, lp );
196 /***********************************************************************
199 static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp )
201 return call_hook_16( WH_KEYBOARD, code, wp, lp );
205 /***********************************************************************
208 static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp )
210 MSG *msg32 = (MSG *)lp;
214 map_msg_32_to_16( msg32, &msg16 );
216 lp = MapLS( &msg16 );
217 ret = call_hook_16( WH_GETMESSAGE, code, wp, lp );
220 map_msg_16_to_32( &msg16, msg32 );
225 /***********************************************************************
226 * call_WH_CALLWNDPROC
228 static LRESULT CALLBACK call_WH_CALLWNDPROC( INT code, WPARAM wp, LPARAM lp )
230 struct wndproc_hook_params params;
231 CWPSTRUCT *cwp32 = (CWPSTRUCT *)lp;
236 return WINPROC_CallProc32ATo16( wndproc_hook_callback16, cwp32->hwnd, cwp32->message,
237 cwp32->wParam, cwp32->lParam, &result, ¶ms );
241 /***********************************************************************
244 static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp )
252 CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lp;
253 CBT_CREATEWND16 cbtcw16;
256 cs16.lpCreateParams = (SEGPTR)cbtcw32->lpcs->lpCreateParams;
257 cs16.hInstance = HINSTANCE_16(cbtcw32->lpcs->hInstance);
258 cs16.hMenu = HMENU_16(cbtcw32->lpcs->hMenu);
259 cs16.hwndParent = HWND_16(cbtcw32->lpcs->hwndParent);
260 cs16.cy = cbtcw32->lpcs->cy;
261 cs16.cx = cbtcw32->lpcs->cx;
262 cs16.y = cbtcw32->lpcs->y;
263 cs16.x = cbtcw32->lpcs->x;
264 cs16.style = cbtcw32->lpcs->style;
265 cs16.lpszName = MapLS( cbtcw32->lpcs->lpszName );
266 cs16.lpszClass = MapLS( cbtcw32->lpcs->lpszClass );
267 cs16.dwExStyle = cbtcw32->lpcs->dwExStyle;
269 cbtcw16.lpcs = (CREATESTRUCT16 *)MapLS( &cs16 );
270 cbtcw16.hwndInsertAfter = HWND_16( cbtcw32->hwndInsertAfter );
272 lp = MapLS( &cbtcw16 );
273 ret = call_hook_16( WH_CBT, code, wp, lp );
274 UnMapLS( cs16.lpszName );
275 UnMapLS( cs16.lpszClass );
277 cbtcw32->hwndInsertAfter = WIN_Handle32( cbtcw16.hwndInsertAfter );
278 UnMapLS( (SEGPTR)cbtcw16.lpcs );
285 CBTACTIVATESTRUCT *cas32 = (CBTACTIVATESTRUCT *)lp;
286 CBTACTIVATESTRUCT16 cas16;
288 cas16.fMouse = cas32->fMouse;
289 cas16.hWndActive = HWND_16( cas32->hWndActive );
291 lp = MapLS( &cas16 );
292 ret = call_hook_16( WH_CBT, code, wp, lp );
296 case HCBT_CLICKSKIPPED:
298 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
299 MOUSEHOOKSTRUCT16 ms16;
301 ms16.pt.x = ms32->pt.x;
302 ms16.pt.y = ms32->pt.y;
303 ms16.hwnd = HWND_16( ms32->hwnd );
304 ms16.wHitTestCode = ms32->wHitTestCode;
305 ms16.dwExtraInfo = ms32->dwExtraInfo;
308 ret = call_hook_16( WH_CBT, code, wp, lp );
314 RECT *rect32 = (RECT *)lp;
317 rect16.left = rect32->left;
318 rect16.top = rect32->top;
319 rect16.right = rect32->right;
320 rect16.bottom = rect32->bottom;
321 lp = MapLS( &rect16 );
322 ret = call_hook_16( WH_CBT, code, wp, lp );
331 /***********************************************************************
334 static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp )
336 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
337 MOUSEHOOKSTRUCT16 ms16;
340 ms16.pt.x = ms32->pt.x;
341 ms16.pt.y = ms32->pt.y;
342 ms16.hwnd = HWND_16( ms32->hwnd );
343 ms16.wHitTestCode = ms32->wHitTestCode;
344 ms16.dwExtraInfo = ms32->dwExtraInfo;
347 ret = call_hook_16( WH_MOUSE, code, wp, lp );
353 /***********************************************************************
356 static LRESULT CALLBACK call_WH_SHELL( INT code, WPARAM wp, LPARAM lp )
358 return call_hook_16( WH_SHELL, code, wp, lp );
362 /***********************************************************************
363 * SetWindowsHook (USER.121)
365 FARPROC16 WINAPI SetWindowsHook16( INT16 id, HOOKPROC16 proc )
367 HINSTANCE16 hInst = FarGetOwner16( HIWORD(proc) );
369 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
370 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
372 return (FARPROC16)SetWindowsHookEx16( id, proc, hInst, hTask );
376 /***********************************************************************
377 * SetWindowsHookEx (USER.291)
379 HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst, HTASK16 hTask )
381 struct user_thread_info *thread_info = get_user_thread_info();
382 struct hook16_queue_info *info;
384 int index = id - WH_MINHOOK;
386 if (id < WH_MINHOOK || id > WH_MAXHOOK16) return 0;
387 if (!hook_procs[index])
389 FIXME( "hook type %d broken in Win16\n", id );
392 if (!hTask) FIXME( "System-global hooks (%d) broken in Win16\n", id );
393 else if (hTask != GetCurrentTask())
395 FIXME( "setting hook (%d) on other task not supported\n", id );
399 if (!(info = thread_info->hook16_info))
401 if (!(info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*info) ))) return 0;
402 thread_info->hook16_info = info;
404 if (info->hook[index])
406 FIXME( "Multiple hooks (%d) for the same task not supported yet\n", id );
409 if (!(hook = SetWindowsHookExA( id, hook_procs[index], 0, GetCurrentThreadId() ))) return 0;
410 info->hook[index] = hook;
411 info->proc[index] = proc;
416 /***********************************************************************
417 * UnhookWindowsHook (USER.234)
419 BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
421 struct hook16_queue_info *info;
422 int index = id - WH_MINHOOK;
424 if (id < WH_MINHOOK || id > WH_MAXHOOK16) return FALSE;
425 if (!(info = get_user_thread_info()->hook16_info)) return FALSE;
426 if (info->proc[index] != proc) return FALSE;
427 if (!UnhookWindowsHookEx( info->hook[index] )) return FALSE;
428 info->hook[index] = 0;
429 info->proc[index] = 0;
434 /***********************************************************************
435 * UnhookWindowsHookEx (USER.292)
437 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
439 struct hook16_queue_info *info;
442 if (!(info = get_user_thread_info()->hook16_info)) return FALSE;
443 for (index = 0; index < NB_HOOKS16; index++)
445 if (info->hook[index] == hhook)
447 info->hook[index] = 0;
448 info->proc[index] = 0;
449 return UnhookWindowsHookEx( hhook );
456 /***********************************************************************
457 * CallMsgFilter32 (USER.823)
459 BOOL16 WINAPI CallMsgFilter32_16( MSG32_16 *lpmsg16_32, INT16 code, BOOL16 wHaveParamHigh )
464 if (GetSysModalWindow16()) return FALSE;
465 msg32.hwnd = WIN_Handle32( lpmsg16_32->msg.hwnd );
466 msg32.message = lpmsg16_32->msg.message;
467 msg32.lParam = lpmsg16_32->msg.lParam;
468 msg32.time = lpmsg16_32->msg.time;
469 msg32.pt.x = lpmsg16_32->msg.pt.x;
470 msg32.pt.y = lpmsg16_32->msg.pt.y;
471 if (wHaveParamHigh) msg32.wParam = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh);
472 else msg32.wParam = lpmsg16_32->msg.wParam;
474 ret = (BOOL16)CallMsgFilterA(&msg32, code);
476 lpmsg16_32->msg.hwnd = HWND_16( msg32.hwnd );
477 lpmsg16_32->msg.message = msg32.message;
478 lpmsg16_32->msg.wParam = LOWORD(msg32.wParam);
479 lpmsg16_32->msg.lParam = msg32.lParam;
480 lpmsg16_32->msg.time = msg32.time;
481 lpmsg16_32->msg.pt.x = msg32.pt.x;
482 lpmsg16_32->msg.pt.y = msg32.pt.y;
483 if (wHaveParamHigh) lpmsg16_32->wParamHigh = HIWORD(msg32.wParam);
488 /***********************************************************************
489 * CallMsgFilter (USER.123)
491 BOOL16 WINAPI CallMsgFilter16( MSG16 *msg, INT16 code )
493 return CallMsgFilter32_16( (MSG32_16 *)msg, code, FALSE );
497 /***********************************************************************
498 * CallNextHookEx (USER.293)
500 LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wparam, LPARAM lparam )
502 struct hook16_queue_info *info;
505 if (!(info = get_user_thread_info()->hook16_info)) return 0;
511 MSG16 *msg16 = MapSL(lparam);
514 map_msg_16_to_32( msg16, &msg32 );
515 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
521 MSG16 *msg16 = MapSL(lparam);
524 map_msg_16_to_32( msg16, &msg32 );
525 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
526 map_msg_32_to_16( &msg32, msg16 );
532 CWPSTRUCT16 *cwp16 = MapSL(lparam);
534 struct wndproc_hook_params params;
536 params.hhook = hhook;
538 params.wparam = wparam;
539 ret = WINPROC_CallProc16To32A( wndproc_hook_callback, cwp16->hwnd, cwp16->message,
540 cwp16->wParam, cwp16->lParam, &result, ¶ms );
549 CBT_CREATEWNDA cbtcw32;
551 CBT_CREATEWND16 *cbtcw16 = MapSL(lparam);
552 CREATESTRUCT16 *cs16 = MapSL( (SEGPTR)cbtcw16->lpcs );
554 cbtcw32.lpcs = &cs32;
555 cbtcw32.hwndInsertAfter = WIN_Handle32( cbtcw16->hwndInsertAfter );
557 cs32.lpCreateParams = (LPVOID)cs16->lpCreateParams;
558 cs32.hInstance = HINSTANCE_32(cs16->hInstance);
559 cs32.hMenu = HMENU_32(cs16->hMenu);
560 cs32.hwndParent = WIN_Handle32(cs16->hwndParent);
565 cs32.style = cs16->style;
566 cs32.lpszName = MapSL( cs16->lpszName );
567 cs32.lpszClass = MapSL( cs16->lpszClass );
568 cs32.dwExStyle = cs16->dwExStyle;
570 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cbtcw32 );
571 cbtcw16->hwndInsertAfter = HWND_16( cbtcw32.hwndInsertAfter );
576 CBTACTIVATESTRUCT16 *cas16 = MapSL(lparam);
577 CBTACTIVATESTRUCT cas32;
578 cas32.fMouse = cas16->fMouse;
579 cas32.hWndActive = WIN_Handle32(cas16->hWndActive);
580 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cas32 );
583 case HCBT_CLICKSKIPPED:
585 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
586 MOUSEHOOKSTRUCT ms32;
588 ms32.pt.x = ms16->pt.x;
589 ms32.pt.y = ms16->pt.y;
590 /* wHitTestCode may be negative, so convince compiler to do
591 correct sign extension. Yay. :| */
592 ms32.wHitTestCode = (INT)(INT16)ms16->wHitTestCode;
593 ms32.dwExtraInfo = ms16->dwExtraInfo;
594 ms32.hwnd = WIN_Handle32( ms16->hwnd );
595 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 );
600 RECT16 *rect16 = MapSL(lparam);
603 rect32.left = rect16->left;
604 rect32.top = rect16->top;
605 rect32.right = rect16->right;
606 rect32.bottom = rect16->bottom;
607 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&rect32 );
615 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
616 MOUSEHOOKSTRUCT ms32;
618 ms32.pt.x = ms16->pt.x;
619 ms32.pt.y = ms16->pt.y;
620 /* wHitTestCode may be negative, so convince compiler to do
621 correct sign extension. Yay. :| */
622 ms32.wHitTestCode = (INT)((INT16)ms16->wHitTestCode);
623 ms32.dwExtraInfo = ms16->dwExtraInfo;
624 ms32.hwnd = WIN_Handle32(ms16->hwnd);
625 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 );
631 ret = CallNextHookEx( hhook, code, wparam, lparam );
635 case WH_FOREGROUNDIDLE:
636 case WH_CALLWNDPROCRET:
637 case WH_SYSMSGFILTER:
638 case WH_JOURNALRECORD:
639 case WH_JOURNALPLAYBACK:
641 FIXME("\t[%i] 16to32 translation unimplemented\n", info->id);
642 ret = CallNextHookEx( hhook, code, wparam, lparam );
649 /***********************************************************************
650 * DefHookProc (USER.235)
652 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wparam, LPARAM lparam, HHOOK *hhook )
654 return CallNextHookEx16( *hhook, code, wparam, lparam );