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