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