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
28 #include "wine/winuser16.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 /* this structure is stored in the thread queue */
66 struct hook16_queue_info
68 INT id; /* id of current hook */
69 HHOOK hook[NB_HOOKS16]; /* Win32 hook handles */
70 HOOKPROC16 proc[NB_HOOKS16]; /* 16-bit hook procedures */
74 /* ### start build ### */
75 extern LONG CALLBACK HOOK_CallTo16_long_wwl(HOOKPROC16,WORD,WORD,LONG);
76 /* ### stop build ### */
79 /***********************************************************************
82 inline static void map_msg_16_to_32( const MSG16 *msg16, MSG *msg32 )
84 msg32->hwnd = WIN_Handle32(msg16->hwnd);
85 msg32->message = msg16->message;
86 msg32->wParam = msg16->wParam;
87 msg32->lParam = msg16->lParam;
88 msg32->time = msg16->time;
89 msg32->pt.x = msg16->pt.x;
90 msg32->pt.y = msg16->pt.y;
94 /***********************************************************************
97 inline static void map_msg_32_to_16( const MSG *msg32, MSG16 *msg16 )
99 msg16->hwnd = HWND_16(msg32->hwnd);
100 msg16->message = msg32->message;
101 msg16->wParam = msg32->wParam;
102 msg16->lParam = msg32->lParam;
103 msg16->time = msg32->time;
104 msg16->pt.x = msg32->pt.x;
105 msg16->pt.y = msg32->pt.y;
109 /***********************************************************************
112 static LRESULT call_hook_16( INT id, INT code, WPARAM wp, LPARAM lp )
114 struct hook16_queue_info *info = QUEUE_Current()->hook16_info;
116 INT prev_id = info->id;
118 ret = HOOK_CallTo16_long_wwl( info->proc[id - WH_MINHOOK], code, wp, lp );
121 /* Grrr. While the hook procedure is supposed to have an LRESULT return
122 value even in Win16, it seems that for those hook types where the
123 return value is interpreted as BOOL, Windows doesn't actually check
124 the HIWORD ... Some buggy Win16 programs, notably WINFILE, rely on
125 that, because they neglect to clear DX ... */
126 if (id != WH_JOURNALPLAYBACK) ret = LOWORD( ret );
131 /***********************************************************************
134 static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp )
136 MSG *msg32 = (MSG *)lp;
140 map_msg_32_to_16( msg32, &msg16 );
141 lp = MapLS( &msg16 );
142 ret = call_hook_16( WH_MSGFILTER, code, wp, lp );
148 /***********************************************************************
151 static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp )
153 return call_hook_16( WH_KEYBOARD, code, wp, lp );
157 /***********************************************************************
160 static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp )
162 MSG *msg32 = (MSG *)lp;
166 map_msg_32_to_16( msg32, &msg16 );
168 lp = MapLS( &msg16 );
169 ret = call_hook_16( WH_GETMESSAGE, code, wp, lp );
172 map_msg_16_to_32( &msg16, msg32 );
177 /***********************************************************************
178 * call_WH_CALLWNDPROC
180 static LRESULT CALLBACK call_WH_CALLWNDPROC( INT code, WPARAM wp, LPARAM lp )
182 CWPSTRUCT *cwp32 = (CWPSTRUCT *)lp;
187 cwp16.hwnd = HWND_16(cwp32->hwnd);
188 cwp16.lParam = cwp32->lParam;
190 WINPROC_MapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam,
191 &cwp16.message, &cwp16.wParam, &cwp16.lParam );
193 lp = MapLS( &cwp16 );
194 ret = call_hook_16( WH_CALLWNDPROC, code, wp, lp );
197 mp16.wParam = cwp16.wParam;
198 mp16.lParam = cwp16.lParam;
200 WINPROC_UnmapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam, cwp32->lParam, &mp16 );
205 /***********************************************************************
208 static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp )
216 CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lp;
217 CBT_CREATEWND16 cbtcw16;
220 cs16.lpCreateParams = cbtcw32->lpcs->lpCreateParams;
221 cs16.hInstance = MapHModuleLS(cbtcw32->lpcs->hInstance);
222 cs16.hMenu = HMENU_16(cbtcw32->lpcs->hMenu);
223 cs16.hwndParent = HWND_16(cbtcw32->lpcs->hwndParent);
224 cs16.cy = cbtcw32->lpcs->cy;
225 cs16.cx = cbtcw32->lpcs->cx;
226 cs16.y = cbtcw32->lpcs->y;
227 cs16.x = cbtcw32->lpcs->x;
228 cs16.style = cbtcw32->lpcs->style;
229 cs16.lpszName = MapLS( cbtcw32->lpcs->lpszName );
230 cs16.lpszClass = MapLS( cbtcw32->lpcs->lpszClass );
231 cs16.dwExStyle = cbtcw32->lpcs->dwExStyle;
233 cbtcw16.lpcs = (CREATESTRUCT16 *)MapLS( &cs16 );
234 cbtcw16.hwndInsertAfter = HWND_16( cbtcw32->hwndInsertAfter );
236 lp = MapLS( &cbtcw16 );
237 ret = call_hook_16( WH_CBT, code, wp, lp );
238 UnMapLS( cs16.lpszName );
239 UnMapLS( cs16.lpszClass );
241 cbtcw32->hwndInsertAfter = WIN_Handle32( cbtcw16.hwndInsertAfter );
242 UnMapLS( (SEGPTR)cbtcw16.lpcs );
249 CBTACTIVATESTRUCT *cas32 = (CBTACTIVATESTRUCT *)lp;
250 CBTACTIVATESTRUCT16 cas16;
252 cas16.fMouse = cas32->fMouse;
253 cas16.hWndActive = HWND_16( cas32->hWndActive );
255 lp = MapLS( &cas16 );
256 ret = call_hook_16( WH_CBT, code, wp, lp );
260 case HCBT_CLICKSKIPPED:
262 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
263 MOUSEHOOKSTRUCT16 ms16;
265 ms16.pt.x = ms32->pt.x;
266 ms16.pt.y = ms32->pt.y;
267 ms16.hwnd = HWND_16( ms32->hwnd );
268 ms16.wHitTestCode = ms32->wHitTestCode;
269 ms16.dwExtraInfo = ms32->dwExtraInfo;
272 ret = call_hook_16( WH_CBT, code, wp, lp );
278 RECT *rect32 = (RECT *)lp;
281 CONV_RECT32TO16( rect32, &rect16 );
282 lp = MapLS( &rect16 );
283 ret = call_hook_16( WH_CBT, code, wp, lp );
292 /***********************************************************************
295 static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp )
297 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
298 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_MOUSE, code, wp, lp );
314 /***********************************************************************
317 static LRESULT CALLBACK call_WH_SHELL( INT code, WPARAM wp, LPARAM lp )
319 return call_hook_16( WH_SHELL, code, wp, lp );
323 /***********************************************************************
324 * SetWindowsHook (USER.121)
326 FARPROC16 WINAPI SetWindowsHook16( INT16 id, HOOKPROC16 proc )
328 HINSTANCE16 hInst = FarGetOwner16( HIWORD(proc) );
330 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
331 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
333 return (FARPROC16)SetWindowsHookEx16( id, proc, hInst, hTask );
337 /***********************************************************************
338 * SetWindowsHookEx (USER.291)
340 HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst, HTASK16 hTask )
342 MESSAGEQUEUE *queue = QUEUE_Current();
343 struct hook16_queue_info *info;
345 int index = id - WH_MINHOOK;
347 if (!queue) return 0;
348 if (id < WH_MINHOOK || id > WH_MAXHOOK16) return 0;
349 if (!hook_procs[index])
351 FIXME( "hook type %d broken in Win16\n", id );
354 if (!hTask) FIXME( "System-global hooks (%d) broken in Win16\n", id );
355 else if (hTask != GetCurrentTask())
357 FIXME( "setting hook (%d) on other task not supported\n", id );
361 if (!(info = queue->hook16_info))
363 if (!(info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*info) ))) return 0;
364 queue->hook16_info = info;
366 if (info->hook[index])
368 FIXME( "Multiple hooks (%d) for the same task not supported yet\n", id );
371 if (!(hook = SetWindowsHookExA( id, hook_procs[index], 0, GetCurrentThreadId() ))) return 0;
372 info->hook[index] = hook;
373 info->proc[index] = proc;
378 /***********************************************************************
379 * UnhookWindowsHook (USER.234)
381 BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
383 MESSAGEQUEUE *queue = QUEUE_Current();
384 struct hook16_queue_info *info;
385 int index = id - WH_MINHOOK;
387 if (id < WH_MINHOOK || id > WH_MAXHOOK16) return FALSE;
388 if (!queue || !(info = queue->hook16_info)) return FALSE;
389 if (info->proc[index] != proc) return FALSE;
390 if (!UnhookWindowsHookEx( info->hook[index] )) return FALSE;
391 info->hook[index] = 0;
392 info->proc[index] = 0;
397 /***********************************************************************
398 * UnhookWindowsHookEx (USER.292)
400 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
402 MESSAGEQUEUE *queue = QUEUE_Current();
403 struct hook16_queue_info *info;
406 if (!queue || !(info = queue->hook16_info)) return FALSE;
407 for (index = 0; index < NB_HOOKS16; index++)
409 if (info->hook[index] == hhook)
411 info->hook[index] = 0;
412 info->proc[index] = 0;
413 return UnhookWindowsHookEx( hhook );
420 /***********************************************************************
421 * CallMsgFilter32 (USER.823)
423 BOOL16 WINAPI CallMsgFilter32_16( MSG32_16 *lpmsg16_32, INT16 code, BOOL16 wHaveParamHigh )
428 if (GetSysModalWindow16()) return FALSE;
429 msg32.hwnd = WIN_Handle32( lpmsg16_32->msg.hwnd );
430 msg32.message = lpmsg16_32->msg.message;
431 msg32.lParam = lpmsg16_32->msg.lParam;
432 msg32.time = lpmsg16_32->msg.time;
433 msg32.pt.x = lpmsg16_32->msg.pt.x;
434 msg32.pt.y = lpmsg16_32->msg.pt.y;
435 if (wHaveParamHigh) msg32.wParam = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh);
436 else msg32.wParam = lpmsg16_32->msg.wParam;
438 ret = (BOOL16)CallMsgFilterA(&msg32, code);
440 lpmsg16_32->msg.hwnd = HWND_16( msg32.hwnd );
441 lpmsg16_32->msg.message = msg32.message;
442 lpmsg16_32->msg.wParam = LOWORD(msg32.wParam);
443 lpmsg16_32->msg.lParam = msg32.lParam;
444 lpmsg16_32->msg.time = msg32.time;
445 lpmsg16_32->msg.pt.x = msg32.pt.x;
446 lpmsg16_32->msg.pt.y = msg32.pt.y;
447 if (wHaveParamHigh) lpmsg16_32->wParamHigh = HIWORD(msg32.wParam);
452 /***********************************************************************
453 * CallMsgFilter (USER.123)
455 BOOL16 WINAPI CallMsgFilter16( MSG16 *msg, INT16 code )
457 return CallMsgFilter32_16( (MSG32_16 *)msg, code, FALSE );
461 /***********************************************************************
462 * CallNextHookEx (USER.293)
464 LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wparam, LPARAM lparam )
466 MESSAGEQUEUE *queue = QUEUE_Current();
467 struct hook16_queue_info *info;
470 if (!queue || !(info = queue->hook16_info)) return 0;
476 MSG16 *msg16 = MapSL(lparam);
479 map_msg_16_to_32( msg16, &msg32 );
480 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
486 MSG16 *msg16 = MapSL(lparam);
489 map_msg_16_to_32( msg16, &msg32 );
490 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
491 map_msg_32_to_16( &msg32, msg16 );
497 CWPSTRUCT16 *cwp16 = MapSL(lparam);
500 cwp32.hwnd = WIN_Handle32(cwp16->hwnd);
501 cwp32.lParam = cwp16->lParam;
503 WINPROC_MapMsg16To32A( cwp32.hwnd, cwp16->message, cwp16->wParam,
504 &cwp32.message, &cwp32.wParam, &cwp32.lParam );
505 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cwp32 );
506 WINPROC_UnmapMsg16To32A( cwp32.hwnd, cwp32.message, cwp32.wParam, cwp32.lParam, 0 );
515 CBT_CREATEWNDA cbtcw32;
517 CBT_CREATEWND16 *cbtcw16 = MapSL(lparam);
518 CREATESTRUCT16 *cs16 = MapSL( (SEGPTR)cbtcw16->lpcs );
520 cbtcw32.lpcs = &cs32;
521 cbtcw32.hwndInsertAfter = WIN_Handle32( cbtcw16->hwndInsertAfter );
523 cs32.lpCreateParams = cs16->lpCreateParams;
524 cs32.hInstance = MapHModuleSL(cs16->hInstance);
525 cs32.hMenu = HMENU_32(cs16->hMenu);
526 cs32.hwndParent = WIN_Handle32(cs16->hwndParent);
531 cs32.style = cs16->style;
532 cs32.lpszName = MapSL( cs16->lpszName );
533 cs32.lpszClass = MapSL( cs16->lpszClass );
534 cs32.dwExStyle = cs16->dwExStyle;
536 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cbtcw32 );
537 cbtcw16->hwndInsertAfter = HWND_16( cbtcw32.hwndInsertAfter );
542 CBTACTIVATESTRUCT16 *cas16 = MapSL(lparam);
543 CBTACTIVATESTRUCT cas32;
544 cas32.fMouse = cas16->fMouse;
545 cas32.hWndActive = WIN_Handle32(cas16->hWndActive);
546 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cas32 );
549 case HCBT_CLICKSKIPPED:
551 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
552 MOUSEHOOKSTRUCT ms32;
554 ms32.pt.x = ms16->pt.x;
555 ms32.pt.y = ms16->pt.y;
556 /* wHitTestCode may be negative, so convince compiler to do
557 correct sign extension. Yay. :| */
558 ms32.wHitTestCode = (INT)(INT16)ms16->wHitTestCode;
559 ms32.dwExtraInfo = ms16->dwExtraInfo;
560 ms32.hwnd = WIN_Handle32( ms16->hwnd );
561 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 );
566 RECT16 *rect16 = MapSL(lparam);
569 CONV_RECT16TO32( rect16, &rect32 );
570 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&rect32 );
578 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
579 MOUSEHOOKSTRUCT ms32;
581 ms32.pt.x = ms16->pt.x;
582 ms32.pt.y = ms16->pt.y;
583 /* wHitTestCode may be negative, so convince compiler to do
584 correct sign extension. Yay. :| */
585 ms32.wHitTestCode = (INT)((INT16)ms16->wHitTestCode);
586 ms32.dwExtraInfo = ms16->dwExtraInfo;
587 ms32.hwnd = WIN_Handle32(ms16->hwnd);
588 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 );
594 ret = CallNextHookEx( hhook, code, wparam, lparam );
598 case WH_FOREGROUNDIDLE:
599 case WH_CALLWNDPROCRET:
600 case WH_SYSMSGFILTER:
601 case WH_JOURNALRECORD:
602 case WH_JOURNALPLAYBACK:
604 FIXME("\t[%i] 16to32 translation unimplemented\n", info->id);
605 ret = CallNextHookEx( hhook, code, wparam, lparam );
612 /***********************************************************************
613 * DefHookProc (USER.235)
615 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wparam, LPARAM lparam, HHOOK *hhook )
617 return CallNextHookEx16( *hhook, code, wparam, lparam );