- Rename WIN_Handle16 to HWDN_16 and make it a macro.
[wine] / windows / hook.c
1 /*
2  * Windows hook functions
3  *
4  * Copyright 1994, 1995 Alexandre Julliard
5  *                 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 /*
25  * Warning!
26  * A HHOOK is a 32-bit handle for compatibility with Windows 3.0 where it was
27  * a pointer to the next function. Now it is in fact composed of a USER heap
28  * handle in the low 16 bits and of a HOOK_MAGIC value in the high 16 bits.
29  */
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "wine/winuser16.h"
36 #include "wine/winbase16.h"
37 #include "hook.h"
38 #include "win.h"
39 #include "queue.h"
40 #include "user.h"
41 #include "heap.h"
42 #include "struct32.h"
43 #include "winproc.h"
44 #include "wine/debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(hook);
47
48 #include "pshpack1.h"
49
50   /* Hook data (pointed to by a HHOOK) */
51 typedef struct
52 {
53     HANDLE16   next;               /* 00 Next hook in chain */
54     HOOKPROC   proc;               /* 02 Hook procedure (original) */
55     INT16      id;                 /* 06 Hook id (WH_xxx) */
56     HQUEUE16   ownerQueue;         /* 08 Owner queue (0 for system hook) */
57     HMODULE16  ownerModule;        /* 0a Owner module */
58     WORD       flags;              /* 0c flags */
59 } HOOKDATA;
60
61 #include "poppack.h"
62
63 #define HOOK_MAGIC  ((int)'H' | (int)'K' << 8)  /* 'HK' */
64 #define HHOOK_32(h) ((HHOOK)(h ? MAKELONG(h, HOOK_MAGIC) : 0))
65 #define HHOOK_16(h) ((HANDLE16)((HIWORD(h) == HOOK_MAGIC) ? LOWORD(h) : 0))
66
67   /* This should probably reside in USER heap */
68 static HANDLE16 HOOK_systemHooks[WH_NB_HOOKS] = { 0, };
69
70 /* ### start build ### */
71 extern LONG CALLBACK HOOK_CallTo16_long_wwl(HOOKPROC16,WORD,WORD,LONG);
72 /* ### stop build ### */
73
74
75 /***********************************************************************
76  *           call_hook_16
77  */
78 inline static LRESULT call_hook_16( HOOKPROC16 proc, INT id, INT code, WPARAM wparam, LPARAM lparam )
79 {
80     LRESULT ret = HOOK_CallTo16_long_wwl( proc, code, wparam, lparam );
81     /* Grrr. While the hook procedure is supposed to have an LRESULT return
82        value even in Win16, it seems that for those hook types where the
83        return value is interpreted as BOOL, Windows doesn't actually check
84        the HIWORD ...  Some buggy Win16 programs, notably WINFILE, rely on
85        that, because they neglect to clear DX ... */
86     if (id != WH_JOURNALPLAYBACK) ret = LOWORD( ret );
87     return ret;
88 }
89
90
91 /***********************************************************************
92  *           call_hook_16_to_32
93  *
94  * Convert hook params to 32-bit and call 32-bit hook procedure
95  */
96 static LRESULT call_hook_16_to_32( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam,
97                                    BOOL unicode )
98 {
99     LRESULT ret = 0;
100
101     switch( id )
102     {
103     case WH_MSGFILTER:
104     case WH_SYSMSGFILTER:
105     case WH_JOURNALRECORD:
106     {
107         MSG16 *msg16 = MapSL(lparam);
108         MSG msg32;
109
110         STRUCT32_MSG16to32( msg16, &msg32 );
111         ret = proc( code, wparam, (LPARAM)&msg32 );
112         break;
113     }
114
115     case WH_GETMESSAGE:
116     {
117         MSG16 *msg16 = MapSL(lparam);
118         MSG msg32;
119
120         STRUCT32_MSG16to32( msg16, &msg32 );
121         ret = proc( code, wparam, (LPARAM)&msg32 );
122         STRUCT32_MSG32to16( &msg32, msg16 );
123         break;
124     }
125
126     case WH_JOURNALPLAYBACK:
127     {
128         EVENTMSG16 *em16 = MapSL(lparam);
129         EVENTMSG em32;
130
131         em32.message = em16->message;
132         em32.paramL  = em16->paramL;
133         em32.paramH  = em16->paramH;
134         em32.time    = em16->time;
135         em32.hwnd    = 0;  /* FIXME */
136         ret = proc( code, wparam, (LPARAM)&em32 );
137         break;
138     }
139
140     case WH_CALLWNDPROC:
141     {
142         CWPSTRUCT16 *cwp16 = MapSL(lparam);
143         CWPSTRUCT cwp32;
144
145         cwp32.hwnd   = WIN_Handle32(cwp16->hwnd);
146         cwp32.lParam = cwp16->lParam;
147
148         if (unicode)
149             WINPROC_MapMsg16To32W( cwp32.hwnd, cwp16->message, cwp16->wParam,
150                                    &cwp32.message, &cwp32.wParam, &cwp32.lParam );
151         else
152             WINPROC_MapMsg16To32A( cwp32.hwnd, cwp16->message, cwp16->wParam,
153                                    &cwp32.message, &cwp32.wParam, &cwp32.lParam );
154
155         ret = proc( code, wparam, (LPARAM)&cwp32 );
156
157         if (unicode)
158             WINPROC_UnmapMsg16To32W( cwp32.hwnd, cwp32.message, cwp32.wParam, cwp32.lParam, 0 );
159         else
160             WINPROC_UnmapMsg16To32A( cwp32.hwnd, cwp32.message, cwp32.wParam, cwp32.lParam, 0 );
161         break;
162     }
163
164     case WH_CBT:
165         switch (code)
166         {
167         case HCBT_CREATEWND:
168             {
169                 CBT_CREATEWNDA cbtcw32;
170                 CREATESTRUCTA cs32;
171                 CBT_CREATEWND16 *cbtcw16 = MapSL(lparam);
172                 CREATESTRUCT16 *cs16 = MapSL( (SEGPTR)cbtcw16->lpcs );
173
174                 cbtcw32.lpcs = &cs32;
175                 cbtcw32.hwndInsertAfter = WIN_Handle32( cbtcw16->hwndInsertAfter );
176                 STRUCT32_CREATESTRUCT16to32A( cs16, &cs32 );
177
178                 if (unicode)
179                 {
180                     cs32.lpszName = (LPSTR)map_str_16_to_32W( cs16->lpszName );
181                     cs32.lpszClass = (LPSTR)map_str_16_to_32W( cs16->lpszClass );
182                     ret = proc( code, wparam, (LPARAM)&cbtcw32 );
183                     unmap_str_16_to_32W( (LPWSTR)cs32.lpszName );
184                     unmap_str_16_to_32W( (LPWSTR)cs32.lpszClass );
185                 }
186                 else
187                 {
188                     cs32.lpszName = MapSL( cs16->lpszName );
189                     cs32.lpszClass = MapSL( cs16->lpszClass );
190                     ret = proc( code, wparam, (LPARAM)&cbtcw32 );
191                 }
192                 cbtcw16->hwndInsertAfter = HWND_16( cbtcw32.hwndInsertAfter );
193                 break;
194             }
195         case HCBT_ACTIVATE:
196             {
197                 CBTACTIVATESTRUCT16 *cas16 = MapSL(lparam);
198                 CBTACTIVATESTRUCT cas32;
199                 cas32.fMouse = cas16->fMouse;
200                 cas32.hWndActive = WIN_Handle32(cas16->hWndActive);
201                 ret = proc( code, wparam, (LPARAM)&cas32 );
202                 break;
203             }
204         case HCBT_CLICKSKIPPED:
205             {
206                 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
207                 MOUSEHOOKSTRUCT ms32;
208
209                 ms32.pt.x = ms16->pt.x;
210                 ms32.pt.y = ms16->pt.y;
211                 /* wHitTestCode may be negative, so convince compiler to do
212                    correct sign extension. Yay. :| */
213                 ms32.wHitTestCode = (INT)(INT16)ms16->wHitTestCode;
214                 ms32.dwExtraInfo = ms16->dwExtraInfo;
215                 ms32.hwnd = WIN_Handle32( ms16->hwnd );
216                 ret = proc( code, wparam, (LPARAM)&ms32 );
217                 break;
218             }
219         case HCBT_MOVESIZE:
220             {
221                 RECT16 *rect16 = MapSL(lparam);
222                 RECT rect32;
223
224                 CONV_RECT16TO32( rect16, &rect32 );
225                 ret = proc( code, wparam, (LPARAM)&rect32 );
226                 break;
227             }
228         }
229         break;
230
231     case WH_MOUSE:
232     {
233         MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
234         MOUSEHOOKSTRUCT ms32;
235
236         ms32.pt.x = ms16->pt.x;
237         ms32.pt.y = ms16->pt.y;
238         /* wHitTestCode may be negative, so convince compiler to do
239            correct sign extension. Yay. :| */
240         ms32.wHitTestCode = (INT)((INT16)ms16->wHitTestCode);
241         ms32.dwExtraInfo = ms16->dwExtraInfo;
242         ms32.hwnd = WIN_Handle32(ms16->hwnd);
243         ret = proc( code, wparam, (LPARAM)&ms32 );
244         break;
245     }
246
247     case WH_DEBUG:
248     {
249         DEBUGHOOKINFO16 *dh16 = MapSL(lparam);
250         DEBUGHOOKINFO dh32;
251
252         dh32.idThread = 0;            /* FIXME */
253         dh32.idThreadInstaller = 0;   /* FIXME */
254         dh32.lParam = dh16->lParam;   /* FIXME Check for sign ext */
255         dh32.wParam = dh16->wParam;
256         dh32.code   = dh16->code;
257
258         /* do sign extension if it was WH_MSGFILTER */
259         if (wparam == 0xffff) wparam = WH_MSGFILTER;
260         ret = proc( code, wparam, (LPARAM)&dh32 );
261         break;
262     }
263
264     case WH_SHELL:
265     case WH_KEYBOARD:
266         ret = proc( code, wparam, lparam );
267         break;
268
269     case WH_HARDWARE:
270     case WH_FOREGROUNDIDLE:
271     case WH_CALLWNDPROCRET:
272     default:
273         FIXME("\t[%i] 16to32 translation unimplemented\n", id);
274         ret = proc( code, wparam, lparam );
275         break;
276     }
277     return ret;
278 }
279
280
281 /***********************************************************************
282  *           call_hook_32_to_16
283  *
284  * Convert hook params to 16-bit and call 16-bit hook procedure
285  */
286 static LRESULT call_hook_32_to_16( HOOKPROC16 proc, INT id, INT code, WPARAM wparam, LPARAM lparam,
287                                    BOOL unicode )
288 {
289     LRESULT ret = 0;
290
291     switch (id)
292     {
293     case WH_MSGFILTER:
294     case WH_SYSMSGFILTER:
295     case WH_JOURNALRECORD:
296     {
297         MSG *msg32 = (MSG *)lparam;
298         MSG16 msg16;
299
300         STRUCT32_MSG32to16( msg32, &msg16 );
301         lparam = MapLS( &msg16 );
302         ret = call_hook_16( proc, id, code, wparam, lparam );
303         UnMapLS( lparam );
304         break;
305     }
306
307     case WH_GETMESSAGE:
308     {
309         MSG *msg32 = (MSG *)lparam;
310         MSG16 msg16;
311
312         STRUCT32_MSG32to16( msg32, &msg16 );
313         lparam = MapLS( &msg16 );
314         ret = call_hook_16( proc, id, code, wparam, lparam );
315         UnMapLS( lparam );
316         STRUCT32_MSG16to32( &msg16, msg32 );
317         break;
318     }
319
320     case WH_JOURNALPLAYBACK:
321     {
322         EVENTMSG *em32 = (EVENTMSG *)lparam;
323         EVENTMSG16 em16;
324
325         em16.message = em32->message;
326         em16.paramL  = em32->paramL;
327         em16.paramH  = em32->paramH;
328         em16.time    = em32->time;
329         lparam = MapLS( &em16 );
330         ret = call_hook_16( proc, id, code, wparam, lparam );
331         UnMapLS( lparam );
332         break;
333     }
334
335     case WH_CALLWNDPROC:
336     {
337         CWPSTRUCT *cwp32 = (CWPSTRUCT *)lparam;
338         CWPSTRUCT16 cwp16;
339         MSGPARAM16 mp16;
340
341         cwp16.hwnd   = HWND_16(cwp32->hwnd);
342         cwp16.lParam = cwp32->lParam;
343
344         if (unicode)
345             WINPROC_MapMsg32WTo16( cwp32->hwnd, cwp32->message, cwp32->wParam,
346                                    &cwp16.message, &cwp16.wParam, &cwp16.lParam );
347         else
348             WINPROC_MapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam,
349                                    &cwp16.message, &cwp16.wParam, &cwp16.lParam );
350
351         lparam = MapLS( &cwp16 );
352         ret = call_hook_16( proc, id, code, wparam, lparam );
353         UnMapLS( lparam );
354
355         mp16.wParam  = cwp16.wParam;
356         mp16.lParam  = cwp16.lParam;
357         mp16.lResult = 0;
358         if (unicode)
359             WINPROC_UnmapMsg32WTo16( cwp32->hwnd, cwp32->message, cwp32->wParam,
360                                      cwp32->lParam, &mp16 );
361         else
362             WINPROC_UnmapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam,
363                                      cwp32->lParam, &mp16 );
364         break;
365     }
366
367     case WH_CBT:
368         switch (code)
369         {
370         case HCBT_CREATEWND:
371             {
372                 CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lparam;
373                 CBT_CREATEWND16 cbtcw16;
374                 CREATESTRUCT16 cs16;
375
376                 STRUCT32_CREATESTRUCT32Ato16( cbtcw32->lpcs, &cs16 );
377                 cbtcw16.lpcs = (CREATESTRUCT16 *)MapLS( &cs16 );
378                 cbtcw16.hwndInsertAfter = HWND_16( cbtcw32->hwndInsertAfter );
379                 lparam = MapLS( &cbtcw16 );
380
381                 if (unicode)
382                 {
383                     cs16.lpszName = map_str_32W_to_16( (LPWSTR)cbtcw32->lpcs->lpszName );
384                     cs16.lpszClass = map_str_32W_to_16( (LPWSTR)cbtcw32->lpcs->lpszClass );
385                     ret = call_hook_16( proc, id, code, wparam, lparam );
386                     unmap_str_32W_to_16( cs16.lpszName );
387                     unmap_str_32W_to_16( cs16.lpszClass );
388                 }
389                 else
390                 {
391                     cs16.lpszName = MapLS( cbtcw32->lpcs->lpszName );
392                     cs16.lpszClass = MapLS( cbtcw32->lpcs->lpszClass );
393                     ret = call_hook_16( proc, id, code, wparam, lparam );
394                     UnMapLS( cs16.lpszName );
395                     UnMapLS( cs16.lpszClass );
396                 }
397                 cbtcw32->hwndInsertAfter = WIN_Handle32( cbtcw16.hwndInsertAfter );
398                 UnMapLS( (SEGPTR)cbtcw16.lpcs );
399                 UnMapLS( lparam );
400                 break;
401             }
402
403         case HCBT_ACTIVATE:
404             {
405                 CBTACTIVATESTRUCT *cas32 = (CBTACTIVATESTRUCT *)lparam;
406                 CBTACTIVATESTRUCT16 cas16;
407
408                 cas16.fMouse     = cas32->fMouse;
409                 cas16.hWndActive = HWND_16( cas32->hWndActive );
410
411                 lparam = MapLS( &cas16 );
412                 ret = call_hook_16( proc, id, code, wparam, lparam );
413                 UnMapLS( lparam );
414                 break;
415             }
416         case HCBT_CLICKSKIPPED:
417             {
418                 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lparam;
419                 MOUSEHOOKSTRUCT16 ms16;
420
421                 ms16.pt.x         = ms32->pt.x;
422                 ms16.pt.y         = ms32->pt.y;
423                 ms16.hwnd         = HWND_16( ms32->hwnd );
424                 ms16.wHitTestCode = ms32->wHitTestCode;
425                 ms16.dwExtraInfo  = ms32->dwExtraInfo;
426
427                 lparam = MapLS( &ms16 );
428                 ret = call_hook_16( proc, id, code, wparam, lparam );
429                 UnMapLS( lparam );
430                 break;
431             }
432         case HCBT_MOVESIZE:
433             {
434                 RECT *rect32 = (RECT *)lparam;
435                 RECT16 rect16;
436
437                 CONV_RECT32TO16( rect32, &rect16 );
438                 lparam = MapLS( &rect16 );
439                 ret = call_hook_16( proc, id, code, wparam, lparam );
440                 UnMapLS( lparam );
441                 break;
442             }
443         }
444         break;
445
446     case WH_MOUSE:
447     {
448         MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lparam;
449         MOUSEHOOKSTRUCT16 ms16;
450
451         ms16.pt.x         = ms32->pt.x;
452         ms16.pt.y         = ms32->pt.y;
453         ms16.hwnd         = HWND_16( ms32->hwnd );
454         ms16.wHitTestCode = ms32->wHitTestCode;
455         ms16.dwExtraInfo  = ms32->dwExtraInfo;
456
457         lparam = MapLS( &ms16 );
458         ret = call_hook_16( proc, id, code, wparam, lparam );
459         UnMapLS( lparam );
460         break;
461     }
462
463     case WH_DEBUG:
464     {
465         DEBUGHOOKINFO *dh32 = (DEBUGHOOKINFO *)lparam;
466         DEBUGHOOKINFO16 dh16;
467
468         dh16.hModuleHook = 0; /* FIXME */
469         dh16.reserved    = 0;
470         dh16.lParam      = dh32->lParam;
471         dh16.wParam      = dh32->wParam;
472         dh16.code        = dh32->code;
473
474         lparam = MapLS( &dh16 );
475         ret = call_hook_16( proc, id, code, wparam, lparam );
476         UnMapLS( lparam );
477         break;
478     }
479
480     case WH_SHELL:
481     case WH_KEYBOARD:
482         ret = call_hook_16( proc, id, code, wparam, lparam );
483         break;
484
485     case WH_HARDWARE:
486     case WH_FOREGROUNDIDLE:
487     case WH_CALLWNDPROCRET:
488     default:
489         FIXME("\t[%i] 32to16 translation unimplemented\n", id);
490         ret = call_hook_16( proc, id, code, wparam, lparam );
491         break;
492     }
493     return ret;
494 }
495
496
497 /***********************************************************************
498  *           call_hook_32_to_32
499  *
500  * Convert hook params to/from Unicode and call hook procedure
501  */
502 static LRESULT call_hook_32_to_32( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam,
503                                    BOOL to_unicode )
504 {
505     if (id != WH_CBT || code != HCBT_CREATEWND) return proc( code, wparam, lparam );
506
507     if (to_unicode)  /* ASCII to Unicode */
508     {
509         CBT_CREATEWNDA *cbtcwA = (CBT_CREATEWNDA *)lparam;
510         CBT_CREATEWNDW cbtcwW;
511         CREATESTRUCTW csW;
512         LRESULT ret;
513
514         cbtcwW.lpcs = &csW;
515         cbtcwW.hwndInsertAfter = cbtcwA->hwndInsertAfter;
516         csW = *(CREATESTRUCTW *)cbtcwA->lpcs;
517
518         if (HIWORD(cbtcwA->lpcs->lpszName))
519             csW.lpszName = HEAP_strdupAtoW( GetProcessHeap(), 0, cbtcwA->lpcs->lpszName );
520         if (HIWORD(cbtcwA->lpcs->lpszClass))
521             csW.lpszClass = HEAP_strdupAtoW( GetProcessHeap(), 0, cbtcwA->lpcs->lpszClass );
522         ret = proc( code, wparam, (LPARAM)&cbtcwW );
523         cbtcwA->hwndInsertAfter = cbtcwW.hwndInsertAfter;
524         if (HIWORD(csW.lpszName)) HeapFree( GetProcessHeap(), 0, (LPWSTR)csW.lpszName );
525         if (HIWORD(csW.lpszClass)) HeapFree( GetProcessHeap(), 0, (LPWSTR)csW.lpszClass );
526         return ret;
527     }
528     else  /* Unicode to ASCII */
529     {
530         CBT_CREATEWNDW *cbtcwW = (CBT_CREATEWNDW *)lparam;
531         CBT_CREATEWNDA cbtcwA;
532         CREATESTRUCTA csA;
533         LRESULT ret;
534
535         cbtcwA.lpcs = &csA;
536         cbtcwA.hwndInsertAfter = cbtcwW->hwndInsertAfter;
537         csA = *(CREATESTRUCTA *)cbtcwW->lpcs;
538
539         if (HIWORD(cbtcwW->lpcs->lpszName))
540             csA.lpszName = HEAP_strdupWtoA( GetProcessHeap(), 0, cbtcwW->lpcs->lpszName );
541         if (HIWORD(cbtcwW->lpcs->lpszClass))
542             csA.lpszClass = HEAP_strdupWtoA( GetProcessHeap(), 0, cbtcwW->lpcs->lpszClass );
543         ret = proc( code, wparam, (LPARAM)&cbtcwA );
544         cbtcwW->hwndInsertAfter = cbtcwA.hwndInsertAfter;
545         if (HIWORD(csA.lpszName)) HeapFree( GetProcessHeap(), 0, (LPSTR)csA.lpszName );
546         if (HIWORD(csA.lpszClass)) HeapFree( GetProcessHeap(), 0, (LPSTR)csA.lpszClass );
547         return ret;
548     }
549 }
550
551
552 /***********************************************************************
553  *           call_hook
554  *
555  * Call a hook procedure.
556  */
557 inline static LRESULT call_hook( HOOKDATA *data, INT fromtype, INT code,
558                                  WPARAM wparam, LPARAM lparam )
559 {
560     INT type = (data->flags & HOOK_MAPTYPE);
561     LRESULT ret;
562
563     /* Suspend window structure locks before calling user code */
564     int iWndsLocks = WIN_SuspendWndsLock();
565
566     if (type == HOOK_WIN16)
567     {
568         if (fromtype == HOOK_WIN16)  /* 16->16 */
569             ret = call_hook_16( (HOOKPROC16)data->proc, data->id, code, wparam, lparam );
570         else  /* 32->16 */
571             ret = call_hook_32_to_16( (HOOKPROC16)data->proc, data->id, code, wparam,
572                                       lparam, (type == HOOK_WIN32W) );
573     }
574     else if (fromtype == HOOK_WIN16)  /* 16->32 */
575         ret = call_hook_16_to_32( data->proc, data->id, code, wparam,
576                                   lparam, (type == HOOK_WIN32W) );
577     else /* 32->32, check unicode */
578     {
579         if (type == fromtype)
580             ret = data->proc( code, wparam, lparam );
581         else
582             ret = call_hook_32_to_32( data->proc, data->id, code, wparam,
583                                       lparam, (type == HOOK_WIN32W) );
584     }
585     WIN_RestoreWndsLock(iWndsLocks);
586     return ret;
587 }
588
589
590 /***********************************************************************
591  *           HOOK_GetNextHook
592  *
593  * Get the next hook of a given hook.
594  */
595 static HHOOK HOOK_GetNextHook( HHOOK hook )
596 {
597     HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(HHOOK_16(hook));
598
599     if (!data || !hook) return 0;
600     if (data->next) return HHOOK_32(data->next);
601     if (!data->ownerQueue) return 0;  /* Already system hook */
602
603     /* Now start enumerating the system hooks */
604     return HHOOK_32(HOOK_systemHooks[data->id - WH_MINHOOK]);
605 }
606
607
608 /***********************************************************************
609  *           HOOK_GetHook
610  *
611  * Get the first hook for a given type.
612  */
613 static HHOOK HOOK_GetHook( INT16 id )
614 {
615     MESSAGEQUEUE *queue;
616     HANDLE16 handle = 0;
617
618     if ((queue = QUEUE_Current()) != NULL)
619         handle = queue->hooks[id - WH_MINHOOK];
620     if (!handle) handle = HOOK_systemHooks[id - WH_MINHOOK];
621     return HHOOK_32(handle);
622 }
623
624
625 /***********************************************************************
626  *           HOOK_SetHook
627  *
628  * Install a given hook.
629  */
630 static HHOOK HOOK_SetHook( INT16 id, LPVOID proc, INT type,
631                            HMODULE16 hModule, DWORD dwThreadId )
632 {
633     HOOKDATA *data;
634     HANDLE16 handle;
635     HQUEUE16 hQueue = 0;
636
637     if ((id < WH_MINHOOK) || (id > WH_MAXHOOK)) return 0;
638
639     TRACE("Setting hook %d: %08x %04x %08lx\n",
640                   id, (UINT)proc, hModule, dwThreadId );
641
642     /* Create task queue if none present */
643     InitThreadInput16( 0, 0 );
644
645     if (id == WH_JOURNALPLAYBACK) EnableHardwareInput16(FALSE);
646
647     if (dwThreadId)  /* Task-specific hook */
648     {
649         if ((id == WH_JOURNALRECORD) || (id == WH_JOURNALPLAYBACK) ||
650             (id == WH_SYSMSGFILTER)) return 0;  /* System-only hooks */
651         if (!(hQueue = GetThreadQueue16( dwThreadId )))
652             return 0;
653     }
654
655     /* Create the hook structure */
656
657     if (!(handle = USER_HEAP_ALLOC( sizeof(HOOKDATA) ))) return 0;
658     data = (HOOKDATA *) USER_HEAP_LIN_ADDR( handle );
659     data->proc        = proc;
660     data->id          = id;
661     data->ownerQueue  = hQueue;
662     data->ownerModule = hModule;
663     data->flags       = type;
664
665     /* Insert it in the correct linked list */
666
667     if (hQueue)
668     {
669         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
670         data->next = queue->hooks[id - WH_MINHOOK];
671         queue->hooks[id - WH_MINHOOK] = handle;
672         QUEUE_Unlock( queue );
673     }
674     else
675     {
676         data->next = HOOK_systemHooks[id - WH_MINHOOK];
677         HOOK_systemHooks[id - WH_MINHOOK] = handle;
678     }
679     TRACE("Setting hook %d: ret=%04x [next=%04x]\n",
680                            id, handle, data->next );
681
682     return HHOOK_32(handle);
683 }
684
685
686 /***********************************************************************
687  *           HOOK_RemoveHook
688  *
689  * Remove a hook from the list.
690  */
691 static BOOL HOOK_RemoveHook( HHOOK hook )
692 {
693     HOOKDATA *data;
694     HANDLE16 *prevHandle;
695
696     TRACE("Removing hook %04x\n", hook );
697
698     if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(HHOOK_16(hook)))) return FALSE;
699     if (data->flags & HOOK_INUSE)
700     {
701         /* Mark it for deletion later on */
702         WARN("Hook still running, deletion delayed\n" );
703         data->proc = (HOOKPROC)0;
704         return TRUE;
705     }
706
707     if (data->id == WH_JOURNALPLAYBACK) EnableHardwareInput16(TRUE);
708
709     /* Remove it from the linked list */
710
711     if (data->ownerQueue)
712     {
713         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( data->ownerQueue );
714         if (!queue) return FALSE;
715         prevHandle = &queue->hooks[data->id - WH_MINHOOK];
716         QUEUE_Unlock( queue );
717     }
718     else prevHandle = &HOOK_systemHooks[data->id - WH_MINHOOK];
719
720     while (*prevHandle && *prevHandle != HHOOK_16(hook))
721         prevHandle = &((HOOKDATA *)USER_HEAP_LIN_ADDR(*prevHandle))->next;
722
723     if (!*prevHandle) return FALSE;
724     *prevHandle = data->next;
725
726     USER_HEAP_FREE(HHOOK_16(hook));
727     return TRUE;
728 }
729
730
731 /***********************************************************************
732  *           HOOK_FindValidHook
733  */
734 static HHOOK HOOK_FindValidHook( HHOOK hook )
735 {
736     HOOKDATA *data;
737
738     for (;;)
739     {
740         if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(HHOOK_16(hook)))) return 0;
741         if (data->proc) return hook;
742         hook = HHOOK_32(data->next);
743     }
744 }
745
746 /***********************************************************************
747  *           HOOK_CallHook
748  *
749  * Call a hook procedure.
750  */
751 static LRESULT HOOK_CallHook( HHOOK hook, INT fromtype, INT code,
752                               WPARAM wParam, LPARAM lParam )
753 {
754     MESSAGEQUEUE *queue;
755     HANDLE16 prevHandle;
756     HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(HHOOK_16(hook));
757     LRESULT ret;
758
759     if (!(queue = QUEUE_Current())) return 0;
760     prevHandle = queue->hCurHook;
761     queue->hCurHook = HHOOK_16(hook);
762
763     TRACE("Calling hook %04x: %d %08x %08lx\n", hook, code, wParam, lParam );
764
765     data->flags |= HOOK_INUSE;
766     ret = call_hook( data, fromtype, code, wParam, lParam );
767     data->flags &= ~HOOK_INUSE;
768
769     TRACE("Ret hook %04x = %08lx\n", hook, ret );
770
771     queue->hCurHook = prevHandle;
772     if (!data->proc) HOOK_RemoveHook( hook );
773     return ret;
774 }
775
776 /***********************************************************************
777  *           Exported Functions & APIs
778  */
779
780 /***********************************************************************
781  *           HOOK_IsHooked
782  *
783  * Replacement for calling HOOK_GetHook from other modules.
784  */
785 BOOL HOOK_IsHooked( INT16 id )
786 {
787     return HOOK_GetHook( id ) != 0;
788 }
789
790
791 /***********************************************************************
792  *           HOOK_CallHooks16
793  *
794  * Call a hook chain.
795  */
796 LRESULT HOOK_CallHooks16( INT16 id, INT16 code, WPARAM16 wParam,
797                           LPARAM lParam )
798 {
799     HHOOK hook;
800
801     if (!(hook = HOOK_GetHook( id ))) return 0;
802     if (!(hook = HOOK_FindValidHook(hook))) return 0;
803     return HOOK_CallHook( hook, HOOK_WIN16, code, wParam, lParam );
804 }
805
806 /***********************************************************************
807  *           HOOK_CallHooksA
808  *
809  * Call a hook chain.
810  */
811 LRESULT HOOK_CallHooksA( INT id, INT code, WPARAM wParam,
812                            LPARAM lParam )
813 {
814     HHOOK hook;
815
816     if (!(hook = HOOK_GetHook( id ))) return 0;
817     if (!(hook = HOOK_FindValidHook(hook))) return 0;
818     return HOOK_CallHook( hook, HOOK_WIN32A, code, wParam, lParam );
819 }
820
821 /***********************************************************************
822  *           HOOK_CallHooksW
823  *
824  * Call a hook chain.
825  */
826 LRESULT HOOK_CallHooksW( INT id, INT code, WPARAM wParam,
827                            LPARAM lParam )
828 {
829     HHOOK hook;
830
831     if (!(hook = HOOK_GetHook( id ))) return 0;
832     if (!(hook = HOOK_FindValidHook(hook))) return 0;
833     return HOOK_CallHook( hook, HOOK_WIN32W, code, wParam,
834                           lParam );
835 }
836
837
838 /***********************************************************************
839  *           HOOK_FreeModuleHooks
840  */
841 void HOOK_FreeModuleHooks( HMODULE16 hModule )
842 {
843  /* remove all system hooks registered by this module */
844
845   HOOKDATA*     hptr;
846   HANDLE16      handle, next;
847   int           id;
848
849   for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
850     {
851        handle = HOOK_systemHooks[id - WH_MINHOOK];
852        while( handle )
853           if( (hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(handle)) )
854             {
855               next = hptr->next;
856               if( hptr->ownerModule == hModule )
857                 {
858                   hptr->flags &= HOOK_MAPTYPE;
859                   HOOK_RemoveHook(HHOOK_32(handle));
860                 }
861               handle = next;
862             }
863           else handle = 0;
864     }
865 }
866
867 /***********************************************************************
868  *           HOOK_FreeQueueHooks
869  */
870 void HOOK_FreeQueueHooks(void)
871 {
872   /* remove all hooks registered by the current queue */
873
874   HOOKDATA*     hptr = NULL;
875   HHOOK         hook, next;
876   int           id;
877
878   for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
879     {
880        hook = HOOK_GetHook( id );
881        while( hook )
882         {
883           next = HOOK_GetNextHook(hook);
884
885           hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(HHOOK_16(hook));
886           if( hptr && hptr->ownerQueue )
887             {
888               hptr->flags &= HOOK_MAPTYPE;
889               HOOK_RemoveHook(hook);
890             }
891           hook = next;
892         }
893     }
894 }
895
896
897 /***********************************************************************
898  *              SetWindowsHook (USER.121)
899  */
900 FARPROC16 WINAPI SetWindowsHook16( INT16 id, HOOKPROC16 proc )
901 {
902     HINSTANCE16 hInst = FarGetOwner16( HIWORD(proc) );
903
904     /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
905     HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
906
907     return (FARPROC16)SetWindowsHookEx16( id, proc, hInst, hTask );
908 }
909
910 /***********************************************************************
911  *              SetWindowsHookA (USER32.@)
912  */
913 HHOOK WINAPI SetWindowsHookA( INT id, HOOKPROC proc )
914 {
915     return SetWindowsHookExA( id, proc, 0, GetCurrentThreadId() );
916 }
917
918 /***********************************************************************
919  *              SetWindowsHookW (USER32.@)
920  */
921 HHOOK WINAPI SetWindowsHookW( INT id, HOOKPROC proc )
922 {
923     return SetWindowsHookExW( id, proc, 0, GetCurrentThreadId() );
924 }
925
926
927 /***********************************************************************
928  *              SetWindowsHookEx (USER.291)
929  *              SetWindowsHookEx16 (USER32.@)
930  */
931 HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst,
932                                  HTASK16 hTask )
933 {
934     if (id == WH_DEBUG)
935     {
936         FIXME("WH_DEBUG is broken in 16-bit Windows.\n");
937         return 0;
938     }
939     return HOOK_SetHook( id, proc, HOOK_WIN16, GetExePtr(hInst), (DWORD)hTask );
940 }
941
942 /***********************************************************************
943  *              SetWindowsHookExA (USER32.@)
944  */
945 HHOOK WINAPI SetWindowsHookExA( INT id, HOOKPROC proc, HINSTANCE hInst,
946                                   DWORD dwThreadId )
947 {
948     return HOOK_SetHook( id, proc, HOOK_WIN32A, MapHModuleLS(hInst), dwThreadId );
949 }
950
951 /***********************************************************************
952  *              SetWindowsHookExW (USER32.@)
953  */
954 HHOOK WINAPI SetWindowsHookExW( INT id, HOOKPROC proc, HINSTANCE hInst,
955                                   DWORD dwThreadId )
956 {
957     return HOOK_SetHook( id, proc, HOOK_WIN32W, MapHModuleLS(hInst), dwThreadId );
958 }
959
960
961 /***********************************************************************
962  *              UnhookWindowsHook (USER.234)
963  */
964 BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
965 {
966     return UnhookWindowsHook( id, (HOOKPROC)proc );
967 }
968
969 /***********************************************************************
970  *              UnhookWindowsHook (USER32.@)
971  */
972 BOOL WINAPI UnhookWindowsHook( INT id, HOOKPROC proc )
973 {
974     HHOOK hook = HOOK_GetHook( id );
975
976     TRACE("%d %08lx\n", id, (DWORD)proc );
977
978     while (hook)
979     {
980         HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(HHOOK_16(hook));
981         if (data->proc == proc) break;
982         hook = HOOK_GetNextHook( hook );
983     }
984     if (!hook) return FALSE;
985     return HOOK_RemoveHook( hook );
986 }
987
988
989 /***********************************************************************
990  *              UnhookWindowsHookEx (USER.292)
991  */
992 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
993 {
994     return HOOK_RemoveHook(hhook);
995 }
996
997 /***********************************************************************
998  *              UnhookWindowsHookEx (USER32.@)
999  */
1000 BOOL WINAPI UnhookWindowsHookEx( HHOOK hhook )
1001 {
1002     return HOOK_RemoveHook(hhook);
1003 }
1004
1005
1006 /***********************************************************************
1007  *              CallNextHookEx (USER.293)
1008  *              CallNextHookEx16 (USER32.@)
1009  *
1010  * I wouldn't have separated this into 16 and 32 bit versions, but I
1011  * need a way to figure out if I need to do a mapping or not.
1012  */
1013 LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wParam,
1014                                  LPARAM lParam )
1015 {
1016     HHOOK next;
1017
1018     if (!(next = HOOK_GetNextHook(hhook))) return 0;
1019
1020     return HOOK_CallHook( next, HOOK_WIN16, code, wParam, lParam );
1021 }
1022
1023
1024 /***********************************************************************
1025  *              CallNextHookEx (USER32.@)
1026  *
1027  * There aren't ANSI and UNICODE versions of this.
1028  */
1029 LRESULT WINAPI CallNextHookEx( HHOOK hhook, INT code, WPARAM wParam,
1030                                  LPARAM lParam )
1031 {
1032     HHOOK next;
1033     INT fromtype;       /* figure out Ansi/Unicode */
1034     HOOKDATA *oldhook;
1035
1036     if (!(next = HOOK_GetNextHook(hhook))) return 0;
1037
1038     oldhook = (HOOKDATA *)USER_HEAP_LIN_ADDR(HHOOK_16(hhook));
1039     fromtype = oldhook->flags & HOOK_MAPTYPE;
1040
1041     if (fromtype == HOOK_WIN16)
1042       ERR("called from 16bit hook!\n");
1043
1044     return HOOK_CallHook( next, fromtype, code, wParam, lParam );
1045 }
1046
1047
1048 /***********************************************************************
1049  *              DefHookProc (USER.235)
1050  */
1051 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wParam, LPARAM lParam,
1052                               HHOOK *hhook )
1053 {
1054     /* Note: the *hhook parameter is never used, since we rely on the
1055      * current hook value from the task queue to find the next hook. */
1056     MESSAGEQUEUE *queue;
1057
1058     if (!(queue = QUEUE_Current())) return 0;
1059     return CallNextHookEx16(HHOOK_32(queue->hCurHook), code, wParam, lParam);
1060 }
1061
1062
1063 /***********************************************************************
1064  *              CallMsgFilter (USER.123)
1065  */
1066 BOOL16 WINAPI CallMsgFilter16( SEGPTR msg, INT16 code )
1067 {
1068     if (GetSysModalWindow16()) return FALSE;
1069     if (HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) return TRUE;
1070     return HOOK_CallHooks16( WH_MSGFILTER, code, 0, (LPARAM)msg );
1071 }
1072
1073
1074 /***********************************************************************
1075  *              CallMsgFilter32 (USER.823)
1076  */
1077 BOOL16 WINAPI CallMsgFilter32_16( SEGPTR msg16_32, INT16 code, BOOL16 wHaveParamHigh )
1078 {
1079     MSG32_16 *lpmsg16_32 = MapSL(msg16_32);
1080
1081     if (wHaveParamHigh == FALSE)
1082     {
1083         lpmsg16_32->wParamHigh = 0;
1084         /* WARNING: msg16_32->msg has to be the first variable in the struct */
1085         return CallMsgFilter16(msg16_32, code);
1086     }
1087     else
1088     {
1089         MSG msg32;
1090         BOOL16 ret;
1091
1092         msg32.hwnd      = WIN_Handle32( lpmsg16_32->msg.hwnd );
1093         msg32.message   = lpmsg16_32->msg.message;
1094         msg32.wParam    = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh);
1095         msg32.lParam    = lpmsg16_32->msg.lParam;
1096         msg32.time      = lpmsg16_32->msg.time;
1097         msg32.pt.x      = lpmsg16_32->msg.pt.x;
1098         msg32.pt.y      = lpmsg16_32->msg.pt.y;
1099
1100         ret = (BOOL16)CallMsgFilterA(&msg32, (INT)code);
1101
1102         lpmsg16_32->msg.hwnd    = HWND_16( msg32.hwnd );
1103         lpmsg16_32->msg.message = msg32.message;
1104         lpmsg16_32->msg.wParam  = LOWORD(msg32.wParam);
1105         lpmsg16_32->msg.lParam  = msg32.lParam;
1106         lpmsg16_32->msg.time    = msg32.time;
1107         lpmsg16_32->msg.pt.x    = msg32.pt.x;
1108         lpmsg16_32->msg.pt.y    = msg32.pt.y;
1109         lpmsg16_32->wParamHigh  = HIWORD(msg32.wParam);
1110
1111         return ret;
1112     }
1113 }
1114
1115
1116 /***********************************************************************
1117  *              CallMsgFilterA (USER32.@)
1118  *
1119  * FIXME: There are ANSI and UNICODE versions of this, plus an unspecified
1120  * version, plus USER (the 16bit one) has a CallMsgFilter32 function.
1121  */
1122 BOOL WINAPI CallMsgFilterA( LPMSG msg, INT code )
1123 {
1124     if (GetSysModalWindow16()) return FALSE;    /* ??? */
1125     if (HOOK_CallHooksA( WH_SYSMSGFILTER, code, 0, (LPARAM)msg ))
1126       return TRUE;
1127     return HOOK_CallHooksA( WH_MSGFILTER, code, 0, (LPARAM)msg );
1128 }
1129
1130
1131 /***********************************************************************
1132  *              CallMsgFilterW (USER32.@)
1133  */
1134 BOOL WINAPI CallMsgFilterW( LPMSG msg, INT code )
1135 {
1136     if (GetSysModalWindow16()) return FALSE;    /* ??? */
1137     if (HOOK_CallHooksW( WH_SYSMSGFILTER, code, 0, (LPARAM)msg ))
1138       return TRUE;
1139     return HOOK_CallHooksW( WH_MSGFILTER, code, 0, (LPARAM)msg );
1140 }
1141
1142
1143 /***********************************************************************
1144  *           SetWinEventHook                            [USER32.@]
1145  *
1146  * Set up an event hook for a set of events.
1147  *
1148  * PARAMS
1149  *  dwMin     [I] Lowest event handled by pfnProc
1150  *  dwMax     [I] Highest event handled by pfnProc
1151  *  hModule   [I] DLL containing pfnProc
1152  *  pfnProc   [I] Callback event hook function
1153  *  dwProcess [I] Process to get events from, or 0 for all processes
1154  *  dwThread  [I] Thread to get events from, or 0 for all threads
1155  *  dwFlags   [I] Flags indicating the status of pfnProc
1156  *
1157  * RETURNS
1158  *  Success: A handle representing the hook.
1159  *  Failure: A NULL handle.
1160  *
1161  * BUGS
1162  *  Not implemented.
1163  */
1164 HWINEVENTHOOK WINAPI SetWinEventHook(DWORD dwMin, DWORD dwMax, HMODULE hModule,
1165                                      WINEVENTPROC pfnProc, DWORD dwProcess,
1166                                      DWORD dwThread, DWORD dwFlags)
1167 {
1168   FIXME("(%ld,%ld,0x%08x,%p,%ld,%ld,0x%08lx)-stub!\n", dwMin, dwMax, hModule,
1169         pfnProc, dwProcess, dwThread, dwFlags);
1170
1171   return (HWINEVENTHOOK)0;
1172 }
1173
1174 /***********************************************************************
1175  *           UnhookWinEvent                             [USER32.@]
1176  *
1177  * Remove an event hook for a set of events.
1178  *
1179  * PARAMS
1180  *  hEventHook [I] Event hook to remove
1181  *
1182  * RETURNS
1183  *  Success: TRUE. The event hook has been removed.
1184  *  Failure: FALSE, if hEventHook is invalid.
1185  *
1186  * BUGS
1187  *  Not implemented.
1188  */
1189 BOOL WINAPI UnhookWinEvent(HWINEVENTHOOK hEventHook)
1190 {
1191   FIXME("(%p)-stub!\n", (void*)hEventHook);
1192
1193   if (!hEventHook)
1194     return FALSE;
1195
1196   return TRUE;
1197 }
1198
1199 /***********************************************************************
1200  *           NotifyWinEvent                             [USER32.@]
1201  *
1202  * Inform the OS that an event has occurred.
1203  *
1204  * PARAMS
1205  *  dwEvent  [I] Id of the event
1206  *  hWnd     [I] Window holding the object that created the event
1207  *  nId      [I] Type of object that created the event
1208  *  nChildId [I] Child object of nId, or CHILDID_SELF.
1209  *
1210  * RETURNS
1211  *  Nothing.
1212  *
1213  * BUGS
1214  *  Not implemented.
1215  */
1216 VOID WINAPI NotifyWinEvent(DWORD dwEvent, HWND hWnd, LONG nId, LONG nChildId)
1217 {
1218   FIXME("(%ld,0x%08x,%ld,%ld)-stub!\n", dwEvent, hWnd, nId, nChildId);
1219 }
1220
1221 /***********************************************************************
1222  *           IsWinEventHookInstalled                       [USER32.@]
1223  *
1224  * Determine if an event hook is installed for an event.
1225  *
1226  * PARAMS
1227  *  dwEvent  [I] Id of the event
1228  *
1229  * RETURNS
1230  *  TRUE,  If there are any hooks installed for the event.
1231  *  FALSE, Otherwise.
1232  *
1233  * BUGS
1234  *  Not implemented.
1235  */
1236 BOOL WINAPI IsWinEventHookInstalled(DWORD dwEvent)
1237 {
1238   FIXME("(%ld)-stub!\n", dwEvent);
1239   return TRUE;
1240 }