riched20: Trace the result of a failing test.
[wine/multimedia.git] / dlls / user32 / hook16.c
blob436a16802ec5b34b54cf062b3a0ce64977249275
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 "win.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 */
61 NULL, /* WH_DEBUG */
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 /***********************************************************************
77 * map_msg_16_to_32
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 /***********************************************************************
92 * map_msg_32_to_16
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 /***********************************************************************
107 * call_hook_16
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;
112 WORD args[4];
113 DWORD ret;
114 INT prev_id = info->id;
115 info->id = id;
117 args[3] = code;
118 args[2] = wp;
119 args[1] = HIWORD(lp);
120 args[0] = LOWORD(lp);
121 WOWCallback16Ex( (DWORD)info->proc[id - WH_MINHOOK], WCB16_PASCAL, sizeof(args), args, &ret );
123 info->id = prev_id;
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 );
131 return ret;
135 struct wndproc_hook_params
137 HHOOK hhook;
138 INT code;
139 WPARAM wparam;
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;
147 CWPSTRUCT cwp;
149 cwp.hwnd = hwnd;
150 cwp.message = msg;
151 cwp.wParam = wp;
152 cwp.lParam = lp;
153 *result = 0;
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;
162 CWPSTRUCT16 cwp;
163 LRESULT ret;
165 cwp.hwnd = hwnd;
166 cwp.message = msg;
167 cwp.wParam = wp;
168 cwp.lParam = lp;
170 lp = MapLS( &cwp );
171 ret = call_hook_16( WH_CALLWNDPROC, params->code, params->wparam, lp );
172 UnMapLS( lp );
174 *result = 0;
175 return ret;
179 /***********************************************************************
180 * call_WH_MSGFILTER
182 static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp )
184 MSG *msg32 = (MSG *)lp;
185 MSG16 msg16;
186 LRESULT ret;
188 map_msg_32_to_16( msg32, &msg16 );
189 lp = MapLS( &msg16 );
190 ret = call_hook_16( WH_MSGFILTER, code, wp, lp );
191 UnMapLS( lp );
192 return ret;
196 /***********************************************************************
197 * call_WH_KEYBOARD
199 static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp )
201 return call_hook_16( WH_KEYBOARD, code, wp, lp );
205 /***********************************************************************
206 * call_WH_GETMESSAGE
208 static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp )
210 MSG *msg32 = (MSG *)lp;
211 MSG16 msg16;
212 LRESULT ret;
214 map_msg_32_to_16( msg32, &msg16 );
216 lp = MapLS( &msg16 );
217 ret = call_hook_16( WH_GETMESSAGE, code, wp, lp );
218 UnMapLS( lp );
220 map_msg_16_to_32( &msg16, msg32 );
221 return ret;
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;
232 LRESULT result;
234 params.code = code;
235 params.wparam = wp;
236 return WINPROC_CallProc32ATo16( wndproc_hook_callback16, cwp32->hwnd, cwp32->message,
237 cwp32->wParam, cwp32->lParam, &result, &params );
241 /***********************************************************************
242 * call_WH_CBT
244 static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp )
246 LRESULT ret = 0;
248 switch (code)
250 case HCBT_CREATEWND:
252 CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lp;
253 CBT_CREATEWND16 cbtcw16;
254 CREATESTRUCT16 cs16;
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 );
279 UnMapLS( lp );
280 break;
283 case HCBT_ACTIVATE:
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 );
293 UnMapLS( lp );
294 break;
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;
307 lp = MapLS( &ms16 );
308 ret = call_hook_16( WH_CBT, code, wp, lp );
309 UnMapLS( lp );
310 break;
312 case HCBT_MOVESIZE:
314 RECT *rect32 = (RECT *)lp;
315 RECT16 rect16;
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 );
323 UnMapLS( lp );
324 break;
327 return ret;
331 /***********************************************************************
332 * call_WH_MOUSE
334 static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp )
336 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
337 MOUSEHOOKSTRUCT16 ms16;
338 LRESULT ret;
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;
346 lp = MapLS( &ms16 );
347 ret = call_hook_16( WH_MOUSE, code, wp, lp );
348 UnMapLS( lp );
349 return ret;
353 /***********************************************************************
354 * call_WH_SHELL
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;
383 HHOOK hook;
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 );
390 return 0;
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 );
396 return 0;
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 );
407 return 0;
409 if (!(hook = SetWindowsHookExA( id, hook_procs[index], 0, GetCurrentThreadId() ))) return 0;
410 info->hook[index] = hook;
411 info->proc[index] = proc;
412 return hook;
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;
430 return TRUE;
434 /***********************************************************************
435 * UnhookWindowsHookEx (USER.292)
437 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
439 struct hook16_queue_info *info;
440 int index;
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 );
452 return FALSE;
456 /***********************************************************************
457 * CallMsgFilter32 (USER.823)
459 BOOL16 WINAPI CallMsgFilter32_16( MSG32_16 *lpmsg16_32, INT16 code, BOOL16 wHaveParamHigh )
461 MSG msg32;
462 BOOL16 ret;
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);
484 return ret;
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;
503 LRESULT ret = 0;
505 if (!(info = get_user_thread_info()->hook16_info)) return 0;
507 switch (info->id)
509 case WH_MSGFILTER:
511 MSG16 *msg16 = MapSL(lparam);
512 MSG msg32;
514 map_msg_16_to_32( msg16, &msg32 );
515 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
516 break;
519 case WH_GETMESSAGE:
521 MSG16 *msg16 = MapSL(lparam);
522 MSG msg32;
524 map_msg_16_to_32( msg16, &msg32 );
525 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
526 map_msg_32_to_16( &msg32, msg16 );
527 break;
530 case WH_CALLWNDPROC:
532 CWPSTRUCT16 *cwp16 = MapSL(lparam);
533 LRESULT result;
534 struct wndproc_hook_params params;
536 params.hhook = hhook;
537 params.code = code;
538 params.wparam = wparam;
539 ret = WINPROC_CallProc16To32A( wndproc_hook_callback, cwp16->hwnd, cwp16->message,
540 cwp16->wParam, cwp16->lParam, &result, &params );
541 break;
544 case WH_CBT:
545 switch (code)
547 case HCBT_CREATEWND:
549 CBT_CREATEWNDA cbtcw32;
550 CREATESTRUCTA cs32;
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);
561 cs32.cy = cs16->cy;
562 cs32.cx = cs16->cx;
563 cs32.y = cs16->y;
564 cs32.x = cs16->x;
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 );
572 break;
574 case HCBT_ACTIVATE:
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 );
581 break;
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 );
596 break;
598 case HCBT_MOVESIZE:
600 RECT16 *rect16 = MapSL(lparam);
601 RECT rect32;
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 );
608 break;
611 break;
613 case WH_MOUSE:
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 );
626 break;
629 case WH_SHELL:
630 case WH_KEYBOARD:
631 ret = CallNextHookEx( hhook, code, wparam, lparam );
632 break;
634 case WH_HARDWARE:
635 case WH_FOREGROUNDIDLE:
636 case WH_CALLWNDPROCRET:
637 case WH_SYSMSGFILTER:
638 case WH_JOURNALRECORD:
639 case WH_JOURNALPLAYBACK:
640 default:
641 FIXME("\t[%i] 16to32 translation unimplemented\n", info->id);
642 ret = CallNextHookEx( hhook, code, wparam, lparam );
643 break;
645 return ret;
649 /***********************************************************************
650 * DefHookProc (USER.235)
652 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wparam, LPARAM lparam, HHOOK *hhook )
654 return CallNextHookEx16( *hhook, code, wparam, lparam );