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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 /***********************************************************************
139 static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp )
141 MSG *msg32 = (MSG *)lp;
145 map_msg_32_to_16( msg32, &msg16 );
146 lp = MapLS( &msg16 );
147 ret = call_hook_16( WH_MSGFILTER, code, wp, lp );
153 /***********************************************************************
156 static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp )
158 return call_hook_16( WH_KEYBOARD, code, wp, lp );
162 /***********************************************************************
165 static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp )
167 MSG *msg32 = (MSG *)lp;
171 map_msg_32_to_16( msg32, &msg16 );
173 lp = MapLS( &msg16 );
174 ret = call_hook_16( WH_GETMESSAGE, code, wp, lp );
177 map_msg_16_to_32( &msg16, msg32 );
182 /***********************************************************************
183 * call_WH_CALLWNDPROC
185 static LRESULT CALLBACK call_WH_CALLWNDPROC( INT code, WPARAM wp, LPARAM lp )
187 CWPSTRUCT *cwp32 = (CWPSTRUCT *)lp;
192 cwp16.hwnd = HWND_16(cwp32->hwnd);
193 cwp16.lParam = cwp32->lParam;
195 WINPROC_MapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam,
196 &cwp16.message, &cwp16.wParam, &cwp16.lParam );
198 lp = MapLS( &cwp16 );
199 ret = call_hook_16( WH_CALLWNDPROC, code, wp, lp );
202 mp16.wParam = cwp16.wParam;
203 mp16.lParam = cwp16.lParam;
205 WINPROC_UnmapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam, cwp32->lParam, &mp16 );
210 /***********************************************************************
213 static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp )
221 CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lp;
222 CBT_CREATEWND16 cbtcw16;
225 cs16.lpCreateParams = (SEGPTR)cbtcw32->lpcs->lpCreateParams;
226 cs16.hInstance = HINSTANCE_16(cbtcw32->lpcs->hInstance);
227 cs16.hMenu = HMENU_16(cbtcw32->lpcs->hMenu);
228 cs16.hwndParent = HWND_16(cbtcw32->lpcs->hwndParent);
229 cs16.cy = cbtcw32->lpcs->cy;
230 cs16.cx = cbtcw32->lpcs->cx;
231 cs16.y = cbtcw32->lpcs->y;
232 cs16.x = cbtcw32->lpcs->x;
233 cs16.style = cbtcw32->lpcs->style;
234 cs16.lpszName = MapLS( cbtcw32->lpcs->lpszName );
235 cs16.lpszClass = MapLS( cbtcw32->lpcs->lpszClass );
236 cs16.dwExStyle = cbtcw32->lpcs->dwExStyle;
238 cbtcw16.lpcs = (CREATESTRUCT16 *)MapLS( &cs16 );
239 cbtcw16.hwndInsertAfter = HWND_16( cbtcw32->hwndInsertAfter );
241 lp = MapLS( &cbtcw16 );
242 ret = call_hook_16( WH_CBT, code, wp, lp );
243 UnMapLS( cs16.lpszName );
244 UnMapLS( cs16.lpszClass );
246 cbtcw32->hwndInsertAfter = WIN_Handle32( cbtcw16.hwndInsertAfter );
247 UnMapLS( (SEGPTR)cbtcw16.lpcs );
254 CBTACTIVATESTRUCT *cas32 = (CBTACTIVATESTRUCT *)lp;
255 CBTACTIVATESTRUCT16 cas16;
257 cas16.fMouse = cas32->fMouse;
258 cas16.hWndActive = HWND_16( cas32->hWndActive );
260 lp = MapLS( &cas16 );
261 ret = call_hook_16( WH_CBT, code, wp, lp );
265 case HCBT_CLICKSKIPPED:
267 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
268 MOUSEHOOKSTRUCT16 ms16;
270 ms16.pt.x = ms32->pt.x;
271 ms16.pt.y = ms32->pt.y;
272 ms16.hwnd = HWND_16( ms32->hwnd );
273 ms16.wHitTestCode = ms32->wHitTestCode;
274 ms16.dwExtraInfo = ms32->dwExtraInfo;
277 ret = call_hook_16( WH_CBT, code, wp, lp );
283 RECT *rect32 = (RECT *)lp;
286 rect16.left = rect32->left;
287 rect16.top = rect32->top;
288 rect16.right = rect32->right;
289 rect16.bottom = rect32->bottom;
290 lp = MapLS( &rect16 );
291 ret = call_hook_16( WH_CBT, code, wp, lp );
300 /***********************************************************************
303 static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp )
305 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
306 MOUSEHOOKSTRUCT16 ms16;
309 ms16.pt.x = ms32->pt.x;
310 ms16.pt.y = ms32->pt.y;
311 ms16.hwnd = HWND_16( ms32->hwnd );
312 ms16.wHitTestCode = ms32->wHitTestCode;
313 ms16.dwExtraInfo = ms32->dwExtraInfo;
316 ret = call_hook_16( WH_MOUSE, code, wp, lp );
322 /***********************************************************************
325 static LRESULT CALLBACK call_WH_SHELL( INT code, WPARAM wp, LPARAM lp )
327 return call_hook_16( WH_SHELL, code, wp, lp );
331 /***********************************************************************
332 * SetWindowsHook (USER.121)
334 FARPROC16 WINAPI SetWindowsHook16( INT16 id, HOOKPROC16 proc )
336 HINSTANCE16 hInst = FarGetOwner16( HIWORD(proc) );
338 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
339 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
341 return (FARPROC16)SetWindowsHookEx16( id, proc, hInst, hTask );
345 /***********************************************************************
346 * SetWindowsHookEx (USER.291)
348 HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst, HTASK16 hTask )
350 struct user_thread_info *thread_info = get_user_thread_info();
351 struct hook16_queue_info *info;
353 int index = id - WH_MINHOOK;
355 if (id < WH_MINHOOK || id > WH_MAXHOOK16) return 0;
356 if (!hook_procs[index])
358 FIXME( "hook type %d broken in Win16\n", id );
361 if (!hTask) FIXME( "System-global hooks (%d) broken in Win16\n", id );
362 else if (hTask != GetCurrentTask())
364 FIXME( "setting hook (%d) on other task not supported\n", id );
368 if (!(info = thread_info->hook16_info))
370 if (!(info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*info) ))) return 0;
371 thread_info->hook16_info = info;
373 if (info->hook[index])
375 FIXME( "Multiple hooks (%d) for the same task not supported yet\n", id );
378 if (!(hook = SetWindowsHookExA( id, hook_procs[index], 0, GetCurrentThreadId() ))) return 0;
379 info->hook[index] = hook;
380 info->proc[index] = proc;
385 /***********************************************************************
386 * UnhookWindowsHook (USER.234)
388 BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
390 struct hook16_queue_info *info;
391 int index = id - WH_MINHOOK;
393 if (id < WH_MINHOOK || id > WH_MAXHOOK16) return FALSE;
394 if (!(info = get_user_thread_info()->hook16_info)) return FALSE;
395 if (info->proc[index] != proc) return FALSE;
396 if (!UnhookWindowsHookEx( info->hook[index] )) return FALSE;
397 info->hook[index] = 0;
398 info->proc[index] = 0;
403 /***********************************************************************
404 * UnhookWindowsHookEx (USER.292)
406 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
408 struct hook16_queue_info *info;
411 if (!(info = get_user_thread_info()->hook16_info)) return FALSE;
412 for (index = 0; index < NB_HOOKS16; index++)
414 if (info->hook[index] == hhook)
416 info->hook[index] = 0;
417 info->proc[index] = 0;
418 return UnhookWindowsHookEx( hhook );
425 /***********************************************************************
426 * CallMsgFilter32 (USER.823)
428 BOOL16 WINAPI CallMsgFilter32_16( MSG32_16 *lpmsg16_32, INT16 code, BOOL16 wHaveParamHigh )
433 if (GetSysModalWindow16()) return FALSE;
434 msg32.hwnd = WIN_Handle32( lpmsg16_32->msg.hwnd );
435 msg32.message = lpmsg16_32->msg.message;
436 msg32.lParam = lpmsg16_32->msg.lParam;
437 msg32.time = lpmsg16_32->msg.time;
438 msg32.pt.x = lpmsg16_32->msg.pt.x;
439 msg32.pt.y = lpmsg16_32->msg.pt.y;
440 if (wHaveParamHigh) msg32.wParam = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh);
441 else msg32.wParam = lpmsg16_32->msg.wParam;
443 ret = (BOOL16)CallMsgFilterA(&msg32, code);
445 lpmsg16_32->msg.hwnd = HWND_16( msg32.hwnd );
446 lpmsg16_32->msg.message = msg32.message;
447 lpmsg16_32->msg.wParam = LOWORD(msg32.wParam);
448 lpmsg16_32->msg.lParam = msg32.lParam;
449 lpmsg16_32->msg.time = msg32.time;
450 lpmsg16_32->msg.pt.x = msg32.pt.x;
451 lpmsg16_32->msg.pt.y = msg32.pt.y;
452 if (wHaveParamHigh) lpmsg16_32->wParamHigh = HIWORD(msg32.wParam);
457 /***********************************************************************
458 * CallMsgFilter (USER.123)
460 BOOL16 WINAPI CallMsgFilter16( MSG16 *msg, INT16 code )
462 return CallMsgFilter32_16( (MSG32_16 *)msg, code, FALSE );
466 /***********************************************************************
467 * CallNextHookEx (USER.293)
469 LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wparam, LPARAM lparam )
471 struct hook16_queue_info *info;
474 if (!(info = get_user_thread_info()->hook16_info)) return 0;
480 MSG16 *msg16 = MapSL(lparam);
483 map_msg_16_to_32( msg16, &msg32 );
484 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
490 MSG16 *msg16 = MapSL(lparam);
493 map_msg_16_to_32( msg16, &msg32 );
494 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
495 map_msg_32_to_16( &msg32, msg16 );
501 CWPSTRUCT16 *cwp16 = MapSL(lparam);
504 cwp32.hwnd = WIN_Handle32(cwp16->hwnd);
505 cwp32.lParam = cwp16->lParam;
507 WINPROC_MapMsg16To32A( cwp32.hwnd, cwp16->message, cwp16->wParam,
508 &cwp32.message, &cwp32.wParam, &cwp32.lParam );
509 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cwp32 );
510 WINPROC_UnmapMsg16To32A( cwp32.hwnd, cwp32.message, cwp32.wParam, cwp32.lParam, 0 );
519 CBT_CREATEWNDA cbtcw32;
521 CBT_CREATEWND16 *cbtcw16 = MapSL(lparam);
522 CREATESTRUCT16 *cs16 = MapSL( (SEGPTR)cbtcw16->lpcs );
524 cbtcw32.lpcs = &cs32;
525 cbtcw32.hwndInsertAfter = WIN_Handle32( cbtcw16->hwndInsertAfter );
527 cs32.lpCreateParams = (LPVOID)cs16->lpCreateParams;
528 cs32.hInstance = HINSTANCE_32(cs16->hInstance);
529 cs32.hMenu = HMENU_32(cs16->hMenu);
530 cs32.hwndParent = WIN_Handle32(cs16->hwndParent);
535 cs32.style = cs16->style;
536 cs32.lpszName = MapSL( cs16->lpszName );
537 cs32.lpszClass = MapSL( cs16->lpszClass );
538 cs32.dwExStyle = cs16->dwExStyle;
540 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cbtcw32 );
541 cbtcw16->hwndInsertAfter = HWND_16( cbtcw32.hwndInsertAfter );
546 CBTACTIVATESTRUCT16 *cas16 = MapSL(lparam);
547 CBTACTIVATESTRUCT cas32;
548 cas32.fMouse = cas16->fMouse;
549 cas32.hWndActive = WIN_Handle32(cas16->hWndActive);
550 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cas32 );
553 case HCBT_CLICKSKIPPED:
555 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
556 MOUSEHOOKSTRUCT ms32;
558 ms32.pt.x = ms16->pt.x;
559 ms32.pt.y = ms16->pt.y;
560 /* wHitTestCode may be negative, so convince compiler to do
561 correct sign extension. Yay. :| */
562 ms32.wHitTestCode = (INT)(INT16)ms16->wHitTestCode;
563 ms32.dwExtraInfo = ms16->dwExtraInfo;
564 ms32.hwnd = WIN_Handle32( ms16->hwnd );
565 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 );
570 RECT16 *rect16 = MapSL(lparam);
573 rect32.left = rect16->left;
574 rect32.top = rect16->top;
575 rect32.right = rect16->right;
576 rect32.bottom = rect16->bottom;
577 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&rect32 );
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 );
601 ret = CallNextHookEx( hhook, code, wparam, lparam );
605 case WH_FOREGROUNDIDLE:
606 case WH_CALLWNDPROCRET:
607 case WH_SYSMSGFILTER:
608 case WH_JOURNALRECORD:
609 case WH_JOURNALPLAYBACK:
611 FIXME("\t[%i] 16to32 translation unimplemented\n", info->id);
612 ret = CallNextHookEx( hhook, code, wparam, lparam );
619 /***********************************************************************
620 * DefHookProc (USER.235)
622 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wparam, LPARAM lparam, HHOOK *hhook )
624 return CallNextHookEx16( *hhook, code, wparam, lparam );