Release 1.3.7.
[wine/gsoc-2012-control.git] / dlls / user.exe16 / hook.c
blob640899eca50d7af722adc0b060ff9ed90146aea5
1 /*
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
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "wownt32.h"
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 */
60 NULL, /* WH_DEBUG */
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 );
77 if (!info && create)
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 );
83 return info;
87 /***********************************************************************
88 * map_msg_16_to_32
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 /***********************************************************************
103 * map_msg_32_to_16
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 /***********************************************************************
118 * call_hook_16
120 static LRESULT call_hook_16( INT id, INT code, WPARAM wp, LPARAM lp )
122 struct hook16_queue_info *info = get_hook_info( FALSE );
123 WORD args[4];
124 DWORD ret;
125 INT prev_id = info->id;
126 info->id = id;
128 args[3] = code;
129 args[2] = wp;
130 args[1] = HIWORD(lp);
131 args[0] = LOWORD(lp);
132 WOWCallback16Ex( (DWORD)info->proc[id - WH_MINHOOK], WCB16_PASCAL, sizeof(args), args, &ret );
134 info->id = prev_id;
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 );
142 return ret;
146 struct wndproc_hook_params
148 HHOOK hhook;
149 INT code;
150 WPARAM wparam;
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;
158 CWPSTRUCT cwp;
160 cwp.hwnd = hwnd;
161 cwp.message = msg;
162 cwp.wParam = wp;
163 cwp.lParam = lp;
164 *result = 0;
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;
173 CWPSTRUCT16 cwp;
174 LRESULT ret;
176 cwp.hwnd = hwnd;
177 cwp.message = msg;
178 cwp.wParam = wp;
179 cwp.lParam = lp;
181 lp = MapLS( &cwp );
182 ret = call_hook_16( WH_CALLWNDPROC, params->code, params->wparam, lp );
183 UnMapLS( lp );
185 *result = 0;
186 return ret;
190 /***********************************************************************
191 * call_WH_MSGFILTER
193 static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp )
195 MSG *msg32 = (MSG *)lp;
196 MSG16 msg16;
197 LRESULT ret;
199 map_msg_32_to_16( msg32, &msg16 );
200 lp = MapLS( &msg16 );
201 ret = call_hook_16( WH_MSGFILTER, code, wp, lp );
202 UnMapLS( lp );
203 return ret;
207 /***********************************************************************
208 * call_WH_KEYBOARD
210 static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp )
212 return call_hook_16( WH_KEYBOARD, code, wp, lp );
216 /***********************************************************************
217 * call_WH_GETMESSAGE
219 static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp )
221 MSG *msg32 = (MSG *)lp;
222 MSG16 msg16;
223 LRESULT ret;
225 map_msg_32_to_16( msg32, &msg16 );
227 lp = MapLS( &msg16 );
228 ret = call_hook_16( WH_GETMESSAGE, code, wp, lp );
229 UnMapLS( lp );
231 map_msg_16_to_32( &msg16, msg32 );
232 return ret;
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;
243 LRESULT result;
245 params.code = code;
246 params.wparam = wp;
247 return WINPROC_CallProc32ATo16( wndproc_hook_callback16, cwp32->hwnd, cwp32->message,
248 cwp32->wParam, cwp32->lParam, &result, &params );
252 /***********************************************************************
253 * call_WH_CBT
255 static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp )
257 LRESULT ret = 0;
259 switch (code)
261 case HCBT_CREATEWND:
263 CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lp;
264 CBT_CREATEWND16 cbtcw16;
265 CREATESTRUCT16 cs16;
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 );
290 UnMapLS( lp );
291 break;
294 case HCBT_ACTIVATE:
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 );
304 UnMapLS( lp );
305 break;
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;
318 lp = MapLS( &ms16 );
319 ret = call_hook_16( WH_CBT, code, wp, lp );
320 UnMapLS( lp );
321 break;
323 case HCBT_MOVESIZE:
325 RECT *rect32 = (RECT *)lp;
326 RECT16 rect16;
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 );
334 UnMapLS( lp );
335 break;
338 return ret;
342 /***********************************************************************
343 * call_WH_MOUSE
345 static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp )
347 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
348 MOUSEHOOKSTRUCT16 ms16;
349 LRESULT ret;
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;
357 lp = MapLS( &ms16 );
358 ret = call_hook_16( WH_MOUSE, code, wp, lp );
359 UnMapLS( lp );
360 return ret;
364 /***********************************************************************
365 * call_WH_SHELL
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;
393 HHOOK hook;
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 );
400 return 0;
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 );
406 return 0;
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 );
413 return 0;
415 if (!(hook = SetWindowsHookExA( id, hook_procs[index], 0, GetCurrentThreadId() ))) return 0;
416 info->hook[index] = hook;
417 info->proc[index] = proc;
418 return hook;
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;
436 return TRUE;
440 /***********************************************************************
441 * UnhookWindowsHookEx (USER.292)
443 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
445 struct hook16_queue_info *info;
446 int index;
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 );
458 return FALSE;
462 /***********************************************************************
463 * CallMsgFilter32 (USER.823)
465 BOOL16 WINAPI CallMsgFilter32_16( MSG32_16 *lpmsg16_32, INT16 code, BOOL16 wHaveParamHigh )
467 MSG msg32;
468 BOOL16 ret;
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);
490 return ret;
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;
509 LRESULT ret = 0;
511 if (!(info = get_hook_info( FALSE ))) return 0;
513 switch (info->id)
515 case WH_MSGFILTER:
517 MSG16 *msg16 = MapSL(lparam);
518 MSG msg32;
520 map_msg_16_to_32( msg16, &msg32 );
521 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
522 break;
525 case WH_GETMESSAGE:
527 MSG16 *msg16 = MapSL(lparam);
528 MSG msg32;
530 map_msg_16_to_32( msg16, &msg32 );
531 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
532 map_msg_32_to_16( &msg32, msg16 );
533 break;
536 case WH_CALLWNDPROC:
538 CWPSTRUCT16 *cwp16 = MapSL(lparam);
539 LRESULT result;
540 struct wndproc_hook_params params;
542 params.hhook = hhook;
543 params.code = code;
544 params.wparam = wparam;
545 ret = WINPROC_CallProc16To32A( wndproc_hook_callback, cwp16->hwnd, cwp16->message,
546 cwp16->wParam, cwp16->lParam, &result, &params );
547 break;
550 case WH_CBT:
551 switch (code)
553 case HCBT_CREATEWND:
555 CBT_CREATEWNDA cbtcw32;
556 CREATESTRUCTA cs32;
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);
567 cs32.cy = cs16->cy;
568 cs32.cx = cs16->cx;
569 cs32.y = cs16->y;
570 cs32.x = cs16->x;
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 );
578 break;
580 case HCBT_ACTIVATE:
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 );
587 break;
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 );
602 break;
604 case HCBT_MOVESIZE:
606 RECT16 *rect16 = MapSL(lparam);
607 RECT rect32;
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 );
614 break;
617 break;
619 case WH_MOUSE:
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 );
632 break;
635 case WH_SHELL:
636 case WH_KEYBOARD:
637 ret = CallNextHookEx( hhook, code, wparam, lparam );
638 break;
640 case WH_HARDWARE:
641 case WH_FOREGROUNDIDLE:
642 case WH_CALLWNDPROCRET:
643 case WH_SYSMSGFILTER:
644 case WH_JOURNALRECORD:
645 case WH_JOURNALPLAYBACK:
646 default:
647 FIXME("\t[%i] 16to32 translation unimplemented\n", info->id);
648 ret = CallNextHookEx( hhook, code, wparam, lparam );
649 break;
651 return ret;
655 /***********************************************************************
656 * DefHookProc (USER.235)
658 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wparam, LPARAM lparam, HHOOK *hhook )
660 return CallNextHookEx16( *hhook, code, wparam, lparam );