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' */
64 #define HHOOK_32(h) ((HHOOK)(h ? MAKELONG(h, HOOK_MAGIC) : 0))
65 #define HHOOK_16(h) ((HANDLE16)((HIWORD(h) == HOOK_MAGIC) ? LOWORD(h) : 0))
67 /* This should probably reside in USER heap */
68 static HANDLE16 HOOK_systemHooks
[WH_NB_HOOKS
] = { 0, };
70 /* ### start build ### */
71 extern LONG CALLBACK
HOOK_CallTo16_long_wwl(HOOKPROC16
,WORD
,WORD
,LONG
);
72 /* ### stop build ### */
75 /***********************************************************************
78 inline static LRESULT
call_hook_16( HOOKPROC16 proc
, INT id
, INT code
, WPARAM wparam
, LPARAM lparam
)
80 LRESULT ret
= HOOK_CallTo16_long_wwl( proc
, code
, wparam
, lparam
);
81 /* Grrr. While the hook procedure is supposed to have an LRESULT return
82 value even in Win16, it seems that for those hook types where the
83 return value is interpreted as BOOL, Windows doesn't actually check
84 the HIWORD ... Some buggy Win16 programs, notably WINFILE, rely on
85 that, because they neglect to clear DX ... */
86 if (id
!= WH_JOURNALPLAYBACK
) ret
= LOWORD( ret
);
91 /***********************************************************************
94 * Convert hook params to 32-bit and call 32-bit hook procedure
96 static LRESULT
call_hook_16_to_32( HOOKPROC proc
, INT id
, INT code
, WPARAM wparam
, LPARAM lparam
,
104 case WH_SYSMSGFILTER
:
105 case WH_JOURNALRECORD
:
107 MSG16
*msg16
= MapSL(lparam
);
110 STRUCT32_MSG16to32( msg16
, &msg32
);
111 ret
= proc( code
, wparam
, (LPARAM
)&msg32
);
117 MSG16
*msg16
= MapSL(lparam
);
120 STRUCT32_MSG16to32( msg16
, &msg32
);
121 ret
= proc( code
, wparam
, (LPARAM
)&msg32
);
122 STRUCT32_MSG32to16( &msg32
, msg16
);
126 case WH_JOURNALPLAYBACK
:
128 EVENTMSG16
*em16
= MapSL(lparam
);
131 em32
.message
= em16
->message
;
132 em32
.paramL
= em16
->paramL
;
133 em32
.paramH
= em16
->paramH
;
134 em32
.time
= em16
->time
;
135 em32
.hwnd
= 0; /* FIXME */
136 ret
= proc( code
, wparam
, (LPARAM
)&em32
);
142 CWPSTRUCT16
*cwp16
= MapSL(lparam
);
145 cwp32
.hwnd
= WIN_Handle32(cwp16
->hwnd
);
146 cwp32
.lParam
= cwp16
->lParam
;
149 WINPROC_MapMsg16To32W( cwp32
.hwnd
, cwp16
->message
, cwp16
->wParam
,
150 &cwp32
.message
, &cwp32
.wParam
, &cwp32
.lParam
);
152 WINPROC_MapMsg16To32A( cwp32
.hwnd
, cwp16
->message
, cwp16
->wParam
,
153 &cwp32
.message
, &cwp32
.wParam
, &cwp32
.lParam
);
155 ret
= proc( code
, wparam
, (LPARAM
)&cwp32
);
158 WINPROC_UnmapMsg16To32W( cwp32
.hwnd
, cwp32
.message
, cwp32
.wParam
, cwp32
.lParam
, 0 );
160 WINPROC_UnmapMsg16To32A( cwp32
.hwnd
, cwp32
.message
, cwp32
.wParam
, cwp32
.lParam
, 0 );
169 CBT_CREATEWNDA cbtcw32
;
171 CBT_CREATEWND16
*cbtcw16
= MapSL(lparam
);
172 CREATESTRUCT16
*cs16
= MapSL( (SEGPTR
)cbtcw16
->lpcs
);
174 cbtcw32
.lpcs
= &cs32
;
175 cbtcw32
.hwndInsertAfter
= WIN_Handle32( cbtcw16
->hwndInsertAfter
);
176 STRUCT32_CREATESTRUCT16to32A( cs16
, &cs32
);
180 cs32
.lpszName
= (LPSTR
)map_str_16_to_32W( cs16
->lpszName
);
181 cs32
.lpszClass
= (LPSTR
)map_str_16_to_32W( cs16
->lpszClass
);
182 ret
= proc( code
, wparam
, (LPARAM
)&cbtcw32
);
183 unmap_str_16_to_32W( (LPWSTR
)cs32
.lpszName
);
184 unmap_str_16_to_32W( (LPWSTR
)cs32
.lpszClass
);
188 cs32
.lpszName
= MapSL( cs16
->lpszName
);
189 cs32
.lpszClass
= MapSL( cs16
->lpszClass
);
190 ret
= proc( code
, wparam
, (LPARAM
)&cbtcw32
);
192 cbtcw16
->hwndInsertAfter
= HWND_16( cbtcw32
.hwndInsertAfter
);
197 CBTACTIVATESTRUCT16
*cas16
= MapSL(lparam
);
198 CBTACTIVATESTRUCT cas32
;
199 cas32
.fMouse
= cas16
->fMouse
;
200 cas32
.hWndActive
= WIN_Handle32(cas16
->hWndActive
);
201 ret
= proc( code
, wparam
, (LPARAM
)&cas32
);
204 case HCBT_CLICKSKIPPED
:
206 MOUSEHOOKSTRUCT16
*ms16
= MapSL(lparam
);
207 MOUSEHOOKSTRUCT ms32
;
209 ms32
.pt
.x
= ms16
->pt
.x
;
210 ms32
.pt
.y
= ms16
->pt
.y
;
211 /* wHitTestCode may be negative, so convince compiler to do
212 correct sign extension. Yay. :| */
213 ms32
.wHitTestCode
= (INT
)(INT16
)ms16
->wHitTestCode
;
214 ms32
.dwExtraInfo
= ms16
->dwExtraInfo
;
215 ms32
.hwnd
= WIN_Handle32( ms16
->hwnd
);
216 ret
= proc( code
, wparam
, (LPARAM
)&ms32
);
221 RECT16
*rect16
= MapSL(lparam
);
224 CONV_RECT16TO32( rect16
, &rect32
);
225 ret
= proc( code
, wparam
, (LPARAM
)&rect32
);
233 MOUSEHOOKSTRUCT16
*ms16
= MapSL(lparam
);
234 MOUSEHOOKSTRUCT ms32
;
236 ms32
.pt
.x
= ms16
->pt
.x
;
237 ms32
.pt
.y
= ms16
->pt
.y
;
238 /* wHitTestCode may be negative, so convince compiler to do
239 correct sign extension. Yay. :| */
240 ms32
.wHitTestCode
= (INT
)((INT16
)ms16
->wHitTestCode
);
241 ms32
.dwExtraInfo
= ms16
->dwExtraInfo
;
242 ms32
.hwnd
= WIN_Handle32(ms16
->hwnd
);
243 ret
= proc( code
, wparam
, (LPARAM
)&ms32
);
249 DEBUGHOOKINFO16
*dh16
= MapSL(lparam
);
252 dh32
.idThread
= 0; /* FIXME */
253 dh32
.idThreadInstaller
= 0; /* FIXME */
254 dh32
.lParam
= dh16
->lParam
; /* FIXME Check for sign ext */
255 dh32
.wParam
= dh16
->wParam
;
256 dh32
.code
= dh16
->code
;
258 /* do sign extension if it was WH_MSGFILTER */
259 if (wparam
== 0xffff) wparam
= WH_MSGFILTER
;
260 ret
= proc( code
, wparam
, (LPARAM
)&dh32
);
266 ret
= proc( code
, wparam
, lparam
);
270 case WH_FOREGROUNDIDLE
:
271 case WH_CALLWNDPROCRET
:
273 FIXME("\t[%i] 16to32 translation unimplemented\n", id
);
274 ret
= proc( code
, wparam
, lparam
);
281 /***********************************************************************
284 * Convert hook params to 16-bit and call 16-bit hook procedure
286 static LRESULT
call_hook_32_to_16( HOOKPROC16 proc
, INT id
, INT code
, WPARAM wparam
, LPARAM lparam
,
294 case WH_SYSMSGFILTER
:
295 case WH_JOURNALRECORD
:
297 MSG
*msg32
= (MSG
*)lparam
;
300 STRUCT32_MSG32to16( msg32
, &msg16
);
301 lparam
= MapLS( &msg16
);
302 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
309 MSG
*msg32
= (MSG
*)lparam
;
312 STRUCT32_MSG32to16( msg32
, &msg16
);
313 lparam
= MapLS( &msg16
);
314 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
316 STRUCT32_MSG16to32( &msg16
, msg32
);
320 case WH_JOURNALPLAYBACK
:
322 EVENTMSG
*em32
= (EVENTMSG
*)lparam
;
325 em16
.message
= em32
->message
;
326 em16
.paramL
= em32
->paramL
;
327 em16
.paramH
= em32
->paramH
;
328 em16
.time
= em32
->time
;
329 lparam
= MapLS( &em16
);
330 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
337 CWPSTRUCT
*cwp32
= (CWPSTRUCT
*)lparam
;
341 cwp16
.hwnd
= HWND_16(cwp32
->hwnd
);
342 cwp16
.lParam
= cwp32
->lParam
;
345 WINPROC_MapMsg32WTo16( cwp32
->hwnd
, cwp32
->message
, cwp32
->wParam
,
346 &cwp16
.message
, &cwp16
.wParam
, &cwp16
.lParam
);
348 WINPROC_MapMsg32ATo16( cwp32
->hwnd
, cwp32
->message
, cwp32
->wParam
,
349 &cwp16
.message
, &cwp16
.wParam
, &cwp16
.lParam
);
351 lparam
= MapLS( &cwp16
);
352 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
355 mp16
.wParam
= cwp16
.wParam
;
356 mp16
.lParam
= cwp16
.lParam
;
359 WINPROC_UnmapMsg32WTo16( cwp32
->hwnd
, cwp32
->message
, cwp32
->wParam
,
360 cwp32
->lParam
, &mp16
);
362 WINPROC_UnmapMsg32ATo16( cwp32
->hwnd
, cwp32
->message
, cwp32
->wParam
,
363 cwp32
->lParam
, &mp16
);
372 CBT_CREATEWNDA
*cbtcw32
= (CBT_CREATEWNDA
*)lparam
;
373 CBT_CREATEWND16 cbtcw16
;
376 STRUCT32_CREATESTRUCT32Ato16( cbtcw32
->lpcs
, &cs16
);
377 cbtcw16
.lpcs
= (CREATESTRUCT16
*)MapLS( &cs16
);
378 cbtcw16
.hwndInsertAfter
= HWND_16( cbtcw32
->hwndInsertAfter
);
379 lparam
= MapLS( &cbtcw16
);
383 cs16
.lpszName
= map_str_32W_to_16( (LPWSTR
)cbtcw32
->lpcs
->lpszName
);
384 cs16
.lpszClass
= map_str_32W_to_16( (LPWSTR
)cbtcw32
->lpcs
->lpszClass
);
385 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
386 unmap_str_32W_to_16( cs16
.lpszName
);
387 unmap_str_32W_to_16( cs16
.lpszClass
);
391 cs16
.lpszName
= MapLS( cbtcw32
->lpcs
->lpszName
);
392 cs16
.lpszClass
= MapLS( cbtcw32
->lpcs
->lpszClass
);
393 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
394 UnMapLS( cs16
.lpszName
);
395 UnMapLS( cs16
.lpszClass
);
397 cbtcw32
->hwndInsertAfter
= WIN_Handle32( cbtcw16
.hwndInsertAfter
);
398 UnMapLS( (SEGPTR
)cbtcw16
.lpcs
);
405 CBTACTIVATESTRUCT
*cas32
= (CBTACTIVATESTRUCT
*)lparam
;
406 CBTACTIVATESTRUCT16 cas16
;
408 cas16
.fMouse
= cas32
->fMouse
;
409 cas16
.hWndActive
= HWND_16( cas32
->hWndActive
);
411 lparam
= MapLS( &cas16
);
412 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
416 case HCBT_CLICKSKIPPED
:
418 MOUSEHOOKSTRUCT
*ms32
= (MOUSEHOOKSTRUCT
*)lparam
;
419 MOUSEHOOKSTRUCT16 ms16
;
421 ms16
.pt
.x
= ms32
->pt
.x
;
422 ms16
.pt
.y
= ms32
->pt
.y
;
423 ms16
.hwnd
= HWND_16( ms32
->hwnd
);
424 ms16
.wHitTestCode
= ms32
->wHitTestCode
;
425 ms16
.dwExtraInfo
= ms32
->dwExtraInfo
;
427 lparam
= MapLS( &ms16
);
428 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
434 RECT
*rect32
= (RECT
*)lparam
;
437 CONV_RECT32TO16( rect32
, &rect16
);
438 lparam
= MapLS( &rect16
);
439 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
448 MOUSEHOOKSTRUCT
*ms32
= (MOUSEHOOKSTRUCT
*)lparam
;
449 MOUSEHOOKSTRUCT16 ms16
;
451 ms16
.pt
.x
= ms32
->pt
.x
;
452 ms16
.pt
.y
= ms32
->pt
.y
;
453 ms16
.hwnd
= HWND_16( ms32
->hwnd
);
454 ms16
.wHitTestCode
= ms32
->wHitTestCode
;
455 ms16
.dwExtraInfo
= ms32
->dwExtraInfo
;
457 lparam
= MapLS( &ms16
);
458 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
465 DEBUGHOOKINFO
*dh32
= (DEBUGHOOKINFO
*)lparam
;
466 DEBUGHOOKINFO16 dh16
;
468 dh16
.hModuleHook
= 0; /* FIXME */
470 dh16
.lParam
= dh32
->lParam
;
471 dh16
.wParam
= dh32
->wParam
;
472 dh16
.code
= dh32
->code
;
474 lparam
= MapLS( &dh16
);
475 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
482 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
486 case WH_FOREGROUNDIDLE
:
487 case WH_CALLWNDPROCRET
:
489 FIXME("\t[%i] 32to16 translation unimplemented\n", id
);
490 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
497 /***********************************************************************
500 * Convert hook params to/from Unicode and call hook procedure
502 static LRESULT
call_hook_32_to_32( HOOKPROC proc
, INT id
, INT code
, WPARAM wparam
, LPARAM lparam
,
505 if (id
!= WH_CBT
|| code
!= HCBT_CREATEWND
) return proc( code
, wparam
, lparam
);
507 if (to_unicode
) /* ASCII to Unicode */
509 CBT_CREATEWNDA
*cbtcwA
= (CBT_CREATEWNDA
*)lparam
;
510 CBT_CREATEWNDW cbtcwW
;
515 cbtcwW
.hwndInsertAfter
= cbtcwA
->hwndInsertAfter
;
516 csW
= *(CREATESTRUCTW
*)cbtcwA
->lpcs
;
518 if (HIWORD(cbtcwA
->lpcs
->lpszName
))
519 csW
.lpszName
= HEAP_strdupAtoW( GetProcessHeap(), 0, cbtcwA
->lpcs
->lpszName
);
520 if (HIWORD(cbtcwA
->lpcs
->lpszClass
))
521 csW
.lpszClass
= HEAP_strdupAtoW( GetProcessHeap(), 0, cbtcwA
->lpcs
->lpszClass
);
522 ret
= proc( code
, wparam
, (LPARAM
)&cbtcwW
);
523 cbtcwA
->hwndInsertAfter
= cbtcwW
.hwndInsertAfter
;
524 if (HIWORD(csW
.lpszName
)) HeapFree( GetProcessHeap(), 0, (LPWSTR
)csW
.lpszName
);
525 if (HIWORD(csW
.lpszClass
)) HeapFree( GetProcessHeap(), 0, (LPWSTR
)csW
.lpszClass
);
528 else /* Unicode to ASCII */
530 CBT_CREATEWNDW
*cbtcwW
= (CBT_CREATEWNDW
*)lparam
;
531 CBT_CREATEWNDA cbtcwA
;
536 cbtcwA
.hwndInsertAfter
= cbtcwW
->hwndInsertAfter
;
537 csA
= *(CREATESTRUCTA
*)cbtcwW
->lpcs
;
539 if (HIWORD(cbtcwW
->lpcs
->lpszName
))
540 csA
.lpszName
= HEAP_strdupWtoA( GetProcessHeap(), 0, cbtcwW
->lpcs
->lpszName
);
541 if (HIWORD(cbtcwW
->lpcs
->lpszClass
))
542 csA
.lpszClass
= HEAP_strdupWtoA( GetProcessHeap(), 0, cbtcwW
->lpcs
->lpszClass
);
543 ret
= proc( code
, wparam
, (LPARAM
)&cbtcwA
);
544 cbtcwW
->hwndInsertAfter
= cbtcwA
.hwndInsertAfter
;
545 if (HIWORD(csA
.lpszName
)) HeapFree( GetProcessHeap(), 0, (LPSTR
)csA
.lpszName
);
546 if (HIWORD(csA
.lpszClass
)) HeapFree( GetProcessHeap(), 0, (LPSTR
)csA
.lpszClass
);
552 /***********************************************************************
555 * Call a hook procedure.
557 inline static LRESULT
call_hook( HOOKDATA
*data
, INT fromtype
, INT code
,
558 WPARAM wparam
, LPARAM lparam
)
560 INT type
= (data
->flags
& HOOK_MAPTYPE
);
563 /* Suspend window structure locks before calling user code */
564 int iWndsLocks
= WIN_SuspendWndsLock();
566 if (type
== HOOK_WIN16
)
568 if (fromtype
== HOOK_WIN16
) /* 16->16 */
569 ret
= call_hook_16( (HOOKPROC16
)data
->proc
, data
->id
, code
, wparam
, lparam
);
571 ret
= call_hook_32_to_16( (HOOKPROC16
)data
->proc
, data
->id
, code
, wparam
,
572 lparam
, (type
== HOOK_WIN32W
) );
574 else if (fromtype
== HOOK_WIN16
) /* 16->32 */
575 ret
= call_hook_16_to_32( data
->proc
, data
->id
, code
, wparam
,
576 lparam
, (type
== HOOK_WIN32W
) );
577 else /* 32->32, check unicode */
579 if (type
== fromtype
)
580 ret
= data
->proc( code
, wparam
, lparam
);
582 ret
= call_hook_32_to_32( data
->proc
, data
->id
, code
, wparam
,
583 lparam
, (type
== HOOK_WIN32W
) );
585 WIN_RestoreWndsLock(iWndsLocks
);
590 /***********************************************************************
593 * Get the next hook of a given hook.
595 static HHOOK
HOOK_GetNextHook( HHOOK hook
)
597 HOOKDATA
*data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(HHOOK_16(hook
));
599 if (!data
|| !hook
) return 0;
600 if (data
->next
) return HHOOK_32(data
->next
);
601 if (!data
->ownerQueue
) return 0; /* Already system hook */
603 /* Now start enumerating the system hooks */
604 return HHOOK_32(HOOK_systemHooks
[data
->id
- WH_MINHOOK
]);
608 /***********************************************************************
611 * Get the first hook for a given type.
613 static HHOOK
HOOK_GetHook( INT16 id
)
618 if ((queue
= QUEUE_Current()) != NULL
)
619 handle
= queue
->hooks
[id
- WH_MINHOOK
];
620 if (!handle
) handle
= HOOK_systemHooks
[id
- WH_MINHOOK
];
621 return HHOOK_32(handle
);
625 /***********************************************************************
628 * Install a given hook.
630 static HHOOK
HOOK_SetHook( INT16 id
, LPVOID proc
, INT type
,
631 HMODULE16 hModule
, DWORD dwThreadId
)
637 if ((id
< WH_MINHOOK
) || (id
> WH_MAXHOOK
)) return 0;
639 TRACE("Setting hook %d: %08x %04x %08lx\n",
640 id
, (UINT
)proc
, hModule
, dwThreadId
);
642 /* Create task queue if none present */
643 InitThreadInput16( 0, 0 );
645 if (id
== WH_JOURNALPLAYBACK
) EnableHardwareInput16(FALSE
);
647 if (dwThreadId
) /* Task-specific hook */
649 if ((id
== WH_JOURNALRECORD
) || (id
== WH_JOURNALPLAYBACK
) ||
650 (id
== WH_SYSMSGFILTER
)) return 0; /* System-only hooks */
651 if (!(hQueue
= GetThreadQueue16( dwThreadId
)))
655 /* Create the hook structure */
657 if (!(handle
= USER_HEAP_ALLOC( sizeof(HOOKDATA
) ))) return 0;
658 data
= (HOOKDATA
*) USER_HEAP_LIN_ADDR( handle
);
661 data
->ownerQueue
= hQueue
;
662 data
->ownerModule
= hModule
;
665 /* Insert it in the correct linked list */
669 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)QUEUE_Lock( hQueue
);
670 data
->next
= queue
->hooks
[id
- WH_MINHOOK
];
671 queue
->hooks
[id
- WH_MINHOOK
] = handle
;
672 QUEUE_Unlock( queue
);
676 data
->next
= HOOK_systemHooks
[id
- WH_MINHOOK
];
677 HOOK_systemHooks
[id
- WH_MINHOOK
] = handle
;
679 TRACE("Setting hook %d: ret=%04x [next=%04x]\n",
680 id
, handle
, data
->next
);
682 return HHOOK_32(handle
);
686 /***********************************************************************
689 * Remove a hook from the list.
691 static BOOL
HOOK_RemoveHook( HHOOK hook
)
694 HANDLE16
*prevHandle
;
696 TRACE("Removing hook %04x\n", hook
);
698 if (!(data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(HHOOK_16(hook
)))) return FALSE
;
699 if (data
->flags
& HOOK_INUSE
)
701 /* Mark it for deletion later on */
702 WARN("Hook still running, deletion delayed\n" );
703 data
->proc
= (HOOKPROC
)0;
707 if (data
->id
== WH_JOURNALPLAYBACK
) EnableHardwareInput16(TRUE
);
709 /* Remove it from the linked list */
711 if (data
->ownerQueue
)
713 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)QUEUE_Lock( data
->ownerQueue
);
714 if (!queue
) return FALSE
;
715 prevHandle
= &queue
->hooks
[data
->id
- WH_MINHOOK
];
716 QUEUE_Unlock( queue
);
718 else prevHandle
= &HOOK_systemHooks
[data
->id
- WH_MINHOOK
];
720 while (*prevHandle
&& *prevHandle
!= HHOOK_16(hook
))
721 prevHandle
= &((HOOKDATA
*)USER_HEAP_LIN_ADDR(*prevHandle
))->next
;
723 if (!*prevHandle
) return FALSE
;
724 *prevHandle
= data
->next
;
726 USER_HEAP_FREE(HHOOK_16(hook
));
731 /***********************************************************************
734 static HHOOK
HOOK_FindValidHook( HHOOK hook
)
740 if (!(data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(HHOOK_16(hook
)))) return 0;
741 if (data
->proc
) return hook
;
742 hook
= HHOOK_32(data
->next
);
746 /***********************************************************************
749 * Call a hook procedure.
751 static LRESULT
HOOK_CallHook( HHOOK hook
, INT fromtype
, INT code
,
752 WPARAM wParam
, LPARAM lParam
)
756 HOOKDATA
*data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(HHOOK_16(hook
));
759 if (!(queue
= QUEUE_Current())) return 0;
760 prevHandle
= queue
->hCurHook
;
761 queue
->hCurHook
= HHOOK_16(hook
);
763 TRACE("Calling hook %04x: %d %08x %08lx\n", hook
, code
, wParam
, lParam
);
765 data
->flags
|= HOOK_INUSE
;
766 ret
= call_hook( data
, fromtype
, code
, wParam
, lParam
);
767 data
->flags
&= ~HOOK_INUSE
;
769 TRACE("Ret hook %04x = %08lx\n", hook
, ret
);
771 queue
->hCurHook
= prevHandle
;
772 if (!data
->proc
) HOOK_RemoveHook( hook
);
776 /***********************************************************************
777 * Exported Functions & APIs
780 /***********************************************************************
783 * Replacement for calling HOOK_GetHook from other modules.
785 BOOL
HOOK_IsHooked( INT16 id
)
787 return HOOK_GetHook( id
) != 0;
791 /***********************************************************************
796 LRESULT
HOOK_CallHooks16( INT16 id
, INT16 code
, WPARAM16 wParam
,
801 if (!(hook
= HOOK_GetHook( id
))) return 0;
802 if (!(hook
= HOOK_FindValidHook(hook
))) return 0;
803 return HOOK_CallHook( hook
, HOOK_WIN16
, code
, wParam
, lParam
);
806 /***********************************************************************
811 LRESULT
HOOK_CallHooksA( INT id
, INT code
, WPARAM wParam
,
816 if (!(hook
= HOOK_GetHook( id
))) return 0;
817 if (!(hook
= HOOK_FindValidHook(hook
))) return 0;
818 return HOOK_CallHook( hook
, HOOK_WIN32A
, code
, wParam
, lParam
);
821 /***********************************************************************
826 LRESULT
HOOK_CallHooksW( INT id
, INT code
, WPARAM wParam
,
831 if (!(hook
= HOOK_GetHook( id
))) return 0;
832 if (!(hook
= HOOK_FindValidHook(hook
))) return 0;
833 return HOOK_CallHook( hook
, HOOK_WIN32W
, code
, wParam
,
838 /***********************************************************************
839 * HOOK_FreeModuleHooks
841 void HOOK_FreeModuleHooks( HMODULE16 hModule
)
843 /* remove all system hooks registered by this module */
846 HANDLE16 handle
, next
;
849 for( id
= WH_MINHOOK
; id
<= WH_MAXHOOK
; id
++ )
851 handle
= HOOK_systemHooks
[id
- WH_MINHOOK
];
853 if( (hptr
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(handle
)) )
856 if( hptr
->ownerModule
== hModule
)
858 hptr
->flags
&= HOOK_MAPTYPE
;
859 HOOK_RemoveHook(HHOOK_32(handle
));
867 /***********************************************************************
868 * HOOK_FreeQueueHooks
870 void HOOK_FreeQueueHooks(void)
872 /* remove all hooks registered by the current queue */
874 HOOKDATA
* hptr
= NULL
;
878 for( id
= WH_MINHOOK
; id
<= WH_MAXHOOK
; id
++ )
880 hook
= HOOK_GetHook( id
);
883 next
= HOOK_GetNextHook(hook
);
885 hptr
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(HHOOK_16(hook
));
886 if( hptr
&& hptr
->ownerQueue
)
888 hptr
->flags
&= HOOK_MAPTYPE
;
889 HOOK_RemoveHook(hook
);
897 /***********************************************************************
898 * SetWindowsHook (USER.121)
900 FARPROC16 WINAPI
SetWindowsHook16( INT16 id
, HOOKPROC16 proc
)
902 HINSTANCE16 hInst
= FarGetOwner16( HIWORD(proc
) );
904 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
905 HTASK16 hTask
= (id
== WH_MSGFILTER
) ? GetCurrentTask() : 0;
907 return (FARPROC16
)SetWindowsHookEx16( id
, proc
, hInst
, hTask
);
910 /***********************************************************************
911 * SetWindowsHookA (USER32.@)
913 HHOOK WINAPI
SetWindowsHookA( INT id
, HOOKPROC proc
)
915 return SetWindowsHookExA( id
, proc
, 0, GetCurrentThreadId() );
918 /***********************************************************************
919 * SetWindowsHookW (USER32.@)
921 HHOOK WINAPI
SetWindowsHookW( INT id
, HOOKPROC proc
)
923 return SetWindowsHookExW( id
, proc
, 0, GetCurrentThreadId() );
927 /***********************************************************************
928 * SetWindowsHookEx (USER.291)
930 HHOOK WINAPI
SetWindowsHookEx16( INT16 id
, HOOKPROC16 proc
, HINSTANCE16 hInst
,
935 FIXME("WH_DEBUG is broken in 16-bit Windows.\n");
938 return HOOK_SetHook( id
, proc
, HOOK_WIN16
, GetExePtr(hInst
), (DWORD
)hTask
);
941 /***********************************************************************
942 * SetWindowsHookExA (USER32.@)
944 HHOOK WINAPI
SetWindowsHookExA( INT id
, HOOKPROC proc
, HINSTANCE hInst
,
947 return HOOK_SetHook( id
, proc
, HOOK_WIN32A
, MapHModuleLS(hInst
), dwThreadId
);
950 /***********************************************************************
951 * SetWindowsHookExW (USER32.@)
953 HHOOK WINAPI
SetWindowsHookExW( INT id
, HOOKPROC proc
, HINSTANCE hInst
,
956 return HOOK_SetHook( id
, proc
, HOOK_WIN32W
, MapHModuleLS(hInst
), dwThreadId
);
960 /***********************************************************************
961 * UnhookWindowsHook (USER.234)
963 BOOL16 WINAPI
UnhookWindowsHook16( INT16 id
, HOOKPROC16 proc
)
965 return UnhookWindowsHook( id
, (HOOKPROC
)proc
);
968 /***********************************************************************
969 * UnhookWindowsHook (USER32.@)
971 BOOL WINAPI
UnhookWindowsHook( INT id
, HOOKPROC proc
)
973 HHOOK hook
= HOOK_GetHook( id
);
975 TRACE("%d %08lx\n", id
, (DWORD
)proc
);
979 HOOKDATA
*data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(HHOOK_16(hook
));
980 if (data
->proc
== proc
) break;
981 hook
= HOOK_GetNextHook( hook
);
983 if (!hook
) return FALSE
;
984 return HOOK_RemoveHook( hook
);
988 /***********************************************************************
989 * UnhookWindowsHookEx (USER.292)
991 BOOL16 WINAPI
UnhookWindowsHookEx16( HHOOK hhook
)
993 return HOOK_RemoveHook(hhook
);
996 /***********************************************************************
997 * UnhookWindowsHookEx (USER32.@)
999 BOOL WINAPI
UnhookWindowsHookEx( HHOOK hhook
)
1001 return HOOK_RemoveHook(hhook
);
1005 /***********************************************************************
1006 * CallNextHookEx (USER.293)
1008 * I wouldn't have separated this into 16 and 32 bit versions, but I
1009 * need a way to figure out if I need to do a mapping or not.
1011 LRESULT WINAPI
CallNextHookEx16( HHOOK hhook
, INT16 code
, WPARAM16 wParam
,
1016 if (!(next
= HOOK_GetNextHook(hhook
))) return 0;
1018 return HOOK_CallHook( next
, HOOK_WIN16
, code
, wParam
, lParam
);
1022 /***********************************************************************
1023 * CallNextHookEx (USER32.@)
1025 * There aren't ANSI and UNICODE versions of this.
1027 LRESULT WINAPI
CallNextHookEx( HHOOK hhook
, INT code
, WPARAM wParam
,
1031 INT fromtype
; /* figure out Ansi/Unicode */
1034 if (!(next
= HOOK_GetNextHook(hhook
))) return 0;
1036 oldhook
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(HHOOK_16(hhook
));
1037 fromtype
= oldhook
->flags
& HOOK_MAPTYPE
;
1039 if (fromtype
== HOOK_WIN16
)
1040 ERR("called from 16bit hook!\n");
1042 return HOOK_CallHook( next
, fromtype
, code
, wParam
, lParam
);
1046 /***********************************************************************
1047 * DefHookProc (USER.235)
1049 LRESULT WINAPI
DefHookProc16( INT16 code
, WPARAM16 wParam
, LPARAM lParam
,
1052 /* Note: the *hhook parameter is never used, since we rely on the
1053 * current hook value from the task queue to find the next hook. */
1054 MESSAGEQUEUE
*queue
;
1056 if (!(queue
= QUEUE_Current())) return 0;
1057 return CallNextHookEx16(HHOOK_32(queue
->hCurHook
), code
, wParam
, lParam
);
1061 /***********************************************************************
1062 * CallMsgFilter (USER.123)
1064 BOOL16 WINAPI
CallMsgFilter16( SEGPTR msg
, INT16 code
)
1066 if (GetSysModalWindow16()) return FALSE
;
1067 if (HOOK_CallHooks16( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)msg
)) return TRUE
;
1068 return HOOK_CallHooks16( WH_MSGFILTER
, code
, 0, (LPARAM
)msg
);
1072 /***********************************************************************
1073 * CallMsgFilter32 (USER.823)
1075 BOOL16 WINAPI
CallMsgFilter32_16( SEGPTR msg16_32
, INT16 code
, BOOL16 wHaveParamHigh
)
1077 MSG32_16
*lpmsg16_32
= MapSL(msg16_32
);
1079 if (wHaveParamHigh
== FALSE
)
1081 lpmsg16_32
->wParamHigh
= 0;
1082 /* WARNING: msg16_32->msg has to be the first variable in the struct */
1083 return CallMsgFilter16(msg16_32
, code
);
1090 msg32
.hwnd
= WIN_Handle32( lpmsg16_32
->msg
.hwnd
);
1091 msg32
.message
= lpmsg16_32
->msg
.message
;
1092 msg32
.wParam
= MAKELONG(lpmsg16_32
->msg
.wParam
, lpmsg16_32
->wParamHigh
);
1093 msg32
.lParam
= lpmsg16_32
->msg
.lParam
;
1094 msg32
.time
= lpmsg16_32
->msg
.time
;
1095 msg32
.pt
.x
= lpmsg16_32
->msg
.pt
.x
;
1096 msg32
.pt
.y
= lpmsg16_32
->msg
.pt
.y
;
1098 ret
= (BOOL16
)CallMsgFilterA(&msg32
, (INT
)code
);
1100 lpmsg16_32
->msg
.hwnd
= HWND_16( msg32
.hwnd
);
1101 lpmsg16_32
->msg
.message
= msg32
.message
;
1102 lpmsg16_32
->msg
.wParam
= LOWORD(msg32
.wParam
);
1103 lpmsg16_32
->msg
.lParam
= msg32
.lParam
;
1104 lpmsg16_32
->msg
.time
= msg32
.time
;
1105 lpmsg16_32
->msg
.pt
.x
= msg32
.pt
.x
;
1106 lpmsg16_32
->msg
.pt
.y
= msg32
.pt
.y
;
1107 lpmsg16_32
->wParamHigh
= HIWORD(msg32
.wParam
);
1114 /***********************************************************************
1115 * CallMsgFilterA (USER32.@)
1117 * FIXME: There are ANSI and UNICODE versions of this, plus an unspecified
1118 * version, plus USER (the 16bit one) has a CallMsgFilter32 function.
1120 BOOL WINAPI
CallMsgFilterA( LPMSG msg
, INT code
)
1122 if (GetSysModalWindow16()) return FALSE
; /* ??? */
1123 if (HOOK_CallHooksA( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)msg
))
1125 return HOOK_CallHooksA( WH_MSGFILTER
, code
, 0, (LPARAM
)msg
);
1129 /***********************************************************************
1130 * CallMsgFilterW (USER32.@)
1132 BOOL WINAPI
CallMsgFilterW( LPMSG msg
, INT code
)
1134 if (GetSysModalWindow16()) return FALSE
; /* ??? */
1135 if (HOOK_CallHooksW( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)msg
))
1137 return HOOK_CallHooksW( WH_MSGFILTER
, code
, 0, (LPARAM
)msg
);
1141 /***********************************************************************
1142 * SetWinEventHook [USER32.@]
1144 * Set up an event hook for a set of events.
1147 * dwMin [I] Lowest event handled by pfnProc
1148 * dwMax [I] Highest event handled by pfnProc
1149 * hModule [I] DLL containing pfnProc
1150 * pfnProc [I] Callback event hook function
1151 * dwProcess [I] Process to get events from, or 0 for all processes
1152 * dwThread [I] Thread to get events from, or 0 for all threads
1153 * dwFlags [I] Flags indicating the status of pfnProc
1156 * Success: A handle representing the hook.
1157 * Failure: A NULL handle.
1162 HWINEVENTHOOK WINAPI
SetWinEventHook(DWORD dwMin
, DWORD dwMax
, HMODULE hModule
,
1163 WINEVENTPROC pfnProc
, DWORD dwProcess
,
1164 DWORD dwThread
, DWORD dwFlags
)
1166 FIXME("(%ld,%ld,0x%08x,%p,%ld,%ld,0x%08lx)-stub!\n", dwMin
, dwMax
, hModule
,
1167 pfnProc
, dwProcess
, dwThread
, dwFlags
);
1169 return (HWINEVENTHOOK
)0;
1172 /***********************************************************************
1173 * UnhookWinEvent [USER32.@]
1175 * Remove an event hook for a set of events.
1178 * hEventHook [I] Event hook to remove
1181 * Success: TRUE. The event hook has been removed.
1182 * Failure: FALSE, if hEventHook is invalid.
1187 BOOL WINAPI
UnhookWinEvent(HWINEVENTHOOK hEventHook
)
1189 FIXME("(%p)-stub!\n", (void*)hEventHook
);
1197 /***********************************************************************
1198 * NotifyWinEvent [USER32.@]
1200 * Inform the OS that an event has occurred.
1203 * dwEvent [I] Id of the event
1204 * hWnd [I] Window holding the object that created the event
1205 * nId [I] Type of object that created the event
1206 * nChildId [I] Child object of nId, or CHILDID_SELF.
1214 VOID WINAPI
NotifyWinEvent(DWORD dwEvent
, HWND hWnd
, LONG nId
, LONG nChildId
)
1216 FIXME("(%ld,0x%08x,%ld,%ld)-stub!\n", dwEvent
, hWnd
, nId
, nChildId
);
1219 /***********************************************************************
1220 * IsWinEventHookInstalled [USER32.@]
1222 * Determine if an event hook is installed for an event.
1225 * dwEvent [I] Id of the event
1228 * TRUE, If there are any hooks installed for the event.
1234 BOOL WINAPI
IsWinEventHookInstalled(DWORD dwEvent
)
1236 FIXME("(%ld)-stub!\n", dwEvent
);