Require {DECLARE,DEFAULT}_DEBUG_CHANNEL statements to end in a ;
[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 "wingdi.h"
19 #include "winuser.h"
20 #include "wine/winuser16.h"
21 #include "wine/winbase16.h"
22 #include "callback.h"
23 #include "hook.h"
24 #include "win.h"
25 #include "queue.h"
26 #include "task.h"
27 #include "user.h"
28 #include "heap.h"
29 #include "struct32.h"
30 #include "winproc.h"
31 #include "debugtools.h"
32
33 DEFAULT_DEBUG_CHANNEL(hook);
34
35 #include "pshpack1.h"
36
37   /* Hook data (pointed to by a HHOOK) */
38 typedef struct
39 {
40     HANDLE16   next;               /* 00 Next hook in chain */
41     HOOKPROC   proc;               /* 02 Hook procedure (original) */
42     INT16      id;                 /* 06 Hook id (WH_xxx) */
43     HQUEUE16   ownerQueue;         /* 08 Owner queue (0 for system hook) */
44     HMODULE16  ownerModule;        /* 0a Owner module */
45     WORD       flags;              /* 0c flags */
46     HOOKPROC   thunk;              /* 0e Hook procedure (CallTo16 thunk) */
47 } HOOKDATA;
48
49 #include "poppack.h"
50
51 #define HOOK_MAGIC  ((int)'H' | (int)'K' << 8)  /* 'HK' */
52
53   /* This should probably reside in USER heap */
54 static HANDLE16 HOOK_systemHooks[WH_NB_HOOKS] = { 0, };
55
56 typedef VOID (*HOOK_MapFunc)(INT, INT, WPARAM *, LPARAM *);
57 typedef VOID (*HOOK_UnMapFunc)(INT, INT, WPARAM, LPARAM, WPARAM,
58                                LPARAM);
59
60 /***********************************************************************
61  *           HOOK_Map16To32Common
62  */
63 static void HOOK_Map16To32Common(INT id, INT code, WPARAM *pwParam,
64                                  LPARAM *plParam, BOOL bA )
65 {
66
67    switch( id )
68    {
69         case WH_MSGFILTER:
70         case WH_SYSMSGFILTER: 
71         case WH_GETMESSAGE: 
72         case WH_JOURNALRECORD:
73         {
74             LPMSG16 lpmsg16 = PTR_SEG_TO_LIN(*plParam);
75             LPMSG lpmsg32 = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpmsg32) );
76         
77             STRUCT32_MSG16to32( lpmsg16, lpmsg32 );
78             *plParam = (LPARAM)lpmsg32;
79             break;
80         } 
81
82         case WH_JOURNALPLAYBACK:
83         {
84             LPEVENTMSG16 lpem16 = PTR_SEG_TO_LIN(*plParam);
85             LPEVENTMSG lpem32 = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpem32) );
86
87             lpem32->message = lpem16->message;
88             lpem32->paramL = lpem16->paramL;
89             lpem32->paramH = lpem16->paramH;
90             lpem32->time = lpem16->time;
91             lpem32->hwnd = 0;   /* FIXME */
92
93             *plParam = (LPARAM)lpem32;
94             break;
95         } 
96
97         case WH_CALLWNDPROC:
98         {
99             LPCWPSTRUCT16   lpcwp16 = PTR_SEG_TO_LIN(*plParam);
100             LPCWPSTRUCT   lpcwp32 = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpcwp32) );
101             
102             lpcwp32->hwnd = lpcwp16->hwnd;
103             lpcwp32->lParam = lpcwp16->lParam;
104             
105             if (bA) WINPROC_MapMsg16To32A( lpcwp16->message, lpcwp16->wParam, 
106                                            &lpcwp32->message, &lpcwp32->wParam,
107                                            &lpcwp32->lParam );
108             else WINPROC_MapMsg16To32W( lpcwp16->hwnd,lpcwp16->message, lpcwp16->wParam, 
109                                         &lpcwp32->message, &lpcwp32->wParam,
110                                         &lpcwp32->lParam );
111             *plParam = (LPARAM)lpcwp32;
112             break;
113         }
114
115         case WH_CBT:
116           switch (code)
117           {
118             case HCBT_CREATEWND:
119             {
120                 LPCBT_CREATEWND16  lpcbtcw16 = PTR_SEG_TO_LIN(*plParam);
121                 LPCREATESTRUCT16   lpcs16 = PTR_SEG_TO_LIN(lpcbtcw16->lpcs);
122                 LPCBT_CREATEWNDA lpcbtcw32 = HeapAlloc( GetProcessHeap(), 0,
123                                                           sizeof(*lpcbtcw32) );
124                 lpcbtcw32->lpcs = HeapAlloc( GetProcessHeap(), 0,
125                                              sizeof(*lpcbtcw32->lpcs) );
126
127                 STRUCT32_CREATESTRUCT16to32A( lpcs16,
128                                              (LPCREATESTRUCTA)lpcbtcw32->lpcs );
129
130                 if (HIWORD(lpcs16->lpszName))
131                     lpcbtcw32->lpcs->lpszName = 
132                         (bA) ? PTR_SEG_TO_LIN(lpcs16->lpszName)
133                              : HEAP_strdupAtoW( GetProcessHeap(), 0,
134                                                 PTR_SEG_TO_LIN(lpcs16->lpszName) );
135                 else
136                     lpcbtcw32->lpcs->lpszName = (LPCSTR)lpcs16->lpszName;
137
138                 if (HIWORD(lpcs16->lpszClass))
139                     lpcbtcw32->lpcs->lpszClass =
140                         (bA) ? PTR_SEG_TO_LIN(lpcs16->lpszClass)
141                              : HEAP_strdupAtoW( GetProcessHeap(), 0,
142                                                 PTR_SEG_TO_LIN(lpcs16->lpszClass) );
143                 else
144                     lpcbtcw32->lpcs->lpszClass = (LPCSTR)lpcs16->lpszClass;
145
146                 lpcbtcw32->hwndInsertAfter = lpcbtcw16->hwndInsertAfter;
147
148                 *plParam = (LPARAM)lpcbtcw32;
149                 break;
150             } 
151             case HCBT_ACTIVATE:
152             {
153                 LPCBTACTIVATESTRUCT16 lpcas16 = PTR_SEG_TO_LIN(*plParam);
154                 LPCBTACTIVATESTRUCT lpcas32 = HeapAlloc( GetProcessHeap(), 0,
155                                                            sizeof(*lpcas32) );
156                 lpcas32->fMouse = lpcas16->fMouse;
157                 lpcas32->hWndActive = lpcas16->hWndActive;
158                 *plParam = (LPARAM)lpcas32;
159                 break;
160             }
161             case HCBT_CLICKSKIPPED:
162             {
163                 LPMOUSEHOOKSTRUCT16 lpms16 = PTR_SEG_TO_LIN(*plParam);
164                 LPMOUSEHOOKSTRUCT lpms32 = HeapAlloc( GetProcessHeap(), 0,
165                                                         sizeof(*lpms32) );
166
167                 CONV_POINT16TO32( &lpms16->pt, &lpms32->pt );
168
169                 /* wHitTestCode may be negative, so convince compiler to do
170                    correct sign extension. Yay. :| */
171                 lpms32->wHitTestCode = (INT)((INT16)lpms16->wHitTestCode);
172
173                 lpms32->dwExtraInfo = lpms16->dwExtraInfo;
174                 lpms32->hwnd = lpms16->hwnd;
175                 *plParam = (LPARAM)lpms32;
176                 break;
177             }
178             case HCBT_MOVESIZE:
179             {
180                 LPRECT16 lprect16 = PTR_SEG_TO_LIN(*plParam);
181                 LPRECT lprect32 = HeapAlloc( GetProcessHeap(), 0,
182                                                sizeof(*lprect32) );
183
184                 CONV_RECT16TO32( lprect16, lprect32 );
185                 *plParam = (LPARAM)lprect32;
186                 break;
187             }
188           } 
189           break;
190
191         case WH_MOUSE:
192         {
193             LPMOUSEHOOKSTRUCT16 lpms16 = PTR_SEG_TO_LIN(*plParam);
194             LPMOUSEHOOKSTRUCT lpms32 = HeapAlloc( GetProcessHeap(), 0,
195                                                     sizeof(*lpms32) );
196
197             CONV_POINT16TO32( &lpms16->pt, &lpms32->pt );
198
199             /* wHitTestCode may be negative, so convince compiler to do
200                correct sign extension. Yay. :| */
201             lpms32->wHitTestCode = (INT)((INT16)lpms16->wHitTestCode);
202             lpms32->dwExtraInfo = lpms16->dwExtraInfo;
203             lpms32->hwnd = lpms16->hwnd;
204             *plParam = (LPARAM)lpms32;
205             break;
206         } 
207
208         case WH_DEBUG:
209         {
210             LPDEBUGHOOKINFO16 lpdh16 = PTR_SEG_TO_LIN(*plParam);
211             LPDEBUGHOOKINFO lpdh32 = HeapAlloc( GetProcessHeap(), 0,
212                                                   sizeof(*lpdh32) );
213
214             lpdh32->idThread = 0;               /* FIXME */
215             lpdh32->idThreadInstaller = 0;      /* FIXME */
216             lpdh32->lParam = lpdh16->lParam;    /* FIXME Check for sign ext */
217             lpdh32->wParam = lpdh16->wParam;
218             lpdh32->code = lpdh16->code;
219           
220             /* do sign extension if it was WH_MSGFILTER */
221             if (*pwParam == 0xffff) *pwParam = WH_MSGFILTER;
222
223             *plParam = (LPARAM)lpdh32;
224             break;
225         }
226
227         case WH_SHELL:
228         case WH_KEYBOARD:
229             break;
230
231         case WH_HARDWARE: 
232         case WH_FOREGROUNDIDLE: 
233         case WH_CALLWNDPROCRET:
234             FIXME("\t[%i] 16to32 translation unimplemented\n", id);
235     }
236 }
237
238
239 /***********************************************************************
240  *           HOOK_Map16To32A
241  */
242 static void HOOK_Map16To32A(INT id, INT code, WPARAM *pwParam,
243                             LPARAM *plParam)
244 {
245     HOOK_Map16To32Common( id, code, pwParam, plParam, TRUE );
246 }
247
248
249 /***********************************************************************
250  *           HOOK_Map16To32W
251  */
252 static void HOOK_Map16To32W(INT id, INT code, WPARAM *pwParam,
253                             LPARAM *plParam)
254 {
255     HOOK_Map16To32Common( id, code, pwParam, plParam, FALSE );
256 }
257
258
259 /***********************************************************************
260  *           HOOK_UnMap16To32Common
261  */
262 static void HOOK_UnMap16To32Common(INT id, INT code, WPARAM wParamOrig,
263                                    LPARAM lParamOrig, WPARAM wParam,
264                                    LPARAM lParam, BOOL bA)
265 {
266     switch (id)
267     {
268         case WH_MSGFILTER:
269         case WH_SYSMSGFILTER:
270         case WH_JOURNALRECORD:
271         case WH_JOURNALPLAYBACK:
272       
273             HeapFree( GetProcessHeap(), 0, (LPVOID)lParam );
274             break;
275
276         case WH_CALLWNDPROC:
277         {
278             LPCWPSTRUCT   lpcwp32 = (LPCWPSTRUCT)lParam;
279             if (bA) WINPROC_UnmapMsg16To32A( lpcwp32->hwnd,lpcwp32->message, lpcwp32->wParam,
280                                              lpcwp32->lParam, 0 );
281             else WINPROC_UnmapMsg16To32W( lpcwp32->hwnd,lpcwp32->message, lpcwp32->wParam,
282                                           lpcwp32->lParam, 0 );
283             HeapFree( GetProcessHeap(), 0, lpcwp32 );
284             break;
285         }
286
287         case WH_GETMESSAGE:
288         {
289             LPMSG16 lpmsg16 = PTR_SEG_TO_LIN(lParamOrig);
290             STRUCT32_MSG32to16( (LPMSG)lParam, lpmsg16 );
291             HeapFree( GetProcessHeap(), 0, (LPVOID)lParam );
292             break;
293         }
294
295         case WH_MOUSE:
296         case WH_DEBUG:
297
298             HeapFree( GetProcessHeap(), 0, (LPVOID)lParam );
299             break;
300
301         case WH_CBT:
302             switch (code)
303             {
304               case HCBT_CREATEWND:
305               {
306                 LPCBT_CREATEWNDA lpcbtcw32 = (LPCBT_CREATEWNDA)lParam;
307                 LPCBT_CREATEWND16  lpcbtcw16 = PTR_SEG_TO_LIN(lParamOrig);
308
309                 if( !bA )
310                 {
311                    if (HIWORD(lpcbtcw32->lpcs->lpszName))
312                        HeapFree( GetProcessHeap(), 0, (LPWSTR)lpcbtcw32->lpcs->lpszName );
313                    if (HIWORD(lpcbtcw32->lpcs->lpszClass))
314                        HeapFree( GetProcessHeap(), 0, (LPWSTR)lpcbtcw32->lpcs->lpszClass );
315                 }
316
317                 lpcbtcw16->hwndInsertAfter = lpcbtcw32->hwndInsertAfter;
318
319                 HeapFree( GetProcessHeap(), 0, lpcbtcw32->lpcs );
320               } /* fall through */
321
322               case HCBT_ACTIVATE:
323               case HCBT_CLICKSKIPPED:
324               case HCBT_MOVESIZE:
325
326                 HeapFree( GetProcessHeap(), 0, (LPVOID)lParam);
327                 break;
328             }
329             break;
330
331         case WH_SHELL:
332         case WH_KEYBOARD:
333             break;
334
335         case WH_HARDWARE:
336         case WH_FOREGROUNDIDLE:
337         case WH_CALLWNDPROCRET:
338             FIXME("\t[%i] skipping unmap\n", id);
339             break;
340     }
341 }
342
343
344 /***********************************************************************
345  *           HOOK_UnMap16To32A
346  */
347 static void HOOK_UnMap16To32A(INT id, INT code, WPARAM wParamOrig,
348                               LPARAM lParamOrig, WPARAM wParam,
349                               LPARAM lParam)
350 {
351     HOOK_UnMap16To32Common( id, code, wParamOrig, lParamOrig, wParam,
352                             lParam, TRUE );
353 }
354
355
356 /***********************************************************************
357  *           HOOK_UnMap16To32W
358  */
359 static void HOOK_UnMap16To32W(INT id, INT code, WPARAM wParamOrig,
360                               LPARAM lParamOrig, WPARAM wParam,
361                               LPARAM lParam)
362 {
363     HOOK_UnMap16To32Common( id, code, wParamOrig, lParamOrig, wParam, 
364                             lParam, FALSE );
365 }
366
367
368 /***********************************************************************
369  *           HOOK_Map32To16Common
370  */
371 static void HOOK_Map32To16Common(INT id, INT code, WPARAM *pwParam,
372                                  LPARAM *plParam, BOOL bA)
373 {
374     switch (id)
375     {
376       case WH_MSGFILTER:
377       case WH_SYSMSGFILTER:
378       case WH_GETMESSAGE:
379       case WH_JOURNALRECORD:
380       {
381           LPMSG lpmsg32 = (LPMSG)*plParam;
382           LPMSG16 lpmsg16 = SEGPTR_NEW( MSG16 );
383
384           STRUCT32_MSG32to16( lpmsg32, lpmsg16 );
385
386           *plParam = (LPARAM)SEGPTR_GET( lpmsg16 );
387           break;
388       }
389
390       case WH_JOURNALPLAYBACK:
391       {
392           LPEVENTMSG lpem32 = (LPEVENTMSG)*plParam;
393           LPEVENTMSG16 lpem16 = SEGPTR_NEW( EVENTMSG16 );
394
395           lpem16->message = lpem32->message;
396           lpem16->paramL  = lpem32->paramL;
397           lpem16->paramH  = lpem32->paramH;
398           lpem16->time    = lpem32->time;
399
400           *plParam = (LPARAM)SEGPTR_GET( lpem16 );
401           break;
402       }
403
404       case WH_CALLWNDPROC:
405       {
406           LPCWPSTRUCT   lpcwp32 = (LPCWPSTRUCT)*plParam;
407           LPCWPSTRUCT16   lpcwp16 = SEGPTR_NEW( CWPSTRUCT16 );
408
409           lpcwp16->hwnd = lpcwp32->hwnd;
410           lpcwp16->lParam = lpcwp32->lParam;
411
412           if (bA) WINPROC_MapMsg32ATo16( lpcwp32->hwnd, lpcwp32->message,
413                                          lpcwp32->wParam, &lpcwp16->message,
414                                          &lpcwp16->wParam, &lpcwp16->lParam );
415           else WINPROC_MapMsg32WTo16( lpcwp32->hwnd, lpcwp32->message,
416                                       lpcwp32->wParam, &lpcwp16->message,
417                                       &lpcwp16->wParam, &lpcwp16->lParam );
418           *plParam = (LPARAM)SEGPTR_GET( lpcwp16 );
419           break;
420       }
421
422       case WH_CBT:
423         switch (code)
424         {
425           case HCBT_ACTIVATE:
426           {
427               LPCBTACTIVATESTRUCT lpcas32 = (LPCBTACTIVATESTRUCT)*plParam;
428               LPCBTACTIVATESTRUCT16 lpcas16 =SEGPTR_NEW( CBTACTIVATESTRUCT16 );
429
430               lpcas16->fMouse     = lpcas32->fMouse;
431               lpcas16->hWndActive = lpcas32->hWndActive;
432
433               *plParam = (LPARAM)SEGPTR_GET( lpcas16 );
434               break;
435           }
436               
437           case HCBT_CLICKSKIPPED:
438           {
439               LPMOUSEHOOKSTRUCT lpms32 = (LPMOUSEHOOKSTRUCT)*plParam;
440               LPMOUSEHOOKSTRUCT16 lpms16 = SEGPTR_NEW( MOUSEHOOKSTRUCT16 );
441
442               CONV_POINT32TO16( &lpms32->pt, &lpms16->pt );
443
444               lpms16->hwnd         = lpms32->hwnd;
445               lpms16->wHitTestCode = lpms32->wHitTestCode;
446               lpms16->dwExtraInfo  = lpms32->dwExtraInfo;
447
448               *plParam = (LPARAM)SEGPTR_GET( lpms16 );
449               break;
450           }
451
452           case HCBT_MOVESIZE:
453           {
454               LPRECT lprect32 = (LPRECT)*plParam;
455               LPRECT16 lprect16 = SEGPTR_NEW( RECT16 );
456
457               CONV_RECT32TO16( lprect32, lprect16 );
458
459               *plParam = (LPARAM)SEGPTR_GET( lprect16 );
460               break;
461           }
462         }
463         break;
464
465       case WH_MOUSE:
466       {
467           LPMOUSEHOOKSTRUCT lpms32 = (LPMOUSEHOOKSTRUCT)*plParam;
468           LPMOUSEHOOKSTRUCT16 lpms16 = SEGPTR_NEW( MOUSEHOOKSTRUCT16 );
469
470           CONV_POINT32TO16( &lpms32->pt, &lpms16->pt );
471
472           lpms16->hwnd = lpms32->hwnd;
473           lpms16->wHitTestCode = lpms32->wHitTestCode;
474           lpms16->dwExtraInfo = lpms32->dwExtraInfo;
475
476           *plParam = (LPARAM)SEGPTR_GET( lpms16 );
477           break;
478       }
479
480       case WH_DEBUG:
481       {
482           LPDEBUGHOOKINFO lpdh32 = (LPDEBUGHOOKINFO)*plParam;
483           LPDEBUGHOOKINFO16 lpdh16 = SEGPTR_NEW( DEBUGHOOKINFO16 );
484
485           lpdh16->hModuleHook = 0;      /* FIXME */
486           lpdh16->reserved    = 0;
487           lpdh16->lParam      = lpdh32->lParam;
488           lpdh16->wParam      = lpdh32->wParam;
489           lpdh16->code        = lpdh32->code;
490           
491           *plParam = (LPARAM)SEGPTR_GET( lpdh16 );
492           break;
493       }
494
495       case WH_SHELL:
496       case WH_KEYBOARD:
497         break;
498
499       case WH_HARDWARE:
500       case WH_FOREGROUNDIDLE:
501       case WH_CALLWNDPROCRET:
502         FIXME("\t[%i] 32to16 translation unimplemented\n", id);
503     }
504 }
505
506
507 /***********************************************************************
508  *           HOOK_Map32ATo16
509  */
510 static void HOOK_Map32ATo16(INT id, INT code, WPARAM *pwParam,
511                             LPARAM *plParam)
512 {
513     if (id == WH_CBT && code == HCBT_CREATEWND)
514     {
515         LPCBT_CREATEWNDA lpcbtcw32 = (LPCBT_CREATEWNDA)*plParam;
516         LPCBT_CREATEWND16 lpcbtcw16 = SEGPTR_NEW( CBT_CREATEWND16 );
517         LPCREATESTRUCT16 lpcs16 = SEGPTR_NEW( CREATESTRUCT16 );
518
519         lpcbtcw16->lpcs = (LPCREATESTRUCT16)SEGPTR_GET( lpcs16 );
520         STRUCT32_CREATESTRUCT32Ato16( lpcbtcw32->lpcs, lpcs16 );
521
522         if (HIWORD(lpcbtcw32->lpcs->lpszName))
523           lpcs16->lpszName =
524             SEGPTR_GET( SEGPTR_STRDUP( lpcbtcw32->lpcs->lpszName ) );
525         else
526           lpcs16->lpszName = (SEGPTR)lpcbtcw32->lpcs->lpszName;
527
528         if (HIWORD(lpcbtcw32->lpcs->lpszClass))
529           lpcs16->lpszClass =
530             SEGPTR_GET( SEGPTR_STRDUP( lpcbtcw32->lpcs->lpszClass ) );
531         else
532           lpcs16->lpszClass = (SEGPTR)lpcbtcw32->lpcs->lpszClass;
533
534         lpcbtcw16->hwndInsertAfter = lpcbtcw32->hwndInsertAfter;
535
536         *plParam = (LPARAM)SEGPTR_GET( lpcbtcw16 );
537     }
538     else HOOK_Map32To16Common(id, code, pwParam, plParam, TRUE);
539 }
540
541
542 /***********************************************************************
543  *           HOOK_Map32WTo16
544  */
545 static void HOOK_Map32WTo16(INT id, INT code, WPARAM *pwParam,
546                             LPARAM *plParam)
547 {
548     if (id == WH_CBT && code == HCBT_CREATEWND)
549     {
550         LPSTR name, cls;
551         LPCBT_CREATEWNDW lpcbtcw32 = (LPCBT_CREATEWNDW)*plParam;
552         LPCBT_CREATEWND16 lpcbtcw16 = SEGPTR_NEW( CBT_CREATEWND16 );
553         LPCREATESTRUCT16 lpcs16 = SEGPTR_NEW( CREATESTRUCT16 );
554
555         lpcbtcw16->lpcs = (LPCREATESTRUCT16)SEGPTR_GET( lpcs16 );
556         STRUCT32_CREATESTRUCT32Ato16( (LPCREATESTRUCTA)lpcbtcw32->lpcs,
557                                       lpcs16 );
558
559         name = SEGPTR_STRDUP_WtoA( lpcbtcw32->lpcs->lpszName );
560         cls  = SEGPTR_STRDUP_WtoA( lpcbtcw32->lpcs->lpszClass );
561         lpcs16->lpszName  = SEGPTR_GET( name );
562         lpcs16->lpszClass = SEGPTR_GET( cls );
563         lpcbtcw16->hwndInsertAfter = lpcbtcw32->hwndInsertAfter;
564
565         *plParam = (LPARAM)SEGPTR_GET( lpcbtcw16 );
566     }
567     else HOOK_Map32To16Common(id, code, pwParam, plParam, FALSE);
568 }
569
570
571 /***********************************************************************
572  *           HOOK_UnMap32To16Common
573  */
574 static void HOOK_UnMap32To16Common(INT id, INT code, WPARAM wParamOrig,
575                                    LPARAM lParamOrig, WPARAM wParam,
576                                    LPARAM lParam, BOOL bA)
577 {
578     switch (id)
579     {
580       case WH_MSGFILTER:
581       case WH_SYSMSGFILTER:
582       case WH_JOURNALRECORD:
583       case WH_JOURNALPLAYBACK:
584       case WH_MOUSE:
585       case WH_DEBUG:
586         SEGPTR_FREE( PTR_SEG_TO_LIN(lParam) );
587         break;
588
589       case WH_CALLWNDPROC:
590       {
591           LPCWPSTRUCT16   lpcwp16 = (LPCWPSTRUCT16)PTR_SEG_TO_LIN(lParam);
592           LPCWPSTRUCT   lpcwp32 = (LPCWPSTRUCT)lParamOrig;
593           MSGPARAM16      mp16;
594
595           mp16.wParam = lpcwp16->wParam;
596           mp16.lParam = lpcwp16->lParam;
597           mp16.lResult = 0;
598
599           if (bA) WINPROC_UnmapMsg32ATo16( lpcwp32->hwnd,lpcwp32->message, lpcwp32->wParam,
600                                            lpcwp32->lParam, &mp16 );
601           else WINPROC_UnmapMsg32WTo16( lpcwp32->hwnd,lpcwp32->message, lpcwp32->wParam,
602                                         lpcwp32->lParam, &mp16 );
603           SEGPTR_FREE( PTR_SEG_TO_LIN(lParam) );
604           break;
605       }
606
607       case WH_GETMESSAGE:
608       {
609           LPMSG lpmsg32 = (LPMSG)lParamOrig;
610
611           STRUCT32_MSG16to32( (LPMSG16)PTR_SEG_TO_LIN(lParam), lpmsg32 );
612           SEGPTR_FREE( PTR_SEG_TO_LIN(lParam) );
613           break;
614       }
615
616       case WH_CBT:
617         switch (code)
618         {
619           case HCBT_CREATEWND:
620           {
621                LPCBT_CREATEWNDA lpcbtcw32 = (LPCBT_CREATEWNDA)(lParamOrig);
622                LPCBT_CREATEWND16 lpcbtcw16 = PTR_SEG_TO_LIN(lParam);
623                LPCREATESTRUCT16  lpcs16 = PTR_SEG_TO_LIN(lpcbtcw16->lpcs);
624
625                if (HIWORD(lpcs16->lpszName))
626                    SEGPTR_FREE( PTR_SEG_TO_LIN(lpcs16->lpszName) );
627
628                if (HIWORD(lpcs16->lpszClass))
629                    SEGPTR_FREE( PTR_SEG_TO_LIN(lpcs16->lpszClass) );
630
631                lpcbtcw32->hwndInsertAfter = lpcbtcw16->hwndInsertAfter;
632
633                SEGPTR_FREE( lpcs16 );
634           } /* fall through */
635
636           case HCBT_ACTIVATE:
637           case HCBT_CLICKSKIPPED:
638           case HCBT_MOVESIZE:
639
640                SEGPTR_FREE( PTR_SEG_TO_LIN(lParam) );
641                break;
642         }
643         break;
644
645       case WH_SHELL:
646       case WH_KEYBOARD:
647         break;
648
649       case WH_HARDWARE:
650       case WH_FOREGROUNDIDLE:
651       case WH_CALLWNDPROCRET:
652         FIXME("\t[%i] skipping unmap\n", id);
653     }
654 }
655
656
657 /***********************************************************************
658  *           HOOK_UnMap32ATo16
659  */
660 static void HOOK_UnMap32ATo16(INT id, INT code, WPARAM wParamOrig,
661                               LPARAM lParamOrig, WPARAM wParam,
662                               LPARAM lParam)
663 {
664     HOOK_UnMap32To16Common( id, code, wParamOrig, lParamOrig, wParam,
665                             lParam, TRUE );
666 }
667
668
669 /***********************************************************************
670  *           HOOK_UnMap32WTo16
671  */
672 static void HOOK_UnMap32WTo16(INT id, INT code, WPARAM wParamOrig,
673                               LPARAM lParamOrig, WPARAM wParam,
674                               LPARAM lParam)
675 {
676     HOOK_UnMap32To16Common( id, code, wParamOrig, lParamOrig, wParam,
677                             lParam, FALSE );
678 }
679
680
681 /***********************************************************************
682  *           HOOK_Map32ATo32W
683  */
684 static void HOOK_Map32ATo32W(INT id, INT code, WPARAM *pwParam,
685                              LPARAM *plParam)
686 {
687     if (id == WH_CBT && code == HCBT_CREATEWND)
688     {
689         LPCBT_CREATEWNDA lpcbtcwA = (LPCBT_CREATEWNDA)*plParam;
690         LPCBT_CREATEWNDW lpcbtcwW = HeapAlloc( GetProcessHeap(), 0,
691                                                  sizeof(*lpcbtcwW) );
692         lpcbtcwW->lpcs = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpcbtcwW->lpcs) );
693
694         lpcbtcwW->hwndInsertAfter = lpcbtcwA->hwndInsertAfter;
695         *lpcbtcwW->lpcs = *(LPCREATESTRUCTW)lpcbtcwA->lpcs;
696
697         if (HIWORD(lpcbtcwA->lpcs->lpszName))
698         {
699             lpcbtcwW->lpcs->lpszName = HEAP_strdupAtoW( GetProcessHeap(), 0,
700                                                     lpcbtcwA->lpcs->lpszName );
701         }
702         else
703           lpcbtcwW->lpcs->lpszName = (LPWSTR)lpcbtcwA->lpcs->lpszName;
704
705         if (HIWORD(lpcbtcwA->lpcs->lpszClass))
706         {
707             lpcbtcwW->lpcs->lpszClass = HEAP_strdupAtoW( GetProcessHeap(), 0,
708                                                    lpcbtcwA->lpcs->lpszClass );
709         }
710         else
711           lpcbtcwW->lpcs->lpszClass = (LPCWSTR)lpcbtcwA->lpcs->lpszClass;
712         *plParam = (LPARAM)lpcbtcwW;
713     }
714     return;
715 }
716
717
718 /***********************************************************************
719  *           HOOK_UnMap32ATo32W
720  */
721 static void HOOK_UnMap32ATo32W(INT id, INT code, WPARAM wParamOrig,
722                                LPARAM lParamOrig, WPARAM wParam,
723                                LPARAM lParam)
724 {
725     if (id == WH_CBT && code == HCBT_CREATEWND)
726     {
727         LPCBT_CREATEWNDW lpcbtcwW = (LPCBT_CREATEWNDW)lParam;
728         if (HIWORD(lpcbtcwW->lpcs->lpszName))
729             HeapFree( GetProcessHeap(), 0, (LPWSTR)lpcbtcwW->lpcs->lpszName );
730         if (HIWORD(lpcbtcwW->lpcs->lpszClass))
731             HeapFree( GetProcessHeap(), 0, (LPWSTR)lpcbtcwW->lpcs->lpszClass );
732         HeapFree( GetProcessHeap(), 0, lpcbtcwW->lpcs );
733         HeapFree( GetProcessHeap(), 0, lpcbtcwW );
734     }
735     return;
736 }
737
738
739 /***********************************************************************
740  *           HOOK_Map32WTo32A
741  */
742 static void HOOK_Map32WTo32A(INT id, INT code, WPARAM *pwParam,
743                              LPARAM *plParam)
744 {
745     if (id == WH_CBT && code == HCBT_CREATEWND)
746     {
747         LPCBT_CREATEWNDW lpcbtcwW = (LPCBT_CREATEWNDW)*plParam;
748         LPCBT_CREATEWNDA lpcbtcwA = HeapAlloc( GetProcessHeap(), 0,
749                                                  sizeof(*lpcbtcwA) );
750         lpcbtcwA->lpcs = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpcbtcwA->lpcs) );
751
752         lpcbtcwA->hwndInsertAfter = lpcbtcwW->hwndInsertAfter;
753         *lpcbtcwA->lpcs = *(LPCREATESTRUCTA)lpcbtcwW->lpcs;
754
755         if (HIWORD(lpcbtcwW->lpcs->lpszName))
756           lpcbtcwA->lpcs->lpszName = HEAP_strdupWtoA( GetProcessHeap(), 0,
757                                                     lpcbtcwW->lpcs->lpszName );
758         else
759           lpcbtcwA->lpcs->lpszName = (LPSTR)lpcbtcwW->lpcs->lpszName;
760
761         if (HIWORD(lpcbtcwW->lpcs->lpszClass))
762           lpcbtcwA->lpcs->lpszClass = HEAP_strdupWtoA( GetProcessHeap(), 0,
763                                                    lpcbtcwW->lpcs->lpszClass );
764         else
765           lpcbtcwA->lpcs->lpszClass = (LPSTR)lpcbtcwW->lpcs->lpszClass;
766         *plParam = (LPARAM)lpcbtcwA;
767     }
768     return;
769 }
770
771
772 /***********************************************************************
773  *           HOOK_UnMap32WTo32A
774  */
775 static void HOOK_UnMap32WTo32A(INT id, INT code, WPARAM wParamOrig,
776                                LPARAM lParamOrig, WPARAM wParam,
777                                LPARAM lParam)
778 {
779     if (id == WH_CBT && code == HCBT_CREATEWND)
780     {
781         LPCBT_CREATEWNDA lpcbtcwA = (LPCBT_CREATEWNDA)lParam;
782         if (HIWORD(lpcbtcwA->lpcs->lpszName))
783             HeapFree( GetProcessHeap(), 0, (LPSTR)lpcbtcwA->lpcs->lpszName );
784         if (HIWORD(lpcbtcwA->lpcs->lpszClass))
785             HeapFree( GetProcessHeap(), 0, (LPSTR)lpcbtcwA->lpcs->lpszClass );
786         HeapFree( GetProcessHeap(), 0, lpcbtcwA->lpcs );
787         HeapFree( GetProcessHeap(), 0, lpcbtcwA );
788     }
789     return;
790 }
791
792
793 /***********************************************************************
794  *           Map Function Tables
795  */
796 static const HOOK_MapFunc HOOK_MapFuncs[3][3] = 
797 {
798     { NULL,            HOOK_Map16To32A,  HOOK_Map16To32W },
799     { HOOK_Map32ATo16, NULL,             HOOK_Map32ATo32W },
800     { HOOK_Map32WTo16, HOOK_Map32WTo32A, NULL }
801 };
802
803 static const HOOK_UnMapFunc HOOK_UnMapFuncs[3][3] = 
804 {
805     { NULL,              HOOK_UnMap16To32A,  HOOK_UnMap16To32W },
806     { HOOK_UnMap32ATo16, NULL,               HOOK_UnMap32ATo32W },
807     { HOOK_UnMap32WTo16, HOOK_UnMap32WTo32A, NULL }
808 };
809
810
811 /***********************************************************************
812  *           Internal Functions
813  */
814
815 /***********************************************************************
816  *           HOOK_GetNextHook
817  *
818  * Get the next hook of a given hook.
819  */
820 static HANDLE16 HOOK_GetNextHook( HANDLE16 hook )
821 {
822     HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR( hook );
823
824     if (!data || !hook) return 0;
825     if (data->next) return data->next;
826     if (!data->ownerQueue) return 0;  /* Already system hook */
827
828     /* Now start enumerating the system hooks */
829     return HOOK_systemHooks[data->id - WH_MINHOOK];
830 }
831
832
833 /***********************************************************************
834  *           HOOK_GetHook
835  *
836  * Get the first hook for a given type.
837  */
838 static HANDLE16 HOOK_GetHook( INT16 id, HQUEUE16 hQueue )
839 {
840     MESSAGEQUEUE *queue;
841     HANDLE16 hook = 0;
842
843     if ((queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue )) != NULL)
844         hook = queue->hooks[id - WH_MINHOOK];
845     if (!hook) hook = HOOK_systemHooks[id - WH_MINHOOK];
846
847     QUEUE_Unlock( queue );
848     return hook;
849 }
850
851
852 /***********************************************************************
853  *           HOOK_SetHook
854  *
855  * Install a given hook.
856  */
857 /* ### start build ### */
858 extern LONG CALLBACK HOOK_CallTo16_long_wwl(FARPROC16,WORD,WORD,LONG);
859 /* ### stop build ### */
860 static HHOOK HOOK_SetHook( INT16 id, LPVOID proc, INT type,
861                            HMODULE16 hModule, DWORD dwThreadId )
862 {
863     HOOKDATA *data;
864     HANDLE16 handle;
865     HQUEUE16 hQueue = 0;
866
867     if ((id < WH_MINHOOK) || (id > WH_MAXHOOK)) return 0;
868
869     TRACE("Setting hook %d: %08x %04x %08lx\n",
870                   id, (UINT)proc, hModule, dwThreadId );
871
872     /* Create task queue if none present */
873     GetFastQueue16();
874
875     if (id == WH_JOURNALPLAYBACK) EnableHardwareInput16(FALSE);
876
877     if (dwThreadId)  /* Task-specific hook */
878     {
879         if ((id == WH_JOURNALRECORD) || (id == WH_JOURNALPLAYBACK) ||
880             (id == WH_SYSMSGFILTER)) return 0;  /* System-only hooks */
881         if (!(hQueue = GetThreadQueue16( dwThreadId )))
882             return 0;
883     }
884
885     /* Create the hook structure */
886
887     if (!(handle = USER_HEAP_ALLOC( sizeof(HOOKDATA) ))) return 0;
888     data = (HOOKDATA *) USER_HEAP_LIN_ADDR( handle );
889     data->proc        = proc;
890     data->id          = id;
891     data->ownerQueue  = hQueue;
892     data->ownerModule = hModule;
893     data->flags       = type;
894
895     /* Create CallTo16 thunk for 16-bit hooks */
896
897     if ( (data->flags & HOOK_MAPTYPE) == HOOK_WIN16 )
898         data->thunk = (HOOKPROC)THUNK_Alloc( (FARPROC16)data->proc, 
899                                              (RELAY)HOOK_CallTo16_long_wwl );
900     else
901         data->thunk = data->proc;
902
903     if ( !data->thunk && data->proc )
904     {
905         USER_HEAP_FREE( handle );
906         return 0;
907     }
908
909     /* Insert it in the correct linked list */
910
911     if (hQueue)
912     {
913         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
914         data->next = queue->hooks[id - WH_MINHOOK];
915         queue->hooks[id - WH_MINHOOK] = handle;
916         QUEUE_Unlock( queue );
917     }
918     else
919     {
920         data->next = HOOK_systemHooks[id - WH_MINHOOK];
921         HOOK_systemHooks[id - WH_MINHOOK] = handle;
922     }
923     TRACE("Setting hook %d: ret=%04x [next=%04x]\n", 
924                            id, handle, data->next );
925
926     return (HHOOK)( handle? MAKELONG( handle, HOOK_MAGIC ) : 0 );
927 }
928
929
930 /***********************************************************************
931  *           HOOK_RemoveHook
932  *
933  * Remove a hook from the list.
934  */
935 static BOOL HOOK_RemoveHook( HANDLE16 hook )
936 {
937     HOOKDATA *data;
938     HANDLE16 *prevHook;
939
940     TRACE("Removing hook %04x\n", hook );
941
942     if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return FALSE;
943     if (data->flags & HOOK_INUSE)
944     {
945         /* Mark it for deletion later on */
946         WARN("Hook still running, deletion delayed\n" );
947         data->proc = (HOOKPROC)0;
948         return TRUE;
949     }
950
951     if (data->id == WH_JOURNALPLAYBACK) EnableHardwareInput16(TRUE);
952      
953     /* Remove it from the linked list */
954
955     if (data->ownerQueue)
956     {
957         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( data->ownerQueue );
958         if (!queue) return FALSE;
959         prevHook = &queue->hooks[data->id - WH_MINHOOK];
960         QUEUE_Unlock( queue );
961     }
962     else prevHook = &HOOK_systemHooks[data->id - WH_MINHOOK];
963
964     while (*prevHook && *prevHook != hook)
965         prevHook = &((HOOKDATA *)USER_HEAP_LIN_ADDR(*prevHook))->next;
966
967     if (!*prevHook) return FALSE;
968     *prevHook = data->next;
969
970     if ( (data->flags & HOOK_MAPTYPE) == HOOK_WIN16 )
971         THUNK_Free( (FARPROC)data->thunk );
972
973     USER_HEAP_FREE( hook );
974     return TRUE;
975 }
976
977
978 /***********************************************************************
979  *           HOOK_FindValidHook
980  */
981 static HANDLE16 HOOK_FindValidHook( HANDLE16 hook )
982 {
983     HOOKDATA *data;
984
985     for (;;)
986     {
987         if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return 0;
988         if (data->proc) return hook;
989         hook = data->next;
990     }
991 }
992
993
994 /***********************************************************************
995  *           HOOK_CallHook
996  *
997  * Call a hook procedure.
998  */
999 static LRESULT HOOK_CallHook( HANDLE16 hook, INT fromtype, INT code,
1000                               WPARAM wParam, LPARAM lParam )
1001 {
1002     MESSAGEQUEUE *queue;
1003     HANDLE16 prevHook;
1004     HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
1005     LRESULT ret;
1006     int iWndsLocks;
1007
1008     WPARAM wParamOrig = wParam;
1009     LPARAM lParamOrig = lParam;
1010     HOOK_MapFunc MapFunc;
1011     HOOK_UnMapFunc UnMapFunc;
1012
1013     MapFunc = HOOK_MapFuncs[fromtype][data->flags & HOOK_MAPTYPE];
1014     UnMapFunc = HOOK_UnMapFuncs[fromtype][data->flags & HOOK_MAPTYPE];
1015
1016     if (MapFunc)
1017       MapFunc( data->id, code, &wParam, &lParam );
1018
1019     /* Now call it */
1020
1021     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1022     prevHook = queue->hCurHook;
1023     queue->hCurHook = hook;
1024     data->flags |= HOOK_INUSE;
1025
1026     TRACE("Calling hook %04x: %d %08x %08lx\n",
1027                   hook, code, wParam, lParam );
1028
1029     /* Suspend window structure locks before calling user code */
1030     iWndsLocks = WIN_SuspendWndsLock();
1031
1032     ret = data->thunk(code, wParam, lParam);
1033
1034     /* Grrr. While the hook procedure is supposed to have an LRESULT return
1035        value even in Win16, it seems that for those hook types where the 
1036        return value is interpreted as BOOL, Windows doesn't actually check
1037        the HIWORD ...  Some buggy Win16 programs, notably WINFILE, rely on
1038        that, because they neglect to clear DX ... */
1039     if (    (data->flags & HOOK_MAPTYPE) == HOOK_WIN16 
1040          && data->id != WH_JOURNALPLAYBACK )
1041         ret = LOWORD( ret );
1042
1043     WIN_RestoreWndsLock(iWndsLocks);
1044
1045     TRACE("Ret hook %04x = %08lx\n", hook, ret );
1046
1047     data->flags &= ~HOOK_INUSE;
1048     queue->hCurHook = prevHook;
1049
1050     QUEUE_Unlock( queue );
1051
1052     if (UnMapFunc)
1053       UnMapFunc( data->id, code, wParamOrig, lParamOrig, wParam, lParam );
1054
1055     if (!data->proc) HOOK_RemoveHook( hook );
1056
1057     return ret;
1058 }
1059
1060 /***********************************************************************
1061  *           Exported Functions & APIs
1062  */
1063
1064 /***********************************************************************
1065  *           HOOK_IsHooked
1066  *
1067  * Replacement for calling HOOK_GetHook from other modules.
1068  */
1069 BOOL HOOK_IsHooked( INT16 id )
1070 {
1071     /* Hmmm. Use GetThreadQueue(0) instead of GetFastQueue() here to 
1072        avoid queue being created if someone wants to merely check ... */
1073
1074     return HOOK_GetHook( id, GetThreadQueue16(0) ) != 0;
1075 }
1076
1077
1078 /***********************************************************************
1079  *           HOOK_CallHooks16
1080  *
1081  * Call a hook chain.
1082  */
1083 LRESULT HOOK_CallHooks16( INT16 id, INT16 code, WPARAM16 wParam,
1084                           LPARAM lParam )
1085 {
1086     HANDLE16 hook; 
1087
1088     if (!(hook = HOOK_GetHook( id, GetFastQueue16() ))) return 0;
1089     if (!(hook = HOOK_FindValidHook(hook))) return 0;
1090     return HOOK_CallHook( hook, HOOK_WIN16, code, wParam, lParam );
1091 }
1092
1093 /***********************************************************************
1094  *           HOOK_CallHooksA
1095  *
1096  * Call a hook chain.
1097  */
1098 LRESULT HOOK_CallHooksA( INT id, INT code, WPARAM wParam,
1099                            LPARAM lParam )
1100 {
1101     HANDLE16 hook; 
1102
1103     if (!(hook = HOOK_GetHook( id, GetFastQueue16() ))) return 0;
1104     if (!(hook = HOOK_FindValidHook(hook))) return 0;
1105     return HOOK_CallHook( hook, HOOK_WIN32A, code, wParam, lParam );
1106 }
1107
1108 /***********************************************************************
1109  *           HOOK_CallHooksW
1110  *
1111  * Call a hook chain.
1112  */
1113 LRESULT HOOK_CallHooksW( INT id, INT code, WPARAM wParam,
1114                            LPARAM lParam )
1115 {
1116     HANDLE16 hook; 
1117
1118     if (!(hook = HOOK_GetHook( id, GetFastQueue16() ))) return 0;
1119     if (!(hook = HOOK_FindValidHook(hook))) return 0;
1120     return HOOK_CallHook( hook, HOOK_WIN32W, code, wParam,
1121                           lParam );
1122 }
1123
1124
1125 /***********************************************************************
1126  *           HOOK_ResetQueueHooks
1127  */
1128 void HOOK_ResetQueueHooks( HQUEUE16 hQueue )
1129 {
1130     MESSAGEQUEUE *queue;
1131
1132     if ((queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue )) != NULL)
1133     {
1134         HOOKDATA*       data;
1135         HHOOK           hook;
1136         int             id;
1137         for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
1138         {
1139             hook = queue->hooks[id - WH_MINHOOK];
1140             while( hook )
1141             {
1142                 if( (data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook)) )
1143                 {
1144                   data->ownerQueue = hQueue;
1145                   hook = data->next;
1146                 } else break;
1147             }
1148         }
1149
1150         QUEUE_Unlock( queue );
1151     }
1152 }
1153
1154 /***********************************************************************
1155  *           HOOK_FreeModuleHooks
1156  */
1157 void HOOK_FreeModuleHooks( HMODULE16 hModule )
1158 {
1159  /* remove all system hooks registered by this module */
1160
1161   HOOKDATA*     hptr;
1162   HHOOK         hook, next;
1163   int           id;
1164
1165   for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
1166     {
1167        hook = HOOK_systemHooks[id - WH_MINHOOK];
1168        while( hook )
1169           if( (hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook)) )
1170             {
1171               next = hptr->next;
1172               if( hptr->ownerModule == hModule )
1173                 {
1174                   hptr->flags &= HOOK_MAPTYPE;
1175                   HOOK_RemoveHook(hook);
1176                 }
1177               hook = next;
1178             }
1179           else hook = 0;
1180     }
1181 }
1182
1183 /***********************************************************************
1184  *           HOOK_FreeQueueHooks
1185  */
1186 void HOOK_FreeQueueHooks( HQUEUE16 hQueue )
1187 {
1188   /* remove all hooks registered by this queue */
1189
1190   HOOKDATA*     hptr = NULL;
1191   HHOOK         hook, next;
1192   int           id;
1193
1194   for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
1195     {
1196        hook = HOOK_GetHook( id, hQueue );
1197        while( hook )
1198         {
1199           next = HOOK_GetNextHook(hook);
1200
1201           hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
1202           if( hptr && hptr->ownerQueue == hQueue )
1203             {
1204               hptr->flags &= HOOK_MAPTYPE;
1205               HOOK_RemoveHook(hook);
1206             }
1207           hook = next;
1208         }
1209     }
1210 }
1211
1212
1213 /***********************************************************************
1214  *           SetWindowsHook16   (USER.121)
1215  */
1216 FARPROC16 WINAPI SetWindowsHook16( INT16 id, HOOKPROC16 proc )
1217 {
1218     HINSTANCE16 hInst = FarGetOwner16( HIWORD(proc) );
1219
1220     /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
1221     HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
1222
1223     return (FARPROC16)SetWindowsHookEx16( id, proc, hInst, hTask );
1224 }
1225
1226 /***********************************************************************
1227  *           SetWindowsHookA   (USER32.525)
1228  */
1229 HHOOK WINAPI SetWindowsHookA( INT id, HOOKPROC proc )
1230 {
1231     return SetWindowsHookExA( id, proc, 0, GetCurrentThreadId() );
1232 }
1233
1234 /***********************************************************************
1235  *           SetWindowsHookW   (USER32.528)
1236  */
1237 HHOOK WINAPI SetWindowsHookW( INT id, HOOKPROC proc )
1238 {
1239     return SetWindowsHookExW( id, proc, 0, GetCurrentThreadId() );
1240 }
1241
1242
1243 /***********************************************************************
1244  *           SetWindowsHookEx16   (USER.291)
1245  */
1246 HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst,
1247                                  HTASK16 hTask )
1248 {
1249     if (id == WH_DEBUG)
1250     {
1251         FIXME("WH_DEBUG is broken in 16-bit Windows.\n");
1252         return 0;
1253     }
1254     return HOOK_SetHook( id, proc, HOOK_WIN16, GetExePtr(hInst), (DWORD)hTask );
1255 }
1256
1257 /***********************************************************************
1258  *           SetWindowsHookExA   (USER32.526)
1259  */
1260 HHOOK WINAPI SetWindowsHookExA( INT id, HOOKPROC proc, HINSTANCE hInst,
1261                                   DWORD dwThreadId )
1262 {
1263     return HOOK_SetHook( id, proc, HOOK_WIN32A, MapHModuleLS(hInst), dwThreadId );
1264 }
1265
1266 /***********************************************************************
1267  *           SetWindowsHookExW   (USER32.527)
1268  */
1269 HHOOK WINAPI SetWindowsHookExW( INT id, HOOKPROC proc, HINSTANCE hInst,
1270                                   DWORD dwThreadId )
1271 {
1272     return HOOK_SetHook( id, proc, HOOK_WIN32W, MapHModuleLS(hInst), dwThreadId );
1273 }
1274
1275
1276 /***********************************************************************
1277  *           UnhookWindowsHook16   (USER.234)
1278  */
1279 BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
1280 {
1281     return UnhookWindowsHook( id, (HOOKPROC)proc );
1282 }
1283
1284 /***********************************************************************
1285  *           UnhookWindowsHook   (USER32.557)
1286  */
1287 BOOL WINAPI UnhookWindowsHook( INT id, HOOKPROC proc )
1288 {
1289     HANDLE16 hook = HOOK_GetHook( id, GetFastQueue16() );
1290
1291     TRACE("%d %08lx\n", id, (DWORD)proc );
1292
1293     while (hook)
1294     {
1295         HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
1296         if (data->proc == proc) break;
1297         hook = HOOK_GetNextHook( hook );
1298     }
1299     if (!hook) return FALSE;
1300     return HOOK_RemoveHook( hook );
1301 }
1302
1303
1304 /***********************************************************************
1305  *           UnhookWindowsHookEx16   (USER.292)
1306  */
1307 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
1308 {
1309     return UnhookWindowsHookEx( hhook );
1310 }
1311
1312 /***********************************************************************
1313  *           UnhookWindowsHookEx   (USER32.558)
1314  */
1315 BOOL WINAPI UnhookWindowsHookEx( HHOOK hhook )
1316 {
1317     if (HIWORD(hhook) != HOOK_MAGIC) return FALSE;  /* Not a new format hook */
1318     return HOOK_RemoveHook( LOWORD(hhook) );
1319 }
1320
1321
1322 /***********************************************************************
1323  *           CallNextHookEx16     (USER.293)
1324  *
1325  * I wouldn't have separated this into 16 and 32 bit versions, but I
1326  * need a way to figure out if I need to do a mapping or not.
1327  */
1328 LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wParam,
1329                                  LPARAM lParam )
1330 {
1331     HANDLE16 next;
1332
1333     if (HIWORD(hhook) != HOOK_MAGIC) return 0;  /* Not a new format hook */
1334     if (!(next = HOOK_GetNextHook( LOWORD(hhook) ))) return 0;
1335
1336     return HOOK_CallHook( next, HOOK_WIN16, code, wParam, lParam );
1337 }
1338
1339
1340 /***********************************************************************
1341  *           CallNextHookEx    (USER32.17)
1342  *
1343  * There aren't ANSI and UNICODE versions of this.
1344  */
1345 LRESULT WINAPI CallNextHookEx( HHOOK hhook, INT code, WPARAM wParam,
1346                                  LPARAM lParam )
1347 {
1348     HANDLE16 next;
1349     INT fromtype;       /* figure out Ansi/Unicode */
1350     HOOKDATA *oldhook;
1351
1352     if (HIWORD(hhook) != HOOK_MAGIC) return 0;  /* Not a new format hook */
1353     if (!(next = HOOK_GetNextHook( LOWORD(hhook) ))) return 0;
1354
1355     oldhook = (HOOKDATA *)USER_HEAP_LIN_ADDR( LOWORD(hhook) );
1356     fromtype = oldhook->flags & HOOK_MAPTYPE;
1357
1358     if (fromtype == HOOK_WIN16)
1359       ERR("called from 16bit hook!\n");
1360
1361     return HOOK_CallHook( next, fromtype, code, wParam, lParam );
1362 }
1363
1364
1365 /***********************************************************************
1366  *           DefHookProc16   (USER.235)
1367  */
1368 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wParam, LPARAM lParam,
1369                               HHOOK *hhook )
1370 {
1371     /* Note: the *hhook parameter is never used, since we rely on the
1372      * current hook value from the task queue to find the next hook. */
1373     MESSAGEQUEUE *queue;
1374     LRESULT ret;
1375
1376     if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1377     ret = CallNextHookEx16( queue->hCurHook, code, wParam, lParam );
1378     QUEUE_Unlock( queue );
1379     return ret;
1380 }
1381
1382
1383 /***********************************************************************
1384  *           CallMsgFilter16   (USER.123)
1385  */
1386 BOOL16 WINAPI CallMsgFilter16( SEGPTR msg, INT16 code )
1387 {
1388     if (GetSysModalWindow16()) return FALSE;
1389     if (HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) return TRUE;
1390     return HOOK_CallHooks16( WH_MSGFILTER, code, 0, (LPARAM)msg );
1391 }
1392
1393
1394 /***********************************************************************
1395  *           CallMsgFilter32   (USER.823)
1396  */
1397 BOOL16 WINAPI CallMsgFilter32_16( SEGPTR msg16_32, INT16 code, BOOL16 wHaveParamHigh )
1398 {
1399     MSG32_16 *lpmsg16_32 = (MSG32_16 *)PTR_SEG_TO_LIN(msg16_32);
1400
1401     if (wHaveParamHigh == FALSE)
1402     {
1403         lpmsg16_32->wParamHigh = 0;
1404         /* WARNING: msg16_32->msg has to be the first variable in the struct */ 
1405         return CallMsgFilter16(msg16_32, code);
1406     }
1407     else
1408     {
1409         MSG msg32;
1410         BOOL16 ret;
1411
1412         msg32.hwnd              = lpmsg16_32->msg.hwnd;
1413         msg32.message   = lpmsg16_32->msg.message;
1414         msg32.wParam    =
1415                      MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh);
1416         msg32.lParam    = lpmsg16_32->msg.lParam;
1417         msg32.time              = lpmsg16_32->msg.time;
1418         msg32.pt.x              = (INT)lpmsg16_32->msg.pt.x;
1419         msg32.pt.y      = (INT)lpmsg16_32->msg.pt.y;
1420         
1421         ret = (BOOL16)CallMsgFilterA(&msg32, (INT)code);
1422
1423         lpmsg16_32->msg.hwnd    = msg32.hwnd;
1424         lpmsg16_32->msg.message = msg32.message;
1425         lpmsg16_32->msg.wParam  = LOWORD(msg32.wParam);
1426         lpmsg16_32->msg.lParam  = msg32.lParam;
1427         lpmsg16_32->msg.time    = msg32.time;
1428         lpmsg16_32->msg.pt.x    = (INT16)msg32.pt.x;
1429         lpmsg16_32->msg.pt.y    = (INT16)msg32.pt.y;
1430         lpmsg16_32->wParamHigh  = HIWORD(msg32.wParam);
1431
1432         return ret;
1433     }
1434 }
1435
1436
1437 /***********************************************************************
1438  *           CallMsgFilterA   (USER32.15)
1439  */
1440 /*
1441  * FIXME: There are ANSI and UNICODE versions of this, plus an unspecified
1442  * version, plus USER (the 16bit one) has a CallMsgFilter32 function.
1443  */
1444 BOOL WINAPI CallMsgFilterA( LPMSG msg, INT code )
1445 {
1446     if (GetSysModalWindow16()) return FALSE;    /* ??? */
1447     if (HOOK_CallHooksA( WH_SYSMSGFILTER, code, 0, (LPARAM)msg ))
1448       return TRUE;
1449     return HOOK_CallHooksA( WH_MSGFILTER, code, 0, (LPARAM)msg );
1450 }
1451
1452
1453 /***********************************************************************
1454  *           CallMsgFilterW   (USER32.16)
1455  */
1456 BOOL WINAPI CallMsgFilterW( LPMSG msg, INT code )
1457 {
1458     if (GetSysModalWindow16()) return FALSE;    /* ??? */
1459     if (HOOK_CallHooksW( WH_SYSMSGFILTER, code, 0, (LPARAM)msg ))
1460       return TRUE;
1461     return HOOK_CallHooksW( WH_MSGFILTER, code, 0, (LPARAM)msg );
1462 }
1463