- The TTM_ message needed to be in correct order.
[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  */
930 HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst,
931                                  HTASK16 hTask )
932 {
933     if (id == WH_DEBUG)
934     {
935         FIXME("WH_DEBUG is broken in 16-bit Windows.\n");
936         return 0;
937     }
938     return HOOK_SetHook( id, proc, HOOK_WIN16, GetExePtr(hInst), (DWORD)hTask );
939 }
940
941 /***********************************************************************
942  *              SetWindowsHookExA (USER32.@)
943  */
944 HHOOK WINAPI SetWindowsHookExA( INT id, HOOKPROC proc, HINSTANCE hInst,
945                                   DWORD dwThreadId )
946 {
947     return HOOK_SetHook( id, proc, HOOK_WIN32A, MapHModuleLS(hInst), dwThreadId );
948 }
949
950 /***********************************************************************
951  *              SetWindowsHookExW (USER32.@)
952  */
953 HHOOK WINAPI SetWindowsHookExW( INT id, HOOKPROC proc, HINSTANCE hInst,
954                                   DWORD dwThreadId )
955 {
956     return HOOK_SetHook( id, proc, HOOK_WIN32W, MapHModuleLS(hInst), dwThreadId );
957 }
958
959
960 /***********************************************************************
961  *              UnhookWindowsHook (USER.234)
962  */
963 BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
964 {
965     return UnhookWindowsHook( id, (HOOKPROC)proc );
966 }
967
968 /***********************************************************************
969  *              UnhookWindowsHook (USER32.@)
970  */
971 BOOL WINAPI UnhookWindowsHook( INT id, HOOKPROC proc )
972 {
973     HHOOK hook = HOOK_GetHook( id );
974
975     TRACE("%d %08lx\n", id, (DWORD)proc );
976
977     while (hook)
978     {
979         HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(HHOOK_16(hook));
980         if (data->proc == proc) break;
981         hook = HOOK_GetNextHook( hook );
982     }
983     if (!hook) return FALSE;
984     return HOOK_RemoveHook( hook );
985 }
986
987
988 /***********************************************************************
989  *              UnhookWindowsHookEx (USER.292)
990  */
991 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
992 {
993     return HOOK_RemoveHook(hhook);
994 }
995
996 /***********************************************************************
997  *              UnhookWindowsHookEx (USER32.@)
998  */
999 BOOL WINAPI UnhookWindowsHookEx( HHOOK hhook )
1000 {
1001     return HOOK_RemoveHook(hhook);
1002 }
1003
1004
1005 /***********************************************************************
1006  *              CallNextHookEx (USER.293)
1007  *
1008  * I wouldn't have separated this into 16 and 32 bit versions, but I
1009  * need a way to figure out if I need to do a mapping or not.
1010  */
1011 LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wParam,
1012                                  LPARAM lParam )
1013 {
1014     HHOOK next;
1015
1016     if (!(next = HOOK_GetNextHook(hhook))) return 0;
1017
1018     return HOOK_CallHook( next, HOOK_WIN16, code, wParam, lParam );
1019 }
1020
1021
1022 /***********************************************************************
1023  *              CallNextHookEx (USER32.@)
1024  *
1025  * There aren't ANSI and UNICODE versions of this.
1026  */
1027 LRESULT WINAPI CallNextHookEx( HHOOK hhook, INT code, WPARAM wParam,
1028                                  LPARAM lParam )
1029 {
1030     HHOOK next;
1031     INT fromtype;       /* figure out Ansi/Unicode */
1032     HOOKDATA *oldhook;
1033
1034     if (!(next = HOOK_GetNextHook(hhook))) return 0;
1035
1036     oldhook = (HOOKDATA *)USER_HEAP_LIN_ADDR(HHOOK_16(hhook));
1037     fromtype = oldhook->flags & HOOK_MAPTYPE;
1038
1039     if (fromtype == HOOK_WIN16)
1040       ERR("called from 16bit hook!\n");
1041
1042     return HOOK_CallHook( next, fromtype, code, wParam, lParam );
1043 }
1044
1045
1046 /***********************************************************************
1047  *              DefHookProc (USER.235)
1048  */
1049 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wParam, LPARAM lParam,
1050                               HHOOK *hhook )
1051 {
1052     /* Note: the *hhook parameter is never used, since we rely on the
1053      * current hook value from the task queue to find the next hook. */
1054     MESSAGEQUEUE *queue;
1055
1056     if (!(queue = QUEUE_Current())) return 0;
1057     return CallNextHookEx16(HHOOK_32(queue->hCurHook), code, wParam, lParam);
1058 }
1059
1060
1061 /***********************************************************************
1062  *              CallMsgFilter (USER.123)
1063  */
1064 BOOL16 WINAPI CallMsgFilter16( SEGPTR msg, INT16 code )
1065 {
1066     if (GetSysModalWindow16()) return FALSE;
1067     if (HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) return TRUE;
1068     return HOOK_CallHooks16( WH_MSGFILTER, code, 0, (LPARAM)msg );
1069 }
1070
1071
1072 /***********************************************************************
1073  *              CallMsgFilter32 (USER.823)
1074  */
1075 BOOL16 WINAPI CallMsgFilter32_16( SEGPTR msg16_32, INT16 code, BOOL16 wHaveParamHigh )
1076 {
1077     MSG32_16 *lpmsg16_32 = MapSL(msg16_32);
1078
1079     if (wHaveParamHigh == FALSE)
1080     {
1081         lpmsg16_32->wParamHigh = 0;
1082         /* WARNING: msg16_32->msg has to be the first variable in the struct */
1083         return CallMsgFilter16(msg16_32, code);
1084     }
1085     else
1086     {
1087         MSG msg32;
1088         BOOL16 ret;
1089
1090         msg32.hwnd      = WIN_Handle32( lpmsg16_32->msg.hwnd );
1091         msg32.message   = lpmsg16_32->msg.message;
1092         msg32.wParam    = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh);
1093         msg32.lParam    = lpmsg16_32->msg.lParam;
1094         msg32.time      = lpmsg16_32->msg.time;
1095         msg32.pt.x      = lpmsg16_32->msg.pt.x;
1096         msg32.pt.y      = lpmsg16_32->msg.pt.y;
1097
1098         ret = (BOOL16)CallMsgFilterA(&msg32, (INT)code);
1099
1100         lpmsg16_32->msg.hwnd    = HWND_16( msg32.hwnd );
1101         lpmsg16_32->msg.message = msg32.message;
1102         lpmsg16_32->msg.wParam  = LOWORD(msg32.wParam);
1103         lpmsg16_32->msg.lParam  = msg32.lParam;
1104         lpmsg16_32->msg.time    = msg32.time;
1105         lpmsg16_32->msg.pt.x    = msg32.pt.x;
1106         lpmsg16_32->msg.pt.y    = msg32.pt.y;
1107         lpmsg16_32->wParamHigh  = HIWORD(msg32.wParam);
1108
1109         return ret;
1110     }
1111 }
1112
1113
1114 /***********************************************************************
1115  *              CallMsgFilterA (USER32.@)
1116  *
1117  * FIXME: There are ANSI and UNICODE versions of this, plus an unspecified
1118  * version, plus USER (the 16bit one) has a CallMsgFilter32 function.
1119  */
1120 BOOL WINAPI CallMsgFilterA( LPMSG msg, INT code )
1121 {
1122     if (GetSysModalWindow16()) return FALSE;    /* ??? */
1123     if (HOOK_CallHooksA( WH_SYSMSGFILTER, code, 0, (LPARAM)msg ))
1124       return TRUE;
1125     return HOOK_CallHooksA( WH_MSGFILTER, code, 0, (LPARAM)msg );
1126 }
1127
1128
1129 /***********************************************************************
1130  *              CallMsgFilterW (USER32.@)
1131  */
1132 BOOL WINAPI CallMsgFilterW( LPMSG msg, INT code )
1133 {
1134     if (GetSysModalWindow16()) return FALSE;    /* ??? */
1135     if (HOOK_CallHooksW( WH_SYSMSGFILTER, code, 0, (LPARAM)msg ))
1136       return TRUE;
1137     return HOOK_CallHooksW( WH_MSGFILTER, code, 0, (LPARAM)msg );
1138 }
1139
1140
1141 /***********************************************************************
1142  *           SetWinEventHook                            [USER32.@]
1143  *
1144  * Set up an event hook for a set of events.
1145  *
1146  * PARAMS
1147  *  dwMin     [I] Lowest event handled by pfnProc
1148  *  dwMax     [I] Highest event handled by pfnProc
1149  *  hModule   [I] DLL containing pfnProc
1150  *  pfnProc   [I] Callback event hook function
1151  *  dwProcess [I] Process to get events from, or 0 for all processes
1152  *  dwThread  [I] Thread to get events from, or 0 for all threads
1153  *  dwFlags   [I] Flags indicating the status of pfnProc
1154  *
1155  * RETURNS
1156  *  Success: A handle representing the hook.
1157  *  Failure: A NULL handle.
1158  *
1159  * BUGS
1160  *  Not implemented.
1161  */
1162 HWINEVENTHOOK WINAPI SetWinEventHook(DWORD dwMin, DWORD dwMax, HMODULE hModule,
1163                                      WINEVENTPROC pfnProc, DWORD dwProcess,
1164                                      DWORD dwThread, DWORD dwFlags)
1165 {
1166   FIXME("(%ld,%ld,0x%08x,%p,%ld,%ld,0x%08lx)-stub!\n", dwMin, dwMax, hModule,
1167         pfnProc, dwProcess, dwThread, dwFlags);
1168
1169   return (HWINEVENTHOOK)0;
1170 }
1171
1172 /***********************************************************************
1173  *           UnhookWinEvent                             [USER32.@]
1174  *
1175  * Remove an event hook for a set of events.
1176  *
1177  * PARAMS
1178  *  hEventHook [I] Event hook to remove
1179  *
1180  * RETURNS
1181  *  Success: TRUE. The event hook has been removed.
1182  *  Failure: FALSE, if hEventHook is invalid.
1183  *
1184  * BUGS
1185  *  Not implemented.
1186  */
1187 BOOL WINAPI UnhookWinEvent(HWINEVENTHOOK hEventHook)
1188 {
1189   FIXME("(%p)-stub!\n", (void*)hEventHook);
1190
1191   if (!hEventHook)
1192     return FALSE;
1193
1194   return TRUE;
1195 }
1196
1197 /***********************************************************************
1198  *           NotifyWinEvent                             [USER32.@]
1199  *
1200  * Inform the OS that an event has occurred.
1201  *
1202  * PARAMS
1203  *  dwEvent  [I] Id of the event
1204  *  hWnd     [I] Window holding the object that created the event
1205  *  nId      [I] Type of object that created the event
1206  *  nChildId [I] Child object of nId, or CHILDID_SELF.
1207  *
1208  * RETURNS
1209  *  Nothing.
1210  *
1211  * BUGS
1212  *  Not implemented.
1213  */
1214 VOID WINAPI NotifyWinEvent(DWORD dwEvent, HWND hWnd, LONG nId, LONG nChildId)
1215 {
1216   FIXME("(%ld,0x%08x,%ld,%ld)-stub!\n", dwEvent, hWnd, nId, nChildId);
1217 }
1218
1219 /***********************************************************************
1220  *           IsWinEventHookInstalled                       [USER32.@]
1221  *
1222  * Determine if an event hook is installed for an event.
1223  *
1224  * PARAMS
1225  *  dwEvent  [I] Id of the event
1226  *
1227  * RETURNS
1228  *  TRUE,  If there are any hooks installed for the event.
1229  *  FALSE, Otherwise.
1230  *
1231  * BUGS
1232  *  Not implemented.
1233  */
1234 BOOL WINAPI IsWinEventHookInstalled(DWORD dwEvent)
1235 {
1236   FIXME("(%ld)-stub!\n", dwEvent);
1237   return TRUE;
1238 }