2 * Windows hook functions
4 * Copyright 1994, 1995 Alexandre Julliard
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
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.
35 #include "wine/winuser16.h"
36 #include "wine/winbase16.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(hook
);
50 /* Hook data (pointed to by a HHOOK) */
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 */
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 /***********************************************************************
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
);
89 /***********************************************************************
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
,
102 case WH_SYSMSGFILTER
:
103 case WH_JOURNALRECORD
:
105 MSG16
*msg16
= MapSL(lparam
);
108 STRUCT32_MSG16to32( msg16
, &msg32
);
109 ret
= proc( code
, wparam
, (LPARAM
)&msg32
);
115 MSG16
*msg16
= MapSL(lparam
);
118 STRUCT32_MSG16to32( msg16
, &msg32
);
119 ret
= proc( code
, wparam
, (LPARAM
)&msg32
);
120 STRUCT32_MSG32to16( &msg32
, msg16
);
124 case WH_JOURNALPLAYBACK
:
126 EVENTMSG16
*em16
= MapSL(lparam
);
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
);
140 CWPSTRUCT16
*cwp16
= MapSL(lparam
);
143 cwp32
.hwnd
= WIN_Handle32(cwp16
->hwnd
);
144 cwp32
.lParam
= cwp16
->lParam
;
147 WINPROC_MapMsg16To32W( cwp32
.hwnd
, cwp16
->message
, cwp16
->wParam
,
148 &cwp32
.message
, &cwp32
.wParam
, &cwp32
.lParam
);
150 WINPROC_MapMsg16To32A( cwp32
.hwnd
, cwp16
->message
, cwp16
->wParam
,
151 &cwp32
.message
, &cwp32
.wParam
, &cwp32
.lParam
);
153 ret
= proc( code
, wparam
, (LPARAM
)&cwp32
);
156 WINPROC_UnmapMsg16To32W( cwp32
.hwnd
, cwp32
.message
, cwp32
.wParam
, cwp32
.lParam
, 0 );
158 WINPROC_UnmapMsg16To32A( cwp32
.hwnd
, cwp32
.message
, cwp32
.wParam
, cwp32
.lParam
, 0 );
167 CBT_CREATEWNDA cbtcw32
;
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
);
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
);
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
);
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
);
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
);
219 RECT16
*rect16
= MapSL(lparam
);
222 CONV_RECT16TO32( rect16
, &rect32
);
223 ret
= proc( code
, wparam
, (LPARAM
)&rect32
);
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
);
247 DEBUGHOOKINFO16
*dh16
= MapSL(lparam
);
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
);
264 ret
= proc( code
, wparam
, lparam
);
268 case WH_FOREGROUNDIDLE
:
269 case WH_CALLWNDPROCRET
:
271 FIXME("\t[%i] 16to32 translation unimplemented\n", id
);
272 ret
= proc( code
, wparam
, lparam
);
279 /***********************************************************************
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
,
292 case WH_SYSMSGFILTER
:
293 case WH_JOURNALRECORD
:
295 MSG
*msg32
= (MSG
*)lparam
;
298 STRUCT32_MSG32to16( msg32
, &msg16
);
299 lparam
= MapLS( &msg16
);
300 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
307 MSG
*msg32
= (MSG
*)lparam
;
310 STRUCT32_MSG32to16( msg32
, &msg16
);
311 lparam
= MapLS( &msg16
);
312 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
314 STRUCT32_MSG16to32( &msg16
, msg32
);
318 case WH_JOURNALPLAYBACK
:
320 EVENTMSG
*em32
= (EVENTMSG
*)lparam
;
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
);
335 CWPSTRUCT
*cwp32
= (CWPSTRUCT
*)lparam
;
339 cwp16
.hwnd
= WIN_Handle16(cwp32
->hwnd
);
340 cwp16
.lParam
= cwp32
->lParam
;
343 WINPROC_MapMsg32WTo16( cwp32
->hwnd
, cwp32
->message
, cwp32
->wParam
,
344 &cwp16
.message
, &cwp16
.wParam
, &cwp16
.lParam
);
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
);
353 mp16
.wParam
= cwp16
.wParam
;
354 mp16
.lParam
= cwp16
.lParam
;
357 WINPROC_UnmapMsg32WTo16( cwp32
->hwnd
, cwp32
->message
, cwp32
->wParam
,
358 cwp32
->lParam
, &mp16
);
360 WINPROC_UnmapMsg32ATo16( cwp32
->hwnd
, cwp32
->message
, cwp32
->wParam
,
361 cwp32
->lParam
, &mp16
);
370 CBT_CREATEWNDA
*cbtcw32
= (CBT_CREATEWNDA
*)lparam
;
371 CBT_CREATEWND16 cbtcw16
;
374 STRUCT32_CREATESTRUCT32Ato16( cbtcw32
->lpcs
, &cs16
);
375 cbtcw16
.lpcs
= (CREATESTRUCT16
*)MapLS( &cs16
);
376 cbtcw16
.hwndInsertAfter
= WIN_Handle16( cbtcw32
->hwndInsertAfter
);
377 lparam
= MapLS( &cbtcw16
);
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
);
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
);
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
);
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
);
432 RECT
*rect32
= (RECT
*)lparam
;
435 CONV_RECT32TO16( rect32
, &rect16
);
436 lparam
= MapLS( &rect16
);
437 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
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
);
463 DEBUGHOOKINFO
*dh32
= (DEBUGHOOKINFO
*)lparam
;
464 DEBUGHOOKINFO16 dh16
;
466 dh16
.hModuleHook
= 0; /* FIXME */
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
);
480 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
484 case WH_FOREGROUNDIDLE
:
485 case WH_CALLWNDPROCRET
:
487 FIXME("\t[%i] 32to16 translation unimplemented\n", id
);
488 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
495 /***********************************************************************
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
,
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
;
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
);
526 else /* Unicode to ASCII */
528 CBT_CREATEWNDW
*cbtcwW
= (CBT_CREATEWNDW
*)lparam
;
529 CBT_CREATEWNDA cbtcwA
;
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
);
550 /***********************************************************************
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
);
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
);
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
);
580 ret
= call_hook_32_to_32( data
->proc
, data
->id
, code
, wparam
,
581 lparam
, (type
== HOOK_WIN32W
) );
583 WIN_RestoreWndsLock(iWndsLocks
);
588 /***********************************************************************
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 /***********************************************************************
609 * Get the first hook for a given type.
611 static HANDLE16
HOOK_GetHook( INT16 id
)
616 if ((queue
= QUEUE_Current()) != NULL
)
617 hook
= queue
->hooks
[id
- WH_MINHOOK
];
618 if (!hook
) hook
= HOOK_systemHooks
[id
- WH_MINHOOK
];
623 /***********************************************************************
626 * Install a given hook.
628 static HHOOK
HOOK_SetHook( INT16 id
, LPVOID proc
, INT type
,
629 HMODULE16 hModule
, DWORD dwThreadId
)
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
)))
653 /* Create the hook structure */
655 if (!(handle
= USER_HEAP_ALLOC( sizeof(HOOKDATA
) ))) return 0;
656 data
= (HOOKDATA
*) USER_HEAP_LIN_ADDR( handle
);
659 data
->ownerQueue
= hQueue
;
660 data
->ownerModule
= hModule
;
663 /* Insert it in the correct linked list */
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
);
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 /***********************************************************************
687 * Remove a hook from the list.
689 static BOOL
HOOK_RemoveHook( HANDLE16 hook
)
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;
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
);
729 /***********************************************************************
732 static HANDLE16
HOOK_FindValidHook( HANDLE16 hook
)
738 if (!(data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
))) return 0;
739 if (data
->proc
) return hook
;
744 /***********************************************************************
747 * Call a hook procedure.
749 static LRESULT
HOOK_CallHook( HANDLE16 hook
, INT fromtype
, INT code
,
750 WPARAM wParam
, LPARAM lParam
)
754 HOOKDATA
*data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
);
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
);
774 /***********************************************************************
775 * Exported Functions & APIs
778 /***********************************************************************
781 * Replacement for calling HOOK_GetHook from other modules.
783 BOOL
HOOK_IsHooked( INT16 id
)
785 return HOOK_GetHook( id
) != 0;
789 /***********************************************************************
794 LRESULT
HOOK_CallHooks16( INT16 id
, INT16 code
, WPARAM16 wParam
,
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 /***********************************************************************
809 LRESULT
HOOK_CallHooksA( INT id
, INT code
, WPARAM wParam
,
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 /***********************************************************************
824 LRESULT
HOOK_CallHooksW( INT id
, INT code
, WPARAM wParam
,
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
,
836 /***********************************************************************
837 * HOOK_FreeModuleHooks
839 void HOOK_FreeModuleHooks( HMODULE16 hModule
)
841 /* remove all system hooks registered by this module */
847 for( id
= WH_MINHOOK
; id
<= WH_MAXHOOK
; id
++ )
849 hook
= HOOK_systemHooks
[id
- WH_MINHOOK
];
851 if( (hptr
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
)) )
854 if( hptr
->ownerModule
== hModule
)
856 hptr
->flags
&= HOOK_MAPTYPE
;
857 HOOK_RemoveHook(hook
);
865 /***********************************************************************
866 * HOOK_FreeQueueHooks
868 void HOOK_FreeQueueHooks(void)
870 /* remove all hooks registered by the current queue */
872 HOOKDATA
* hptr
= NULL
;
876 for( id
= WH_MINHOOK
; id
<= WH_MAXHOOK
; id
++ )
878 hook
= HOOK_GetHook( id
);
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
);
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
,
934 FIXME("WH_DEBUG is broken in 16-bit Windows.\n");
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
,
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
,
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
);
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
,
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
,
1033 INT fromtype
; /* figure out Ansi/Unicode */
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
,
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
);
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
);
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
))
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
))
1140 return HOOK_CallHooksW( WH_MSGFILTER
, code
, 0, (LPARAM
)msg
);