dbghelp: Keep the mapping of any PDB file open until the module is unloaded.
[wine] / dlls / user.exe16 / hook.c
1 /*
2  * Windows 16-bit hook functions
3  *
4  * Copyright 1994, 1995, 2002 Alexandre Julliard
5  * Copyright 1996 Andrew Lewycky
6  *
7  * Based on investigations by Alex Korobka
8  *
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.
13  *
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.
18  *
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
22  */
23
24 #include <stdarg.h>
25
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"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(hook);
35
36
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 );
44
45 #define WH_MAXHOOK16 WH_SHELL  /* Win16 only supports up to WH_SHELL */
46 #define NB_HOOKS16 (WH_MAXHOOK16 - WH_MINHOOK + 1)
47
48 static const HOOKPROC hook_procs[NB_HOOKS16] =
49 {
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 */
62 };
63
64
65 struct hook16_queue_info
66 {
67     INT        id;                /* id of current hook */
68     HHOOK      hook[NB_HOOKS16];  /* Win32 hook handles */
69     HOOKPROC16 proc[NB_HOOKS16];  /* 16-bit hook procedures */
70 };
71
72 static struct hook16_queue_info *get_hook_info( BOOL create )
73 {
74     static DWORD hook_tls = TLS_OUT_OF_INDEXES;
75     struct hook16_queue_info *info = TlsGetValue( hook_tls );
76
77     if (!info && create)
78     {
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 );
82     }
83     return info;
84 }
85
86
87 /***********************************************************************
88  *           map_msg_16_to_32
89  */
90 static inline void map_msg_16_to_32( const MSG16 *msg16, MSG *msg32 )
91 {
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;
99 }
100
101
102 /***********************************************************************
103  *           map_msg_32_to_16
104  */
105 static inline void map_msg_32_to_16( const MSG *msg32, MSG16 *msg16 )
106 {
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;
114 }
115
116
117 /***********************************************************************
118  *           call_hook_16
119  */
120 static LRESULT call_hook_16( INT id, INT code, WPARAM wp, LPARAM lp )
121 {
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;
127
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 );
133
134     info->id = prev_id;
135
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;
143 }
144
145
146 struct wndproc_hook_params
147 {
148     HHOOK  hhook;
149     INT    code;
150     WPARAM wparam;
151 };
152
153 /* callback for WINPROC_Call16To32A */
154 static LRESULT wndproc_hook_callback( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
155                                       LRESULT *result, void *arg )
156 {
157     struct wndproc_hook_params *params = arg;
158     CWPSTRUCT cwp;
159
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 );
166 }
167
168 /* callback for WINPROC_Call32ATo16 */
169 static LRESULT wndproc_hook_callback16( HWND16 hwnd, UINT16 msg, WPARAM16 wp, LPARAM lp,
170                                         LRESULT *result, void *arg )
171 {
172     struct wndproc_hook_params *params = arg;
173     CWPSTRUCT16 cwp;
174     LRESULT ret;
175
176     cwp.hwnd    = hwnd;
177     cwp.message = msg;
178     cwp.wParam  = wp;
179     cwp.lParam  = lp;
180
181     lp = MapLS( &cwp );
182     ret = call_hook_16( WH_CALLWNDPROC, params->code, params->wparam, lp );
183     UnMapLS( lp );
184
185     *result = 0;
186     return ret;
187 }
188
189
190 /***********************************************************************
191  *              call_WH_MSGFILTER
192  */
193 static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp )
194 {
195     MSG *msg32 = (MSG *)lp;
196     MSG16 msg16;
197     LRESULT ret;
198
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;
204 }
205
206
207 /***********************************************************************
208  *              call_WH_KEYBOARD
209  */
210 static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp )
211 {
212     return call_hook_16( WH_KEYBOARD, code, wp, lp );
213 }
214
215
216 /***********************************************************************
217  *              call_WH_GETMESSAGE
218  */
219 static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp )
220 {
221     MSG *msg32 = (MSG *)lp;
222     MSG16 msg16;
223     LRESULT ret;
224
225     map_msg_32_to_16( msg32, &msg16 );
226
227     lp = MapLS( &msg16 );
228     ret = call_hook_16( WH_GETMESSAGE, code, wp, lp );
229     UnMapLS( lp );
230
231     map_msg_16_to_32( &msg16, msg32 );
232     return ret;
233 }
234
235
236 /***********************************************************************
237  *              call_WH_CALLWNDPROC
238  */
239 static LRESULT CALLBACK call_WH_CALLWNDPROC( INT code, WPARAM wp, LPARAM lp )
240 {
241     struct wndproc_hook_params params;
242     CWPSTRUCT *cwp32 = (CWPSTRUCT *)lp;
243     LRESULT result;
244
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 );
249 }
250
251
252 /***********************************************************************
253  *              call_WH_CBT
254  */
255 static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp )
256 {
257     LRESULT ret = 0;
258
259     switch (code)
260     {
261     case HCBT_CREATEWND:
262         {
263             CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lp;
264             CBT_CREATEWND16 cbtcw16;
265             CREATESTRUCT16 cs16;
266
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;
279
280             cbtcw16.lpcs = (CREATESTRUCT16 *)MapLS( &cs16 );
281             cbtcw16.hwndInsertAfter = HWND_16( cbtcw32->hwndInsertAfter );
282
283             lp = MapLS( &cbtcw16 );
284             ret = call_hook_16( WH_CBT, code, wp, lp );
285             UnMapLS( cs16.lpszName );
286             UnMapLS( cs16.lpszClass );
287
288             cbtcw32->hwndInsertAfter = WIN_Handle32( cbtcw16.hwndInsertAfter );
289             UnMapLS( (SEGPTR)cbtcw16.lpcs );
290             UnMapLS( lp );
291             break;
292         }
293
294     case HCBT_ACTIVATE:
295         {
296             CBTACTIVATESTRUCT *cas32 = (CBTACTIVATESTRUCT *)lp;
297             CBTACTIVATESTRUCT16 cas16;
298
299             cas16.fMouse     = cas32->fMouse;
300             cas16.hWndActive = HWND_16( cas32->hWndActive );
301
302             lp = MapLS( &cas16 );
303             ret = call_hook_16( WH_CBT, code, wp, lp );
304             UnMapLS( lp );
305             break;
306         }
307     case HCBT_CLICKSKIPPED:
308         {
309             MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
310             MOUSEHOOKSTRUCT16 ms16;
311
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;
317
318             lp = MapLS( &ms16 );
319             ret = call_hook_16( WH_CBT, code, wp, lp );
320             UnMapLS( lp );
321             break;
322         }
323     case HCBT_MOVESIZE:
324         {
325             RECT *rect32 = (RECT *)lp;
326             RECT16 rect16;
327
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;
336         }
337     }
338     return ret;
339 }
340
341
342 /***********************************************************************
343  *              call_WH_MOUSE
344  */
345 static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp )
346 {
347     MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
348     MOUSEHOOKSTRUCT16 ms16;
349     LRESULT ret;
350
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;
356
357     lp = MapLS( &ms16 );
358     ret = call_hook_16( WH_MOUSE, code, wp, lp );
359     UnMapLS( lp );
360     return ret;
361 }
362
363
364 /***********************************************************************
365  *              call_WH_SHELL
366  */
367 static LRESULT CALLBACK call_WH_SHELL( INT code, WPARAM wp, LPARAM lp )
368 {
369     return call_hook_16( WH_SHELL, code, wp, lp );
370 }
371
372
373 /***********************************************************************
374  *              SetWindowsHook (USER.121)
375  */
376 FARPROC16 WINAPI SetWindowsHook16( INT16 id, HOOKPROC16 proc )
377 {
378     HINSTANCE16 hInst = FarGetOwner16( HIWORD(proc) );
379
380     /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
381     HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
382
383     return (FARPROC16)SetWindowsHookEx16( id, proc, hInst, hTask );
384 }
385
386
387 /***********************************************************************
388  *              SetWindowsHookEx (USER.291)
389  */
390 HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst, HTASK16 hTask )
391 {
392     struct hook16_queue_info *info;
393     HHOOK hook;
394     int index = id - WH_MINHOOK;
395
396     if (id < WH_MINHOOK || id > WH_MAXHOOK16) return 0;
397     if (!hook_procs[index])
398     {
399         FIXME( "hook type %d broken in Win16\n", id );
400         return 0;
401     }
402     if (!hTask) FIXME( "System-global hooks (%d) broken in Win16\n", id );
403     else if (hTask != GetCurrentTask())
404     {
405         FIXME( "setting hook (%d) on other task not supported\n", id );
406         return 0;
407     }
408
409     if (!(info = get_hook_info( TRUE ))) return 0;
410     if (info->hook[index])
411     {
412         FIXME( "Multiple hooks (%d) for the same task not supported yet\n", id );
413         return 0;
414     }
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;
419 }
420
421
422 /***********************************************************************
423  *              UnhookWindowsHook (USER.234)
424  */
425 BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
426 {
427     struct hook16_queue_info *info;
428     int index = id - WH_MINHOOK;
429
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;
437 }
438
439
440 /***********************************************************************
441  *              UnhookWindowsHookEx (USER.292)
442  */
443 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
444 {
445     struct hook16_queue_info *info;
446     int index;
447
448     if (!(info = get_hook_info( FALSE ))) return FALSE;
449     for (index = 0; index < NB_HOOKS16; index++)
450     {
451         if (info->hook[index] == hhook)
452         {
453             info->hook[index] = 0;
454             info->proc[index] = 0;
455             return UnhookWindowsHookEx( hhook );
456         }
457     }
458     return FALSE;
459 }
460
461
462 /***********************************************************************
463  *              CallMsgFilter32 (USER.823)
464  */
465 BOOL16 WINAPI CallMsgFilter32_16( MSG32_16 *lpmsg16_32, INT16 code, BOOL16 wHaveParamHigh )
466 {
467     MSG msg32;
468     BOOL16 ret;
469
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;
479
480     ret = (BOOL16)CallMsgFilterA(&msg32, code);
481
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;
491 }
492
493
494 /***********************************************************************
495  *              CallMsgFilter (USER.123)
496  */
497 BOOL16 WINAPI CallMsgFilter16( MSG16 *msg, INT16 code )
498 {
499     return CallMsgFilter32_16( (MSG32_16 *)msg, code, FALSE );
500 }
501
502
503 /***********************************************************************
504  *              CallNextHookEx (USER.293)
505  */
506 LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wparam, LPARAM lparam )
507 {
508     struct hook16_queue_info *info;
509     LRESULT ret = 0;
510
511     if (!(info = get_hook_info( FALSE ))) return 0;
512
513     switch (info->id)
514     {
515     case WH_MSGFILTER:
516     {
517         MSG16 *msg16 = MapSL(lparam);
518         MSG msg32;
519
520         map_msg_16_to_32( msg16, &msg32 );
521         ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
522         break;
523     }
524
525     case WH_GETMESSAGE:
526     {
527         MSG16 *msg16 = MapSL(lparam);
528         MSG msg32;
529
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;
534     }
535
536     case WH_CALLWNDPROC:
537     {
538         CWPSTRUCT16 *cwp16 = MapSL(lparam);
539         LRESULT result;
540         struct wndproc_hook_params params;
541
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;
548     }
549
550     case WH_CBT:
551         switch (code)
552         {
553         case HCBT_CREATEWND:
554             {
555                 CBT_CREATEWNDA cbtcw32;
556                 CREATESTRUCTA cs32;
557                 CBT_CREATEWND16 *cbtcw16 = MapSL(lparam);
558                 CREATESTRUCT16 *cs16 = MapSL( (SEGPTR)cbtcw16->lpcs );
559
560                 cbtcw32.lpcs = &cs32;
561                 cbtcw32.hwndInsertAfter = WIN_Handle32( cbtcw16->hwndInsertAfter );
562
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;
575
576                 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cbtcw32 );
577                 cbtcw16->hwndInsertAfter = HWND_16( cbtcw32.hwndInsertAfter );
578                 break;
579             }
580         case HCBT_ACTIVATE:
581             {
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;
588             }
589         case HCBT_CLICKSKIPPED:
590             {
591                 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
592                 MOUSEHOOKSTRUCT ms32;
593
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;
603             }
604         case HCBT_MOVESIZE:
605             {
606                 RECT16 *rect16 = MapSL(lparam);
607                 RECT rect32;
608
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;
615             }
616         }
617         break;
618
619     case WH_MOUSE:
620     {
621         MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
622         MOUSEHOOKSTRUCT ms32;
623
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;
633     }
634
635     case WH_SHELL:
636     case WH_KEYBOARD:
637         ret = CallNextHookEx( hhook, code, wparam, lparam );
638         break;
639
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;
650     }
651     return ret;
652 }
653
654
655 /***********************************************************************
656  *              DefHookProc (USER.235)
657  */
658 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wparam, LPARAM lparam, HHOOK *hhook )
659 {
660     return CallNextHookEx16( *hhook, code, wparam, lparam );
661 }