- support DirectInput 8 interfaces.
[wine/multimedia.git] / windows / hook.c
blobc9ab59d418fe149657c93c2a01ebff412d740f64
1 /*
2 * Windows hook functions
4 * Copyright 1994, 1995 Alexandre Julliard
5 * 1996 Andrew Lewycky
7 * Based on investigations by Alex Korobka
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.
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.
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
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.
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "wine/winuser16.h"
36 #include "wine/winbase16.h"
37 #include "hook.h"
38 #include "win.h"
39 #include "queue.h"
40 #include "user.h"
41 #include "heap.h"
42 #include "struct32.h"
43 #include "winproc.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(hook);
48 #include "pshpack1.h"
50 /* Hook data (pointed to by a HHOOK) */
51 typedef struct
53 HANDLE16 next; /* 00 Next hook in chain */
54 HOOKPROC proc; /* 02 Hook procedure (original) */
55 INT16 id; /* 06 Hook id (WH_xxx) */
56 HQUEUE16 ownerQueue; /* 08 Owner queue (0 for system hook) */
57 HMODULE16 ownerModule; /* 0a Owner module */
58 WORD flags; /* 0c flags */
59 } HOOKDATA;
61 #include "poppack.h"
63 #define HOOK_MAGIC ((int)'H' | (int)'K' << 8) /* 'HK' */
65 /* This should probably reside in USER heap */
66 static HANDLE16 HOOK_systemHooks[WH_NB_HOOKS] = { 0, };
68 /* ### start build ### */
69 extern LONG CALLBACK HOOK_CallTo16_long_wwl(HOOKPROC16,WORD,WORD,LONG);
70 /* ### stop build ### */
73 /***********************************************************************
74 * call_hook_16
76 inline static LRESULT call_hook_16( HOOKPROC16 proc, INT id, INT code, WPARAM wparam, LPARAM lparam )
78 LRESULT ret = HOOK_CallTo16_long_wwl( proc, code, wparam, lparam );
79 /* Grrr. While the hook procedure is supposed to have an LRESULT return
80 value even in Win16, it seems that for those hook types where the
81 return value is interpreted as BOOL, Windows doesn't actually check
82 the HIWORD ... Some buggy Win16 programs, notably WINFILE, rely on
83 that, because they neglect to clear DX ... */
84 if (id != WH_JOURNALPLAYBACK) ret = LOWORD( ret );
85 return ret;
89 /***********************************************************************
90 * call_hook_16_to_32
92 * Convert hook params to 32-bit and call 32-bit hook procedure
94 static LRESULT call_hook_16_to_32( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam,
95 BOOL unicode )
97 LRESULT ret = 0;
99 switch( id )
101 case WH_MSGFILTER:
102 case WH_SYSMSGFILTER:
103 case WH_JOURNALRECORD:
105 MSG16 *msg16 = MapSL(lparam);
106 MSG msg32;
108 STRUCT32_MSG16to32( msg16, &msg32 );
109 ret = proc( code, wparam, (LPARAM)&msg32 );
110 break;
113 case WH_GETMESSAGE:
115 MSG16 *msg16 = MapSL(lparam);
116 MSG msg32;
118 STRUCT32_MSG16to32( msg16, &msg32 );
119 ret = proc( code, wparam, (LPARAM)&msg32 );
120 STRUCT32_MSG32to16( &msg32, msg16 );
121 break;
124 case WH_JOURNALPLAYBACK:
126 EVENTMSG16 *em16 = MapSL(lparam);
127 EVENTMSG em32;
129 em32.message = em16->message;
130 em32.paramL = em16->paramL;
131 em32.paramH = em16->paramH;
132 em32.time = em16->time;
133 em32.hwnd = 0; /* FIXME */
134 ret = proc( code, wparam, (LPARAM)&em32 );
135 break;
138 case WH_CALLWNDPROC:
140 CWPSTRUCT16 *cwp16 = MapSL(lparam);
141 CWPSTRUCT cwp32;
143 cwp32.hwnd = WIN_Handle32(cwp16->hwnd);
144 cwp32.lParam = cwp16->lParam;
146 if (unicode)
147 WINPROC_MapMsg16To32W( cwp32.hwnd, cwp16->message, cwp16->wParam,
148 &cwp32.message, &cwp32.wParam, &cwp32.lParam );
149 else
150 WINPROC_MapMsg16To32A( cwp32.hwnd, cwp16->message, cwp16->wParam,
151 &cwp32.message, &cwp32.wParam, &cwp32.lParam );
153 ret = proc( code, wparam, (LPARAM)&cwp32 );
155 if (unicode)
156 WINPROC_UnmapMsg16To32W( cwp32.hwnd, cwp32.message, cwp32.wParam, cwp32.lParam, 0 );
157 else
158 WINPROC_UnmapMsg16To32A( cwp32.hwnd, cwp32.message, cwp32.wParam, cwp32.lParam, 0 );
159 break;
162 case WH_CBT:
163 switch (code)
165 case HCBT_CREATEWND:
167 CBT_CREATEWNDA cbtcw32;
168 CREATESTRUCTA cs32;
169 CBT_CREATEWND16 *cbtcw16 = MapSL(lparam);
170 CREATESTRUCT16 *cs16 = MapSL( (SEGPTR)cbtcw16->lpcs );
172 cbtcw32.lpcs = &cs32;
173 cbtcw32.hwndInsertAfter = WIN_Handle32( cbtcw16->hwndInsertAfter );
174 STRUCT32_CREATESTRUCT16to32A( cs16, &cs32 );
176 if (unicode)
178 cs32.lpszName = (LPSTR)map_str_16_to_32W( cs16->lpszName );
179 cs32.lpszClass = (LPSTR)map_str_16_to_32W( cs16->lpszClass );
180 ret = proc( code, wparam, (LPARAM)&cbtcw32 );
181 unmap_str_16_to_32W( (LPWSTR)cs32.lpszName );
182 unmap_str_16_to_32W( (LPWSTR)cs32.lpszClass );
184 else
186 cs32.lpszName = MapSL( cs16->lpszName );
187 cs32.lpszClass = MapSL( cs16->lpszClass );
188 ret = proc( code, wparam, (LPARAM)&cbtcw32 );
190 cbtcw16->hwndInsertAfter = WIN_Handle16( cbtcw32.hwndInsertAfter );
191 break;
193 case HCBT_ACTIVATE:
195 CBTACTIVATESTRUCT16 *cas16 = MapSL(lparam);
196 CBTACTIVATESTRUCT cas32;
197 cas32.fMouse = cas16->fMouse;
198 cas32.hWndActive = WIN_Handle32(cas16->hWndActive);
199 ret = proc( code, wparam, (LPARAM)&cas32 );
200 break;
202 case HCBT_CLICKSKIPPED:
204 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
205 MOUSEHOOKSTRUCT ms32;
207 ms32.pt.x = ms16->pt.x;
208 ms32.pt.y = ms16->pt.y;
209 /* wHitTestCode may be negative, so convince compiler to do
210 correct sign extension. Yay. :| */
211 ms32.wHitTestCode = (INT)(INT16)ms16->wHitTestCode;
212 ms32.dwExtraInfo = ms16->dwExtraInfo;
213 ms32.hwnd = WIN_Handle32( ms16->hwnd );
214 ret = proc( code, wparam, (LPARAM)&ms32 );
215 break;
217 case HCBT_MOVESIZE:
219 RECT16 *rect16 = MapSL(lparam);
220 RECT rect32;
222 CONV_RECT16TO32( rect16, &rect32 );
223 ret = proc( code, wparam, (LPARAM)&rect32 );
224 break;
227 break;
229 case WH_MOUSE:
231 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
232 MOUSEHOOKSTRUCT ms32;
234 ms32.pt.x = ms16->pt.x;
235 ms32.pt.y = ms16->pt.y;
236 /* wHitTestCode may be negative, so convince compiler to do
237 correct sign extension. Yay. :| */
238 ms32.wHitTestCode = (INT)((INT16)ms16->wHitTestCode);
239 ms32.dwExtraInfo = ms16->dwExtraInfo;
240 ms32.hwnd = WIN_Handle32(ms16->hwnd);
241 ret = proc( code, wparam, (LPARAM)&ms32 );
242 break;
245 case WH_DEBUG:
247 DEBUGHOOKINFO16 *dh16 = MapSL(lparam);
248 DEBUGHOOKINFO dh32;
250 dh32.idThread = 0; /* FIXME */
251 dh32.idThreadInstaller = 0; /* FIXME */
252 dh32.lParam = dh16->lParam; /* FIXME Check for sign ext */
253 dh32.wParam = dh16->wParam;
254 dh32.code = dh16->code;
256 /* do sign extension if it was WH_MSGFILTER */
257 if (wparam == 0xffff) wparam = WH_MSGFILTER;
258 ret = proc( code, wparam, (LPARAM)&dh32 );
259 break;
262 case WH_SHELL:
263 case WH_KEYBOARD:
264 ret = proc( code, wparam, lparam );
265 break;
267 case WH_HARDWARE:
268 case WH_FOREGROUNDIDLE:
269 case WH_CALLWNDPROCRET:
270 default:
271 FIXME("\t[%i] 16to32 translation unimplemented\n", id);
272 ret = proc( code, wparam, lparam );
273 break;
275 return ret;
279 /***********************************************************************
280 * call_hook_32_to_16
282 * Convert hook params to 16-bit and call 16-bit hook procedure
284 static LRESULT call_hook_32_to_16( HOOKPROC16 proc, INT id, INT code, WPARAM wparam, LPARAM lparam,
285 BOOL unicode )
287 LRESULT ret = 0;
289 switch (id)
291 case WH_MSGFILTER:
292 case WH_SYSMSGFILTER:
293 case WH_JOURNALRECORD:
295 MSG *msg32 = (MSG *)lparam;
296 MSG16 msg16;
298 STRUCT32_MSG32to16( msg32, &msg16 );
299 lparam = MapLS( &msg16 );
300 ret = call_hook_16( proc, id, code, wparam, lparam );
301 UnMapLS( lparam );
302 break;
305 case WH_GETMESSAGE:
307 MSG *msg32 = (MSG *)lparam;
308 MSG16 msg16;
310 STRUCT32_MSG32to16( msg32, &msg16 );
311 lparam = MapLS( &msg16 );
312 ret = call_hook_16( proc, id, code, wparam, lparam );
313 UnMapLS( lparam );
314 STRUCT32_MSG16to32( &msg16, msg32 );
315 break;
318 case WH_JOURNALPLAYBACK:
320 EVENTMSG *em32 = (EVENTMSG *)lparam;
321 EVENTMSG16 em16;
323 em16.message = em32->message;
324 em16.paramL = em32->paramL;
325 em16.paramH = em32->paramH;
326 em16.time = em32->time;
327 lparam = MapLS( &em16 );
328 ret = call_hook_16( proc, id, code, wparam, lparam );
329 UnMapLS( lparam );
330 break;
333 case WH_CALLWNDPROC:
335 CWPSTRUCT *cwp32 = (CWPSTRUCT *)lparam;
336 CWPSTRUCT16 cwp16;
337 MSGPARAM16 mp16;
339 cwp16.hwnd = WIN_Handle16(cwp32->hwnd);
340 cwp16.lParam = cwp32->lParam;
342 if (unicode)
343 WINPROC_MapMsg32WTo16( cwp32->hwnd, cwp32->message, cwp32->wParam,
344 &cwp16.message, &cwp16.wParam, &cwp16.lParam );
345 else
346 WINPROC_MapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam,
347 &cwp16.message, &cwp16.wParam, &cwp16.lParam );
349 lparam = MapLS( &cwp16 );
350 ret = call_hook_16( proc, id, code, wparam, lparam );
351 UnMapLS( lparam );
353 mp16.wParam = cwp16.wParam;
354 mp16.lParam = cwp16.lParam;
355 mp16.lResult = 0;
356 if (unicode)
357 WINPROC_UnmapMsg32WTo16( cwp32->hwnd, cwp32->message, cwp32->wParam,
358 cwp32->lParam, &mp16 );
359 else
360 WINPROC_UnmapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam,
361 cwp32->lParam, &mp16 );
362 break;
365 case WH_CBT:
366 switch (code)
368 case HCBT_CREATEWND:
370 CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lparam;
371 CBT_CREATEWND16 cbtcw16;
372 CREATESTRUCT16 cs16;
374 STRUCT32_CREATESTRUCT32Ato16( cbtcw32->lpcs, &cs16 );
375 cbtcw16.lpcs = (CREATESTRUCT16 *)MapLS( &cs16 );
376 cbtcw16.hwndInsertAfter = WIN_Handle16( cbtcw32->hwndInsertAfter );
377 lparam = MapLS( &cbtcw16 );
379 if (unicode)
381 cs16.lpszName = map_str_32W_to_16( (LPWSTR)cbtcw32->lpcs->lpszName );
382 cs16.lpszClass = map_str_32W_to_16( (LPWSTR)cbtcw32->lpcs->lpszClass );
383 ret = call_hook_16( proc, id, code, wparam, lparam );
384 unmap_str_32W_to_16( cs16.lpszName );
385 unmap_str_32W_to_16( cs16.lpszClass );
387 else
389 cs16.lpszName = MapLS( cbtcw32->lpcs->lpszName );
390 cs16.lpszClass = MapLS( cbtcw32->lpcs->lpszClass );
391 ret = call_hook_16( proc, id, code, wparam, lparam );
392 UnMapLS( cs16.lpszName );
393 UnMapLS( cs16.lpszClass );
395 cbtcw32->hwndInsertAfter = WIN_Handle32( cbtcw16.hwndInsertAfter );
396 UnMapLS( (SEGPTR)cbtcw16.lpcs );
397 UnMapLS( lparam );
398 break;
401 case HCBT_ACTIVATE:
403 CBTACTIVATESTRUCT *cas32 = (CBTACTIVATESTRUCT *)lparam;
404 CBTACTIVATESTRUCT16 cas16;
406 cas16.fMouse = cas32->fMouse;
407 cas16.hWndActive = WIN_Handle16( cas32->hWndActive );
409 lparam = MapLS( &cas16 );
410 ret = call_hook_16( proc, id, code, wparam, lparam );
411 UnMapLS( lparam );
412 break;
414 case HCBT_CLICKSKIPPED:
416 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lparam;
417 MOUSEHOOKSTRUCT16 ms16;
419 ms16.pt.x = ms32->pt.x;
420 ms16.pt.y = ms32->pt.y;
421 ms16.hwnd = WIN_Handle16( ms32->hwnd );
422 ms16.wHitTestCode = ms32->wHitTestCode;
423 ms16.dwExtraInfo = ms32->dwExtraInfo;
425 lparam = MapLS( &ms16 );
426 ret = call_hook_16( proc, id, code, wparam, lparam );
427 UnMapLS( lparam );
428 break;
430 case HCBT_MOVESIZE:
432 RECT *rect32 = (RECT *)lparam;
433 RECT16 rect16;
435 CONV_RECT32TO16( rect32, &rect16 );
436 lparam = MapLS( &rect16 );
437 ret = call_hook_16( proc, id, code, wparam, lparam );
438 UnMapLS( lparam );
439 break;
442 break;
444 case WH_MOUSE:
446 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lparam;
447 MOUSEHOOKSTRUCT16 ms16;
449 ms16.pt.x = ms32->pt.x;
450 ms16.pt.y = ms32->pt.y;
451 ms16.hwnd = WIN_Handle16( ms32->hwnd );
452 ms16.wHitTestCode = ms32->wHitTestCode;
453 ms16.dwExtraInfo = ms32->dwExtraInfo;
455 lparam = MapLS( &ms16 );
456 ret = call_hook_16( proc, id, code, wparam, lparam );
457 UnMapLS( lparam );
458 break;
461 case WH_DEBUG:
463 DEBUGHOOKINFO *dh32 = (DEBUGHOOKINFO *)lparam;
464 DEBUGHOOKINFO16 dh16;
466 dh16.hModuleHook = 0; /* FIXME */
467 dh16.reserved = 0;
468 dh16.lParam = dh32->lParam;
469 dh16.wParam = dh32->wParam;
470 dh16.code = dh32->code;
472 lparam = MapLS( &dh16 );
473 ret = call_hook_16( proc, id, code, wparam, lparam );
474 UnMapLS( lparam );
475 break;
478 case WH_SHELL:
479 case WH_KEYBOARD:
480 ret = call_hook_16( proc, id, code, wparam, lparam );
481 break;
483 case WH_HARDWARE:
484 case WH_FOREGROUNDIDLE:
485 case WH_CALLWNDPROCRET:
486 default:
487 FIXME("\t[%i] 32to16 translation unimplemented\n", id);
488 ret = call_hook_16( proc, id, code, wparam, lparam );
489 break;
491 return ret;
495 /***********************************************************************
496 * call_hook_32_to_32
498 * Convert hook params to/from Unicode and call hook procedure
500 static LRESULT call_hook_32_to_32( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam,
501 BOOL to_unicode )
503 if (id != WH_CBT || code != HCBT_CREATEWND) return proc( code, wparam, lparam );
505 if (to_unicode) /* ASCII to Unicode */
507 CBT_CREATEWNDA *cbtcwA = (CBT_CREATEWNDA *)lparam;
508 CBT_CREATEWNDW cbtcwW;
509 CREATESTRUCTW csW;
510 LRESULT ret;
512 cbtcwW.lpcs = &csW;
513 cbtcwW.hwndInsertAfter = cbtcwA->hwndInsertAfter;
514 csW = *(CREATESTRUCTW *)cbtcwA->lpcs;
516 if (HIWORD(cbtcwA->lpcs->lpszName))
517 csW.lpszName = HEAP_strdupAtoW( GetProcessHeap(), 0, cbtcwA->lpcs->lpszName );
518 if (HIWORD(cbtcwA->lpcs->lpszClass))
519 csW.lpszClass = HEAP_strdupAtoW( GetProcessHeap(), 0, cbtcwA->lpcs->lpszClass );
520 ret = proc( code, wparam, (LPARAM)&cbtcwW );
521 cbtcwA->hwndInsertAfter = cbtcwW.hwndInsertAfter;
522 if (HIWORD(csW.lpszName)) HeapFree( GetProcessHeap(), 0, (LPWSTR)csW.lpszName );
523 if (HIWORD(csW.lpszClass)) HeapFree( GetProcessHeap(), 0, (LPWSTR)csW.lpszClass );
524 return ret;
526 else /* Unicode to ASCII */
528 CBT_CREATEWNDW *cbtcwW = (CBT_CREATEWNDW *)lparam;
529 CBT_CREATEWNDA cbtcwA;
530 CREATESTRUCTA csA;
531 LRESULT ret;
533 cbtcwA.lpcs = &csA;
534 cbtcwA.hwndInsertAfter = cbtcwW->hwndInsertAfter;
535 csA = *(CREATESTRUCTA *)cbtcwW->lpcs;
537 if (HIWORD(cbtcwW->lpcs->lpszName))
538 csA.lpszName = HEAP_strdupWtoA( GetProcessHeap(), 0, cbtcwW->lpcs->lpszName );
539 if (HIWORD(cbtcwW->lpcs->lpszClass))
540 csA.lpszClass = HEAP_strdupWtoA( GetProcessHeap(), 0, cbtcwW->lpcs->lpszClass );
541 ret = proc( code, wparam, (LPARAM)&cbtcwA );
542 cbtcwW->hwndInsertAfter = cbtcwA.hwndInsertAfter;
543 if (HIWORD(csA.lpszName)) HeapFree( GetProcessHeap(), 0, (LPSTR)csA.lpszName );
544 if (HIWORD(csA.lpszClass)) HeapFree( GetProcessHeap(), 0, (LPSTR)csA.lpszClass );
545 return ret;
550 /***********************************************************************
551 * call_hook
553 * Call a hook procedure.
555 inline static LRESULT call_hook( HOOKDATA *data, INT fromtype, INT code,
556 WPARAM wparam, LPARAM lparam )
558 INT type = (data->flags & HOOK_MAPTYPE);
559 LRESULT ret;
561 /* Suspend window structure locks before calling user code */
562 int iWndsLocks = WIN_SuspendWndsLock();
564 if (type == HOOK_WIN16)
566 if (fromtype == HOOK_WIN16) /* 16->16 */
567 ret = call_hook_16( (HOOKPROC16)data->proc, data->id, code, wparam, lparam );
568 else /* 32->16 */
569 ret = call_hook_32_to_16( (HOOKPROC16)data->proc, data->id, code, wparam,
570 lparam, (type == HOOK_WIN32W) );
572 else if (fromtype == HOOK_WIN16) /* 16->32 */
573 ret = call_hook_16_to_32( data->proc, data->id, code, wparam,
574 lparam, (type == HOOK_WIN32W) );
575 else /* 32->32, check unicode */
577 if (type == fromtype)
578 ret = data->proc( code, wparam, lparam );
579 else
580 ret = call_hook_32_to_32( data->proc, data->id, code, wparam,
581 lparam, (type == HOOK_WIN32W) );
583 WIN_RestoreWndsLock(iWndsLocks);
584 return ret;
588 /***********************************************************************
589 * HOOK_GetNextHook
591 * Get the next hook of a given hook.
593 static HANDLE16 HOOK_GetNextHook( HANDLE16 hook )
595 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR( hook );
597 if (!data || !hook) return 0;
598 if (data->next) return data->next;
599 if (!data->ownerQueue) return 0; /* Already system hook */
601 /* Now start enumerating the system hooks */
602 return HOOK_systemHooks[data->id - WH_MINHOOK];
606 /***********************************************************************
607 * HOOK_GetHook
609 * Get the first hook for a given type.
611 static HANDLE16 HOOK_GetHook( INT16 id )
613 MESSAGEQUEUE *queue;
614 HANDLE16 hook = 0;
616 if ((queue = QUEUE_Current()) != NULL)
617 hook = queue->hooks[id - WH_MINHOOK];
618 if (!hook) hook = HOOK_systemHooks[id - WH_MINHOOK];
619 return hook;
623 /***********************************************************************
624 * HOOK_SetHook
626 * Install a given hook.
628 static HHOOK HOOK_SetHook( INT16 id, LPVOID proc, INT type,
629 HMODULE16 hModule, DWORD dwThreadId )
631 HOOKDATA *data;
632 HANDLE16 handle;
633 HQUEUE16 hQueue = 0;
635 if ((id < WH_MINHOOK) || (id > WH_MAXHOOK)) return 0;
637 TRACE("Setting hook %d: %08x %04x %08lx\n",
638 id, (UINT)proc, hModule, dwThreadId );
640 /* Create task queue if none present */
641 InitThreadInput16( 0, 0 );
643 if (id == WH_JOURNALPLAYBACK) EnableHardwareInput16(FALSE);
645 if (dwThreadId) /* Task-specific hook */
647 if ((id == WH_JOURNALRECORD) || (id == WH_JOURNALPLAYBACK) ||
648 (id == WH_SYSMSGFILTER)) return 0; /* System-only hooks */
649 if (!(hQueue = GetThreadQueue16( dwThreadId )))
650 return 0;
653 /* Create the hook structure */
655 if (!(handle = USER_HEAP_ALLOC( sizeof(HOOKDATA) ))) return 0;
656 data = (HOOKDATA *) USER_HEAP_LIN_ADDR( handle );
657 data->proc = proc;
658 data->id = id;
659 data->ownerQueue = hQueue;
660 data->ownerModule = hModule;
661 data->flags = type;
663 /* Insert it in the correct linked list */
665 if (hQueue)
667 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
668 data->next = queue->hooks[id - WH_MINHOOK];
669 queue->hooks[id - WH_MINHOOK] = handle;
670 QUEUE_Unlock( queue );
672 else
674 data->next = HOOK_systemHooks[id - WH_MINHOOK];
675 HOOK_systemHooks[id - WH_MINHOOK] = handle;
677 TRACE("Setting hook %d: ret=%04x [next=%04x]\n",
678 id, handle, data->next );
680 return (HHOOK)( handle? MAKELONG( handle, HOOK_MAGIC ) : 0 );
684 /***********************************************************************
685 * HOOK_RemoveHook
687 * Remove a hook from the list.
689 static BOOL HOOK_RemoveHook( HANDLE16 hook )
691 HOOKDATA *data;
692 HANDLE16 *prevHook;
694 TRACE("Removing hook %04x\n", hook );
696 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return FALSE;
697 if (data->flags & HOOK_INUSE)
699 /* Mark it for deletion later on */
700 WARN("Hook still running, deletion delayed\n" );
701 data->proc = (HOOKPROC)0;
702 return TRUE;
705 if (data->id == WH_JOURNALPLAYBACK) EnableHardwareInput16(TRUE);
707 /* Remove it from the linked list */
709 if (data->ownerQueue)
711 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( data->ownerQueue );
712 if (!queue) return FALSE;
713 prevHook = &queue->hooks[data->id - WH_MINHOOK];
714 QUEUE_Unlock( queue );
716 else prevHook = &HOOK_systemHooks[data->id - WH_MINHOOK];
718 while (*prevHook && *prevHook != hook)
719 prevHook = &((HOOKDATA *)USER_HEAP_LIN_ADDR(*prevHook))->next;
721 if (!*prevHook) return FALSE;
722 *prevHook = data->next;
724 USER_HEAP_FREE( hook );
725 return TRUE;
729 /***********************************************************************
730 * HOOK_FindValidHook
732 static HANDLE16 HOOK_FindValidHook( HANDLE16 hook )
734 HOOKDATA *data;
736 for (;;)
738 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return 0;
739 if (data->proc) return hook;
740 hook = data->next;
744 /***********************************************************************
745 * HOOK_CallHook
747 * Call a hook procedure.
749 static LRESULT HOOK_CallHook( HANDLE16 hook, INT fromtype, INT code,
750 WPARAM wParam, LPARAM lParam )
752 MESSAGEQUEUE *queue;
753 HANDLE16 prevHook;
754 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
755 LRESULT ret;
757 if (!(queue = QUEUE_Current())) return 0;
758 prevHook = queue->hCurHook;
759 queue->hCurHook = hook;
761 TRACE("Calling hook %04x: %d %08x %08lx\n", hook, code, wParam, lParam );
763 data->flags |= HOOK_INUSE;
764 ret = call_hook( data, fromtype, code, wParam, lParam );
765 data->flags &= ~HOOK_INUSE;
767 TRACE("Ret hook %04x = %08lx\n", hook, ret );
769 queue->hCurHook = prevHook;
770 if (!data->proc) HOOK_RemoveHook( hook );
771 return ret;
774 /***********************************************************************
775 * Exported Functions & APIs
778 /***********************************************************************
779 * HOOK_IsHooked
781 * Replacement for calling HOOK_GetHook from other modules.
783 BOOL HOOK_IsHooked( INT16 id )
785 return HOOK_GetHook( id ) != 0;
789 /***********************************************************************
790 * HOOK_CallHooks16
792 * Call a hook chain.
794 LRESULT HOOK_CallHooks16( INT16 id, INT16 code, WPARAM16 wParam,
795 LPARAM lParam )
797 HANDLE16 hook;
799 if (!(hook = HOOK_GetHook( id ))) return 0;
800 if (!(hook = HOOK_FindValidHook(hook))) return 0;
801 return HOOK_CallHook( hook, HOOK_WIN16, code, wParam, lParam );
804 /***********************************************************************
805 * HOOK_CallHooksA
807 * Call a hook chain.
809 LRESULT HOOK_CallHooksA( INT id, INT code, WPARAM wParam,
810 LPARAM lParam )
812 HANDLE16 hook;
814 if (!(hook = HOOK_GetHook( id ))) return 0;
815 if (!(hook = HOOK_FindValidHook(hook))) return 0;
816 return HOOK_CallHook( hook, HOOK_WIN32A, code, wParam, lParam );
819 /***********************************************************************
820 * HOOK_CallHooksW
822 * Call a hook chain.
824 LRESULT HOOK_CallHooksW( INT id, INT code, WPARAM wParam,
825 LPARAM lParam )
827 HANDLE16 hook;
829 if (!(hook = HOOK_GetHook( id ))) return 0;
830 if (!(hook = HOOK_FindValidHook(hook))) return 0;
831 return HOOK_CallHook( hook, HOOK_WIN32W, code, wParam,
832 lParam );
836 /***********************************************************************
837 * HOOK_FreeModuleHooks
839 void HOOK_FreeModuleHooks( HMODULE16 hModule )
841 /* remove all system hooks registered by this module */
843 HOOKDATA* hptr;
844 HHOOK hook, next;
845 int id;
847 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
849 hook = HOOK_systemHooks[id - WH_MINHOOK];
850 while( hook )
851 if( (hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook)) )
853 next = hptr->next;
854 if( hptr->ownerModule == hModule )
856 hptr->flags &= HOOK_MAPTYPE;
857 HOOK_RemoveHook(hook);
859 hook = next;
861 else hook = 0;
865 /***********************************************************************
866 * HOOK_FreeQueueHooks
868 void HOOK_FreeQueueHooks(void)
870 /* remove all hooks registered by the current queue */
872 HOOKDATA* hptr = NULL;
873 HHOOK hook, next;
874 int id;
876 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
878 hook = HOOK_GetHook( id );
879 while( hook )
881 next = HOOK_GetNextHook(hook);
883 hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
884 if( hptr && hptr->ownerQueue )
886 hptr->flags &= HOOK_MAPTYPE;
887 HOOK_RemoveHook(hook);
889 hook = next;
895 /***********************************************************************
896 * SetWindowsHook (USER.121)
898 FARPROC16 WINAPI SetWindowsHook16( INT16 id, HOOKPROC16 proc )
900 HINSTANCE16 hInst = FarGetOwner16( HIWORD(proc) );
902 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
903 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
905 return (FARPROC16)SetWindowsHookEx16( id, proc, hInst, hTask );
908 /***********************************************************************
909 * SetWindowsHookA (USER32.@)
911 HHOOK WINAPI SetWindowsHookA( INT id, HOOKPROC proc )
913 return SetWindowsHookExA( id, proc, 0, GetCurrentThreadId() );
916 /***********************************************************************
917 * SetWindowsHookW (USER32.@)
919 HHOOK WINAPI SetWindowsHookW( INT id, HOOKPROC proc )
921 return SetWindowsHookExW( id, proc, 0, GetCurrentThreadId() );
925 /***********************************************************************
926 * SetWindowsHookEx (USER.291)
927 * SetWindowsHookEx16 (USER32.@)
929 HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst,
930 HTASK16 hTask )
932 if (id == WH_DEBUG)
934 FIXME("WH_DEBUG is broken in 16-bit Windows.\n");
935 return 0;
937 return HOOK_SetHook( id, proc, HOOK_WIN16, GetExePtr(hInst), (DWORD)hTask );
940 /***********************************************************************
941 * SetWindowsHookExA (USER32.@)
943 HHOOK WINAPI SetWindowsHookExA( INT id, HOOKPROC proc, HINSTANCE hInst,
944 DWORD dwThreadId )
946 return HOOK_SetHook( id, proc, HOOK_WIN32A, MapHModuleLS(hInst), dwThreadId );
949 /***********************************************************************
950 * SetWindowsHookExW (USER32.@)
952 HHOOK WINAPI SetWindowsHookExW( INT id, HOOKPROC proc, HINSTANCE hInst,
953 DWORD dwThreadId )
955 return HOOK_SetHook( id, proc, HOOK_WIN32W, MapHModuleLS(hInst), dwThreadId );
959 /***********************************************************************
960 * UnhookWindowsHook (USER.234)
962 BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
964 return UnhookWindowsHook( id, (HOOKPROC)proc );
967 /***********************************************************************
968 * UnhookWindowsHook (USER32.@)
970 BOOL WINAPI UnhookWindowsHook( INT id, HOOKPROC proc )
972 HANDLE16 hook = HOOK_GetHook( id );
974 TRACE("%d %08lx\n", id, (DWORD)proc );
976 while (hook)
978 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
979 if (data->proc == proc) break;
980 hook = HOOK_GetNextHook( hook );
982 if (!hook) return FALSE;
983 return HOOK_RemoveHook( hook );
987 /***********************************************************************
988 * UnhookWindowsHookEx (USER.292)
990 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
992 return UnhookWindowsHookEx( hhook );
995 /***********************************************************************
996 * UnhookWindowsHookEx (USER32.@)
998 BOOL WINAPI UnhookWindowsHookEx( HHOOK hhook )
1000 if (HIWORD(hhook) != HOOK_MAGIC) return FALSE; /* Not a new format hook */
1001 return HOOK_RemoveHook( LOWORD(hhook) );
1005 /***********************************************************************
1006 * CallNextHookEx (USER.293)
1007 * CallNextHookEx16 (USER32.@)
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.
1012 LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wParam,
1013 LPARAM lParam )
1015 HANDLE16 next;
1017 if (HIWORD(hhook) != HOOK_MAGIC) return 0; /* Not a new format hook */
1018 if (!(next = HOOK_GetNextHook( LOWORD(hhook) ))) return 0;
1020 return HOOK_CallHook( next, HOOK_WIN16, code, wParam, lParam );
1024 /***********************************************************************
1025 * CallNextHookEx (USER32.@)
1027 * There aren't ANSI and UNICODE versions of this.
1029 LRESULT WINAPI CallNextHookEx( HHOOK hhook, INT code, WPARAM wParam,
1030 LPARAM lParam )
1032 HANDLE16 next;
1033 INT fromtype; /* figure out Ansi/Unicode */
1034 HOOKDATA *oldhook;
1036 if (HIWORD(hhook) != HOOK_MAGIC) return 0; /* Not a new format hook */
1037 if (!(next = HOOK_GetNextHook( LOWORD(hhook) ))) return 0;
1039 oldhook = (HOOKDATA *)USER_HEAP_LIN_ADDR( LOWORD(hhook) );
1040 fromtype = oldhook->flags & HOOK_MAPTYPE;
1042 if (fromtype == HOOK_WIN16)
1043 ERR("called from 16bit hook!\n");
1045 return HOOK_CallHook( next, fromtype, code, wParam, lParam );
1049 /***********************************************************************
1050 * DefHookProc (USER.235)
1052 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wParam, LPARAM lParam,
1053 HHOOK *hhook )
1055 /* Note: the *hhook parameter is never used, since we rely on the
1056 * current hook value from the task queue to find the next hook. */
1057 MESSAGEQUEUE *queue;
1059 if (!(queue = QUEUE_Current())) return 0;
1060 return CallNextHookEx16( queue->hCurHook, code, wParam, lParam );
1064 /***********************************************************************
1065 * CallMsgFilter (USER.123)
1067 BOOL16 WINAPI CallMsgFilter16( SEGPTR msg, INT16 code )
1069 if (GetSysModalWindow16()) return FALSE;
1070 if (HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) return TRUE;
1071 return HOOK_CallHooks16( WH_MSGFILTER, code, 0, (LPARAM)msg );
1075 /***********************************************************************
1076 * CallMsgFilter32 (USER.823)
1078 BOOL16 WINAPI CallMsgFilter32_16( SEGPTR msg16_32, INT16 code, BOOL16 wHaveParamHigh )
1080 MSG32_16 *lpmsg16_32 = MapSL(msg16_32);
1082 if (wHaveParamHigh == FALSE)
1084 lpmsg16_32->wParamHigh = 0;
1085 /* WARNING: msg16_32->msg has to be the first variable in the struct */
1086 return CallMsgFilter16(msg16_32, code);
1088 else
1090 MSG msg32;
1091 BOOL16 ret;
1093 msg32.hwnd = WIN_Handle32( lpmsg16_32->msg.hwnd );
1094 msg32.message = lpmsg16_32->msg.message;
1095 msg32.wParam = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh);
1096 msg32.lParam = lpmsg16_32->msg.lParam;
1097 msg32.time = lpmsg16_32->msg.time;
1098 msg32.pt.x = lpmsg16_32->msg.pt.x;
1099 msg32.pt.y = lpmsg16_32->msg.pt.y;
1101 ret = (BOOL16)CallMsgFilterA(&msg32, (INT)code);
1103 lpmsg16_32->msg.hwnd = WIN_Handle16( msg32.hwnd );
1104 lpmsg16_32->msg.message = msg32.message;
1105 lpmsg16_32->msg.wParam = LOWORD(msg32.wParam);
1106 lpmsg16_32->msg.lParam = msg32.lParam;
1107 lpmsg16_32->msg.time = msg32.time;
1108 lpmsg16_32->msg.pt.x = msg32.pt.x;
1109 lpmsg16_32->msg.pt.y = msg32.pt.y;
1110 lpmsg16_32->wParamHigh = HIWORD(msg32.wParam);
1112 return ret;
1117 /***********************************************************************
1118 * CallMsgFilterA (USER32.@)
1120 * FIXME: There are ANSI and UNICODE versions of this, plus an unspecified
1121 * version, plus USER (the 16bit one) has a CallMsgFilter32 function.
1123 BOOL WINAPI CallMsgFilterA( LPMSG msg, INT code )
1125 if (GetSysModalWindow16()) return FALSE; /* ??? */
1126 if (HOOK_CallHooksA( WH_SYSMSGFILTER, code, 0, (LPARAM)msg ))
1127 return TRUE;
1128 return HOOK_CallHooksA( WH_MSGFILTER, code, 0, (LPARAM)msg );
1132 /***********************************************************************
1133 * CallMsgFilterW (USER32.@)
1135 BOOL WINAPI CallMsgFilterW( LPMSG msg, INT code )
1137 if (GetSysModalWindow16()) return FALSE; /* ??? */
1138 if (HOOK_CallHooksW( WH_SYSMSGFILTER, code, 0, (LPARAM)msg ))
1139 return TRUE;
1140 return HOOK_CallHooksW( WH_MSGFILTER, code, 0, (LPARAM)msg );