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