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"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(hook);
39 static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp );
40 static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp );
41 static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp );
42 static LRESULT CALLBACK call_WH_CALLWNDPROC( INT code, WPARAM wp, LPARAM lp );
43 static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp );
44 static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp );
45 static LRESULT CALLBACK call_WH_SHELL( INT code, WPARAM wp, LPARAM lp );
47 #define WH_MAXHOOK16 WH_SHELL /* Win16 only supports up to WH_SHELL */
48 #define NB_HOOKS16 (WH_MAXHOOK16 - WH_MINHOOK + 1)
50 static const HOOKPROC hook_procs[NB_HOOKS16] =
52 call_WH_MSGFILTER, /* WH_MSGFILTER */
53 NULL, /* WH_JOURNALRECORD */
54 NULL, /* WH_JOURNALPLAYBACK */
55 call_WH_KEYBOARD, /* WH_KEYBOARD */
56 call_WH_GETMESSAGE, /* WH_GETMESSAGE */
57 call_WH_CALLWNDPROC, /* WH_CALLWNDPROC */
58 call_WH_CBT, /* WH_CBT */
59 NULL, /* WH_SYSMSGFILTER */
60 call_WH_MOUSE, /* WH_MOUSE */
61 NULL, /* WH_HARDWARE */
63 call_WH_SHELL /* WH_SHELL */
67 /* this structure is stored in the thread queue */
68 struct hook16_queue_info
70 INT id; /* id of current hook */
71 HHOOK hook[NB_HOOKS16]; /* Win32 hook handles */
72 HOOKPROC16 proc[NB_HOOKS16]; /* 16-bit hook procedures */
77 /***********************************************************************
80 inline static void map_msg_16_to_32( const MSG16 *msg16, MSG *msg32 )
82 msg32->hwnd = WIN_Handle32(msg16->hwnd);
83 msg32->message = msg16->message;
84 msg32->wParam = msg16->wParam;
85 msg32->lParam = msg16->lParam;
86 msg32->time = msg16->time;
87 msg32->pt.x = msg16->pt.x;
88 msg32->pt.y = msg16->pt.y;
92 /***********************************************************************
95 inline static void map_msg_32_to_16( const MSG *msg32, MSG16 *msg16 )
97 msg16->hwnd = HWND_16(msg32->hwnd);
98 msg16->message = msg32->message;
99 msg16->wParam = msg32->wParam;
100 msg16->lParam = msg32->lParam;
101 msg16->time = msg32->time;
102 msg16->pt.x = msg32->pt.x;
103 msg16->pt.y = msg32->pt.y;
107 /***********************************************************************
110 static LRESULT call_hook_16( INT id, INT code, WPARAM wp, LPARAM lp )
112 struct hook16_queue_info *info = get_user_thread_info()->hook16_info;
115 INT prev_id = info->id;
120 args[1] = HIWORD(lp);
121 args[0] = LOWORD(lp);
122 WOWCallback16Ex( (DWORD)info->proc[id - WH_MINHOOK], WCB16_PASCAL, sizeof(args), args, &ret );
126 /* Grrr. While the hook procedure is supposed to have an LRESULT return
127 value even in Win16, it seems that for those hook types where the
128 return value is interpreted as BOOL, Windows doesn't actually check
129 the HIWORD ... Some buggy Win16 programs, notably WINFILE, rely on
130 that, because they neglect to clear DX ... */
131 if (id != WH_JOURNALPLAYBACK) ret = LOWORD( ret );
136 struct wndproc_hook_params
143 /* callback for WINPROC_Call16To32A */
144 static LRESULT wndproc_hook_callback( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
145 LRESULT *result, void *arg )
147 struct wndproc_hook_params *params = arg;
155 return CallNextHookEx( params->hhook, params->code, params->wparam, (LPARAM)&cwp );
158 /* callback for WINPROC_Call32ATo16 */
159 static LRESULT wndproc_hook_callback16( HWND16 hwnd, UINT16 msg, WPARAM16 wp, LPARAM lp,
160 LRESULT *result, void *arg )
162 struct wndproc_hook_params *params = arg;
172 ret = call_hook_16( WH_CALLWNDPROC, params->code, params->wparam, lp );
180 /***********************************************************************
183 static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp )
185 MSG *msg32 = (MSG *)lp;
189 map_msg_32_to_16( msg32, &msg16 );
190 lp = MapLS( &msg16 );
191 ret = call_hook_16( WH_MSGFILTER, code, wp, lp );
197 /***********************************************************************
200 static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp )
202 return call_hook_16( WH_KEYBOARD, code, wp, lp );
206 /***********************************************************************
209 static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp )
211 MSG *msg32 = (MSG *)lp;
215 map_msg_32_to_16( msg32, &msg16 );
217 lp = MapLS( &msg16 );
218 ret = call_hook_16( WH_GETMESSAGE, code, wp, lp );
221 map_msg_16_to_32( &msg16, msg32 );
226 /***********************************************************************
227 * call_WH_CALLWNDPROC
229 static LRESULT CALLBACK call_WH_CALLWNDPROC( INT code, WPARAM wp, LPARAM lp )
231 struct wndproc_hook_params params;
232 CWPSTRUCT *cwp32 = (CWPSTRUCT *)lp;
237 return WINPROC_CallProc32ATo16( wndproc_hook_callback16, cwp32->hwnd, cwp32->message,
238 cwp32->wParam, cwp32->lParam, &result, ¶ms );
242 /***********************************************************************
245 static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp )
253 CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lp;
254 CBT_CREATEWND16 cbtcw16;
257 cs16.lpCreateParams = (SEGPTR)cbtcw32->lpcs->lpCreateParams;
258 cs16.hInstance = HINSTANCE_16(cbtcw32->lpcs->hInstance);
259 cs16.hMenu = HMENU_16(cbtcw32->lpcs->hMenu);
260 cs16.hwndParent = HWND_16(cbtcw32->lpcs->hwndParent);
261 cs16.cy = cbtcw32->lpcs->cy;
262 cs16.cx = cbtcw32->lpcs->cx;
263 cs16.y = cbtcw32->lpcs->y;
264 cs16.x = cbtcw32->lpcs->x;
265 cs16.style = cbtcw32->lpcs->style;
266 cs16.lpszName = MapLS( cbtcw32->lpcs->lpszName );
267 cs16.lpszClass = MapLS( cbtcw32->lpcs->lpszClass );
268 cs16.dwExStyle = cbtcw32->lpcs->dwExStyle;
270 cbtcw16.lpcs = (CREATESTRUCT16 *)MapLS( &cs16 );
271 cbtcw16.hwndInsertAfter = HWND_16( cbtcw32->hwndInsertAfter );
273 lp = MapLS( &cbtcw16 );
274 ret = call_hook_16( WH_CBT, code, wp, lp );
275 UnMapLS( cs16.lpszName );
276 UnMapLS( cs16.lpszClass );
278 cbtcw32->hwndInsertAfter = WIN_Handle32( cbtcw16.hwndInsertAfter );
279 UnMapLS( (SEGPTR)cbtcw16.lpcs );
286 CBTACTIVATESTRUCT *cas32 = (CBTACTIVATESTRUCT *)lp;
287 CBTACTIVATESTRUCT16 cas16;
289 cas16.fMouse = cas32->fMouse;
290 cas16.hWndActive = HWND_16( cas32->hWndActive );
292 lp = MapLS( &cas16 );
293 ret = call_hook_16( WH_CBT, code, wp, lp );
297 case HCBT_CLICKSKIPPED:
299 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
300 MOUSEHOOKSTRUCT16 ms16;
302 ms16.pt.x = ms32->pt.x;
303 ms16.pt.y = ms32->pt.y;
304 ms16.hwnd = HWND_16( ms32->hwnd );
305 ms16.wHitTestCode = ms32->wHitTestCode;
306 ms16.dwExtraInfo = ms32->dwExtraInfo;
309 ret = call_hook_16( WH_CBT, code, wp, lp );
315 RECT *rect32 = (RECT *)lp;
318 rect16.left = rect32->left;
319 rect16.top = rect32->top;
320 rect16.right = rect32->right;
321 rect16.bottom = rect32->bottom;
322 lp = MapLS( &rect16 );
323 ret = call_hook_16( WH_CBT, code, wp, lp );
332 /***********************************************************************
335 static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp )
337 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
338 MOUSEHOOKSTRUCT16 ms16;
341 ms16.pt.x = ms32->pt.x;
342 ms16.pt.y = ms32->pt.y;
343 ms16.hwnd = HWND_16( ms32->hwnd );
344 ms16.wHitTestCode = ms32->wHitTestCode;
345 ms16.dwExtraInfo = ms32->dwExtraInfo;
348 ret = call_hook_16( WH_MOUSE, code, wp, lp );
354 /***********************************************************************
357 static LRESULT CALLBACK call_WH_SHELL( INT code, WPARAM wp, LPARAM lp )
359 return call_hook_16( WH_SHELL, code, wp, lp );
363 /***********************************************************************
364 * SetWindowsHook (USER.121)
366 FARPROC16 WINAPI SetWindowsHook16( INT16 id, HOOKPROC16 proc )
368 HINSTANCE16 hInst = FarGetOwner16( HIWORD(proc) );
370 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
371 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
373 return (FARPROC16)SetWindowsHookEx16( id, proc, hInst, hTask );
377 /***********************************************************************
378 * SetWindowsHookEx (USER.291)
380 HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst, HTASK16 hTask )
382 struct user_thread_info *thread_info = get_user_thread_info();
383 struct hook16_queue_info *info;
385 int index = id - WH_MINHOOK;
387 if (id < WH_MINHOOK || id > WH_MAXHOOK16) return 0;
388 if (!hook_procs[index])
390 FIXME( "hook type %d broken in Win16\n", id );
393 if (!hTask) FIXME( "System-global hooks (%d) broken in Win16\n", id );
394 else if (hTask != GetCurrentTask())
396 FIXME( "setting hook (%d) on other task not supported\n", id );
400 if (!(info = thread_info->hook16_info))
402 if (!(info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*info) ))) return 0;
403 thread_info->hook16_info = info;
405 if (info->hook[index])
407 FIXME( "Multiple hooks (%d) for the same task not supported yet\n", id );
410 if (!(hook = SetWindowsHookExA( id, hook_procs[index], 0, GetCurrentThreadId() ))) return 0;
411 info->hook[index] = hook;
412 info->proc[index] = proc;
417 /***********************************************************************
418 * UnhookWindowsHook (USER.234)
420 BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
422 struct hook16_queue_info *info;
423 int index = id - WH_MINHOOK;
425 if (id < WH_MINHOOK || id > WH_MAXHOOK16) return FALSE;
426 if (!(info = get_user_thread_info()->hook16_info)) return FALSE;
427 if (info->proc[index] != proc) return FALSE;
428 if (!UnhookWindowsHookEx( info->hook[index] )) return FALSE;
429 info->hook[index] = 0;
430 info->proc[index] = 0;
435 /***********************************************************************
436 * UnhookWindowsHookEx (USER.292)
438 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
440 struct hook16_queue_info *info;
443 if (!(info = get_user_thread_info()->hook16_info)) return FALSE;
444 for (index = 0; index < NB_HOOKS16; index++)
446 if (info->hook[index] == hhook)
448 info->hook[index] = 0;
449 info->proc[index] = 0;
450 return UnhookWindowsHookEx( hhook );
457 /***********************************************************************
458 * CallMsgFilter32 (USER.823)
460 BOOL16 WINAPI CallMsgFilter32_16( MSG32_16 *lpmsg16_32, INT16 code, BOOL16 wHaveParamHigh )
465 if (GetSysModalWindow16()) return FALSE;
466 msg32.hwnd = WIN_Handle32( lpmsg16_32->msg.hwnd );
467 msg32.message = lpmsg16_32->msg.message;
468 msg32.lParam = lpmsg16_32->msg.lParam;
469 msg32.time = lpmsg16_32->msg.time;
470 msg32.pt.x = lpmsg16_32->msg.pt.x;
471 msg32.pt.y = lpmsg16_32->msg.pt.y;
472 if (wHaveParamHigh) msg32.wParam = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh);
473 else msg32.wParam = lpmsg16_32->msg.wParam;
475 ret = (BOOL16)CallMsgFilterA(&msg32, code);
477 lpmsg16_32->msg.hwnd = HWND_16( msg32.hwnd );
478 lpmsg16_32->msg.message = msg32.message;
479 lpmsg16_32->msg.wParam = LOWORD(msg32.wParam);
480 lpmsg16_32->msg.lParam = msg32.lParam;
481 lpmsg16_32->msg.time = msg32.time;
482 lpmsg16_32->msg.pt.x = msg32.pt.x;
483 lpmsg16_32->msg.pt.y = msg32.pt.y;
484 if (wHaveParamHigh) lpmsg16_32->wParamHigh = HIWORD(msg32.wParam);
489 /***********************************************************************
490 * CallMsgFilter (USER.123)
492 BOOL16 WINAPI CallMsgFilter16( MSG16 *msg, INT16 code )
494 return CallMsgFilter32_16( (MSG32_16 *)msg, code, FALSE );
498 /***********************************************************************
499 * CallNextHookEx (USER.293)
501 LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wparam, LPARAM lparam )
503 struct hook16_queue_info *info;
506 if (!(info = get_user_thread_info()->hook16_info)) return 0;
512 MSG16 *msg16 = MapSL(lparam);
515 map_msg_16_to_32( msg16, &msg32 );
516 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
522 MSG16 *msg16 = MapSL(lparam);
525 map_msg_16_to_32( msg16, &msg32 );
526 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
527 map_msg_32_to_16( &msg32, msg16 );
533 CWPSTRUCT16 *cwp16 = MapSL(lparam);
535 struct wndproc_hook_params params;
537 params.hhook = hhook;
539 params.wparam = wparam;
540 ret = WINPROC_CallProc16To32A( wndproc_hook_callback, cwp16->hwnd, cwp16->message,
541 cwp16->wParam, cwp16->lParam, &result, ¶ms );
550 CBT_CREATEWNDA cbtcw32;
552 CBT_CREATEWND16 *cbtcw16 = MapSL(lparam);
553 CREATESTRUCT16 *cs16 = MapSL( (SEGPTR)cbtcw16->lpcs );
555 cbtcw32.lpcs = &cs32;
556 cbtcw32.hwndInsertAfter = WIN_Handle32( cbtcw16->hwndInsertAfter );
558 cs32.lpCreateParams = (LPVOID)cs16->lpCreateParams;
559 cs32.hInstance = HINSTANCE_32(cs16->hInstance);
560 cs32.hMenu = HMENU_32(cs16->hMenu);
561 cs32.hwndParent = WIN_Handle32(cs16->hwndParent);
566 cs32.style = cs16->style;
567 cs32.lpszName = MapSL( cs16->lpszName );
568 cs32.lpszClass = MapSL( cs16->lpszClass );
569 cs32.dwExStyle = cs16->dwExStyle;
571 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cbtcw32 );
572 cbtcw16->hwndInsertAfter = HWND_16( cbtcw32.hwndInsertAfter );
577 CBTACTIVATESTRUCT16 *cas16 = MapSL(lparam);
578 CBTACTIVATESTRUCT cas32;
579 cas32.fMouse = cas16->fMouse;
580 cas32.hWndActive = WIN_Handle32(cas16->hWndActive);
581 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cas32 );
584 case HCBT_CLICKSKIPPED:
586 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
587 MOUSEHOOKSTRUCT ms32;
589 ms32.pt.x = ms16->pt.x;
590 ms32.pt.y = ms16->pt.y;
591 /* wHitTestCode may be negative, so convince compiler to do
592 correct sign extension. Yay. :| */
593 ms32.wHitTestCode = (INT)(INT16)ms16->wHitTestCode;
594 ms32.dwExtraInfo = ms16->dwExtraInfo;
595 ms32.hwnd = WIN_Handle32( ms16->hwnd );
596 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 );
601 RECT16 *rect16 = MapSL(lparam);
604 rect32.left = rect16->left;
605 rect32.top = rect16->top;
606 rect32.right = rect16->right;
607 rect32.bottom = rect16->bottom;
608 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&rect32 );
616 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
617 MOUSEHOOKSTRUCT ms32;
619 ms32.pt.x = ms16->pt.x;
620 ms32.pt.y = ms16->pt.y;
621 /* wHitTestCode may be negative, so convince compiler to do
622 correct sign extension. Yay. :| */
623 ms32.wHitTestCode = (INT)((INT16)ms16->wHitTestCode);
624 ms32.dwExtraInfo = ms16->dwExtraInfo;
625 ms32.hwnd = WIN_Handle32(ms16->hwnd);
626 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 );
632 ret = CallNextHookEx( hhook, code, wparam, lparam );
636 case WH_FOREGROUNDIDLE:
637 case WH_CALLWNDPROCRET:
638 case WH_SYSMSGFILTER:
639 case WH_JOURNALRECORD:
640 case WH_JOURNALPLAYBACK:
642 FIXME("\t[%i] 16to32 translation unimplemented\n", info->id);
643 ret = CallNextHookEx( hhook, code, wparam, lparam );
650 /***********************************************************************
651 * DefHookProc (USER.235)
653 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wparam, LPARAM lparam, HHOOK *hhook )
655 return CallNextHookEx16( *hhook, code, wparam, lparam );