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"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(hook
);
51 /* Hook data (pointed to by a HHOOK) */
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 */
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))
68 /* This should probably reside in USER heap */
69 static HANDLE16 HOOK_systemHooks
[WH_NB_HOOKS
] = { 0, };
71 /* ### start build ### */
72 extern LONG CALLBACK
HOOK_CallTo16_long_wwl(HOOKPROC16
,WORD
,WORD
,LONG
);
73 /* ### stop build ### */
76 /***********************************************************************
79 inline static LRESULT
call_hook_16( HOOKPROC16 proc
, INT id
, INT code
, WPARAM wparam
, LPARAM lparam
)
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
);
92 /***********************************************************************
95 * Convert hook params to 32-bit and call 32-bit hook procedure
97 static LRESULT
call_hook_16_to_32( HOOKPROC proc
, INT id
, INT code
, WPARAM wparam
, LPARAM lparam
,
105 case WH_SYSMSGFILTER
:
106 case WH_JOURNALRECORD
:
108 MSG16
*msg16
= MapSL(lparam
);
111 STRUCT32_MSG16to32( msg16
, &msg32
);
112 ret
= proc( code
, wparam
, (LPARAM
)&msg32
);
118 MSG16
*msg16
= MapSL(lparam
);
121 STRUCT32_MSG16to32( msg16
, &msg32
);
122 ret
= proc( code
, wparam
, (LPARAM
)&msg32
);
123 STRUCT32_MSG32to16( &msg32
, msg16
);
127 case WH_JOURNALPLAYBACK
:
129 EVENTMSG16
*em16
= MapSL(lparam
);
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
);
143 CWPSTRUCT16
*cwp16
= MapSL(lparam
);
146 cwp32
.hwnd
= WIN_Handle32(cwp16
->hwnd
);
147 cwp32
.lParam
= cwp16
->lParam
;
150 WINPROC_MapMsg16To32W( cwp32
.hwnd
, cwp16
->message
, cwp16
->wParam
,
151 &cwp32
.message
, &cwp32
.wParam
, &cwp32
.lParam
);
153 WINPROC_MapMsg16To32A( cwp32
.hwnd
, cwp16
->message
, cwp16
->wParam
,
154 &cwp32
.message
, &cwp32
.wParam
, &cwp32
.lParam
);
156 ret
= proc( code
, wparam
, (LPARAM
)&cwp32
);
159 WINPROC_UnmapMsg16To32W( cwp32
.hwnd
, cwp32
.message
, cwp32
.wParam
, cwp32
.lParam
, 0 );
161 WINPROC_UnmapMsg16To32A( cwp32
.hwnd
, cwp32
.message
, cwp32
.wParam
, cwp32
.lParam
, 0 );
170 CBT_CREATEWNDA cbtcw32
;
172 CBT_CREATEWND16
*cbtcw16
= MapSL(lparam
);
173 CREATESTRUCT16
*cs16
= MapSL( (SEGPTR
)cbtcw16
->lpcs
);
175 cbtcw32
.lpcs
= &cs32
;
176 cbtcw32
.hwndInsertAfter
= WIN_Handle32( cbtcw16
->hwndInsertAfter
);
177 STRUCT32_CREATESTRUCT16to32A( cs16
, &cs32
);
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
);
189 cs32
.lpszName
= MapSL( cs16
->lpszName
);
190 cs32
.lpszClass
= MapSL( cs16
->lpszClass
);
191 ret
= proc( code
, wparam
, (LPARAM
)&cbtcw32
);
193 cbtcw16
->hwndInsertAfter
= HWND_16( cbtcw32
.hwndInsertAfter
);
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
);
205 case HCBT_CLICKSKIPPED
:
207 MOUSEHOOKSTRUCT16
*ms16
= MapSL(lparam
);
208 MOUSEHOOKSTRUCT ms32
;
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
);
222 RECT16
*rect16
= MapSL(lparam
);
225 CONV_RECT16TO32( rect16
, &rect32
);
226 ret
= proc( code
, wparam
, (LPARAM
)&rect32
);
234 MOUSEHOOKSTRUCT16
*ms16
= MapSL(lparam
);
235 MOUSEHOOKSTRUCT ms32
;
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
);
250 DEBUGHOOKINFO16
*dh16
= MapSL(lparam
);
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
;
259 /* do sign extension if it was WH_MSGFILTER */
260 if (wparam
== 0xffff) wparam
= WH_MSGFILTER
;
261 ret
= proc( code
, wparam
, (LPARAM
)&dh32
);
267 ret
= proc( code
, wparam
, lparam
);
271 case WH_FOREGROUNDIDLE
:
272 case WH_CALLWNDPROCRET
:
274 FIXME("\t[%i] 16to32 translation unimplemented\n", id
);
275 ret
= proc( code
, wparam
, lparam
);
282 /***********************************************************************
285 * Convert hook params to 16-bit and call 16-bit hook procedure
287 static LRESULT
call_hook_32_to_16( HOOKPROC16 proc
, INT id
, INT code
, WPARAM wparam
, LPARAM lparam
,
295 case WH_SYSMSGFILTER
:
296 case WH_JOURNALRECORD
:
298 MSG
*msg32
= (MSG
*)lparam
;
301 STRUCT32_MSG32to16( msg32
, &msg16
);
302 lparam
= MapLS( &msg16
);
303 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
310 MSG
*msg32
= (MSG
*)lparam
;
313 STRUCT32_MSG32to16( msg32
, &msg16
);
314 lparam
= MapLS( &msg16
);
315 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
317 STRUCT32_MSG16to32( &msg16
, msg32
);
321 case WH_JOURNALPLAYBACK
:
323 EVENTMSG
*em32
= (EVENTMSG
*)lparam
;
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
);
338 CWPSTRUCT
*cwp32
= (CWPSTRUCT
*)lparam
;
342 cwp16
.hwnd
= HWND_16(cwp32
->hwnd
);
343 cwp16
.lParam
= cwp32
->lParam
;
346 WINPROC_MapMsg32WTo16( cwp32
->hwnd
, cwp32
->message
, cwp32
->wParam
,
347 &cwp16
.message
, &cwp16
.wParam
, &cwp16
.lParam
);
349 WINPROC_MapMsg32ATo16( cwp32
->hwnd
, cwp32
->message
, cwp32
->wParam
,
350 &cwp16
.message
, &cwp16
.wParam
, &cwp16
.lParam
);
352 lparam
= MapLS( &cwp16
);
353 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
356 mp16
.wParam
= cwp16
.wParam
;
357 mp16
.lParam
= cwp16
.lParam
;
360 WINPROC_UnmapMsg32WTo16( cwp32
->hwnd
, cwp32
->message
, cwp32
->wParam
,
361 cwp32
->lParam
, &mp16
);
363 WINPROC_UnmapMsg32ATo16( cwp32
->hwnd
, cwp32
->message
, cwp32
->wParam
,
364 cwp32
->lParam
, &mp16
);
373 CBT_CREATEWNDA
*cbtcw32
= (CBT_CREATEWNDA
*)lparam
;
374 CBT_CREATEWND16 cbtcw16
;
377 STRUCT32_CREATESTRUCT32Ato16( cbtcw32
->lpcs
, &cs16
);
378 cbtcw16
.lpcs
= (CREATESTRUCT16
*)MapLS( &cs16
);
379 cbtcw16
.hwndInsertAfter
= HWND_16( cbtcw32
->hwndInsertAfter
);
380 lparam
= MapLS( &cbtcw16
);
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
);
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
);
398 cbtcw32
->hwndInsertAfter
= WIN_Handle32( cbtcw16
.hwndInsertAfter
);
399 UnMapLS( (SEGPTR
)cbtcw16
.lpcs
);
406 CBTACTIVATESTRUCT
*cas32
= (CBTACTIVATESTRUCT
*)lparam
;
407 CBTACTIVATESTRUCT16 cas16
;
409 cas16
.fMouse
= cas32
->fMouse
;
410 cas16
.hWndActive
= HWND_16( cas32
->hWndActive
);
412 lparam
= MapLS( &cas16
);
413 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
417 case HCBT_CLICKSKIPPED
:
419 MOUSEHOOKSTRUCT
*ms32
= (MOUSEHOOKSTRUCT
*)lparam
;
420 MOUSEHOOKSTRUCT16 ms16
;
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
;
428 lparam
= MapLS( &ms16
);
429 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
435 RECT
*rect32
= (RECT
*)lparam
;
438 CONV_RECT32TO16( rect32
, &rect16
);
439 lparam
= MapLS( &rect16
);
440 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
449 MOUSEHOOKSTRUCT
*ms32
= (MOUSEHOOKSTRUCT
*)lparam
;
450 MOUSEHOOKSTRUCT16 ms16
;
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
;
458 lparam
= MapLS( &ms16
);
459 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
466 DEBUGHOOKINFO
*dh32
= (DEBUGHOOKINFO
*)lparam
;
467 DEBUGHOOKINFO16 dh16
;
469 dh16
.hModuleHook
= 0; /* FIXME */
471 dh16
.lParam
= dh32
->lParam
;
472 dh16
.wParam
= dh32
->wParam
;
473 dh16
.code
= dh32
->code
;
475 lparam
= MapLS( &dh16
);
476 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
483 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
487 case WH_FOREGROUNDIDLE
:
488 case WH_CALLWNDPROCRET
:
490 FIXME("\t[%i] 32to16 translation unimplemented\n", id
);
491 ret
= call_hook_16( proc
, id
, code
, wparam
, lparam
);
498 /***********************************************************************
501 * Convert hook params to/from Unicode and call hook procedure
503 static LRESULT
call_hook_32_to_32( HOOKPROC proc
, INT id
, INT code
, WPARAM wparam
, LPARAM lparam
,
506 if (id
!= WH_CBT
|| code
!= HCBT_CREATEWND
) return proc( code
, wparam
, lparam
);
508 if (to_unicode
) /* ASCII to Unicode */
510 CBT_CREATEWNDA
*cbtcwA
= (CBT_CREATEWNDA
*)lparam
;
511 CBT_CREATEWNDW cbtcwW
;
516 cbtcwW
.hwndInsertAfter
= cbtcwA
->hwndInsertAfter
;
517 csW
= *(CREATESTRUCTW
*)cbtcwA
->lpcs
;
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
);
529 else /* Unicode to ASCII */
531 CBT_CREATEWNDW
*cbtcwW
= (CBT_CREATEWNDW
*)lparam
;
532 CBT_CREATEWNDA cbtcwA
;
537 cbtcwA
.hwndInsertAfter
= cbtcwW
->hwndInsertAfter
;
538 csA
= *(CREATESTRUCTA
*)cbtcwW
->lpcs
;
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
);
553 /***********************************************************************
556 * Call a hook procedure.
558 inline static LRESULT
call_hook( HOOKDATA
*data
, INT fromtype
, INT code
,
559 WPARAM wparam
, LPARAM lparam
)
561 INT type
= (data
->flags
& HOOK_MAPTYPE
);
564 /* Suspend window structure locks before calling user code */
565 int iWndsLocks
= WIN_SuspendWndsLock();
567 if (type
== HOOK_WIN16
)
569 if (fromtype
== HOOK_WIN16
) /* 16->16 */
570 ret
= call_hook_16( (HOOKPROC16
)data
->proc
, data
->id
, code
, wparam
, lparam
);
572 ret
= call_hook_32_to_16( (HOOKPROC16
)data
->proc
, data
->id
, code
, wparam
,
573 lparam
, (type
== HOOK_WIN32W
) );
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 */
580 if (type
== fromtype
)
581 ret
= data
->proc( code
, wparam
, lparam
);
583 ret
= call_hook_32_to_32( data
->proc
, data
->id
, code
, wparam
,
584 lparam
, (type
== HOOK_WIN32W
) );
586 WIN_RestoreWndsLock(iWndsLocks
);
591 /***********************************************************************
594 * Get the next hook of a given hook.
596 static HHOOK
HOOK_GetNextHook( HHOOK hook
)
598 HOOKDATA
*data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR( hook
);
600 if (!data
|| !hook
) return 0;
601 if (data
->next
) return HHOOK_32(data
->next
);
602 if (!data
->ownerQueue
) return 0; /* Already system hook */
604 /* Now start enumerating the system hooks */
605 return HHOOK_32(HOOK_systemHooks
[data
->id
- WH_MINHOOK
]);
609 /***********************************************************************
612 * Get the first hook for a given type.
614 static HHOOK
HOOK_GetHook( INT16 id
)
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
);
626 /***********************************************************************
629 * Install a given hook.
631 static HHOOK
HOOK_SetHook( INT16 id
, LPVOID proc
, INT type
,
632 HMODULE16 hModule
, DWORD dwThreadId
)
638 if ((id
< WH_MINHOOK
) || (id
> WH_MAXHOOK
)) return 0;
640 TRACE("Setting hook %d: %08x %04x %08lx\n",
641 id
, (UINT
)proc
, hModule
, dwThreadId
);
643 /* Create task queue if none present */
644 InitThreadInput16( 0, 0 );
646 if (id
== WH_JOURNALPLAYBACK
) EnableHardwareInput16(FALSE
);
648 if (dwThreadId
) /* Task-specific hook */
650 if ((id
== WH_JOURNALRECORD
) || (id
== WH_JOURNALPLAYBACK
) ||
651 (id
== WH_SYSMSGFILTER
)) return 0; /* System-only hooks */
652 if (!(hQueue
= GetThreadQueue16( dwThreadId
)))
656 /* Create the hook structure */
658 if (!(handle
= USER_HEAP_ALLOC( sizeof(HOOKDATA
) ))) return 0;
659 data
= (HOOKDATA
*) USER_HEAP_LIN_ADDR( handle
);
662 data
->ownerQueue
= hQueue
;
663 data
->ownerModule
= hModule
;
666 /* Insert it in the correct linked list */
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
);
677 data
->next
= HOOK_systemHooks
[id
- WH_MINHOOK
];
678 HOOK_systemHooks
[id
- WH_MINHOOK
] = handle
;
680 TRACE("Setting hook %d: ret=%04x [next=%04x]\n",
681 id
, handle
, data
->next
);
683 return HHOOK_32(handle
);
687 /***********************************************************************
690 * Remove a hook from the list.
692 static BOOL
HOOK_RemoveHook( HHOOK hook
)
695 HANDLE16
*prevHandle
;
697 TRACE("Removing hook %04x\n", hook
);
699 if (!(data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
))) return FALSE
;
700 if (data
->flags
& HOOK_INUSE
)
702 /* Mark it for deletion later on */
703 WARN("Hook still running, deletion delayed\n" );
704 data
->proc
= (HOOKPROC
)0;
708 if (data
->id
== WH_JOURNALPLAYBACK
) EnableHardwareInput16(TRUE
);
710 /* Remove it from the linked list */
712 if (data
->ownerQueue
)
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
);
719 else prevHandle
= &HOOK_systemHooks
[data
->id
- WH_MINHOOK
];
721 while (*prevHandle
&& *prevHandle
!= HHOOK_16(hook
))
722 prevHandle
= &((HOOKDATA
*)USER_HEAP_LIN_ADDR(*prevHandle
))->next
;
724 if (!*prevHandle
) return FALSE
;
725 *prevHandle
= data
->next
;
727 USER_HEAP_FREE( hook
);
732 /***********************************************************************
735 static HHOOK
HOOK_FindValidHook( HHOOK hook
)
741 if (!(data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR( hook
))) return 0;
742 if (data
->proc
) return hook
;
743 hook
= HHOOK_32(data
->next
);
747 /***********************************************************************
750 * Call a hook procedure.
752 static LRESULT
HOOK_CallHook( HHOOK hook
, INT fromtype
, INT code
,
753 WPARAM wParam
, LPARAM lParam
)
757 HOOKDATA
*data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR( hook
);
760 if (!(queue
= QUEUE_Current())) return 0;
761 prevHandle
= queue
->hCurHook
;
762 queue
->hCurHook
= HHOOK_16(hook
);
764 TRACE("Calling hook %04x: %d %08x %08lx\n", hook
, code
, wParam
, lParam
);
766 data
->flags
|= HOOK_INUSE
;
767 ret
= call_hook( data
, fromtype
, code
, wParam
, lParam
);
768 data
->flags
&= ~HOOK_INUSE
;
770 TRACE("Ret hook %04x = %08lx\n", hook
, ret
);
772 queue
->hCurHook
= prevHandle
;
773 if (!data
->proc
) HOOK_RemoveHook( hook
);
777 /***********************************************************************
778 * Exported Functions & APIs
781 /***********************************************************************
784 * Replacement for calling HOOK_GetHook from other modules.
786 BOOL
HOOK_IsHooked( INT16 id
)
788 return HOOK_GetHook( id
) != 0;
792 /***********************************************************************
797 LRESULT
HOOK_CallHooks16( INT16 id
, INT16 code
, WPARAM16 wParam
,
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
);
807 /***********************************************************************
812 LRESULT
HOOK_CallHooksA( INT id
, INT code
, WPARAM wParam
,
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
);
822 /***********************************************************************
827 LRESULT
HOOK_CallHooksW( INT id
, INT code
, WPARAM wParam
,
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
,
839 /***********************************************************************
840 * HOOK_FreeModuleHooks
842 void HOOK_FreeModuleHooks( HMODULE16 hModule
)
844 /* remove all system hooks registered by this module */
847 HANDLE16 handle
, next
;
850 for( id
= WH_MINHOOK
; id
<= WH_MAXHOOK
; id
++ )
852 handle
= HOOK_systemHooks
[id
- WH_MINHOOK
];
854 if( (hptr
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(handle
)) )
857 if( hptr
->ownerModule
== hModule
)
859 hptr
->flags
&= HOOK_MAPTYPE
;
860 HOOK_RemoveHook(HHOOK_32(handle
));
868 /***********************************************************************
869 * HOOK_FreeQueueHooks
871 void HOOK_FreeQueueHooks(void)
873 /* remove all hooks registered by the current queue */
875 HOOKDATA
* hptr
= NULL
;
879 for( id
= WH_MINHOOK
; id
<= WH_MAXHOOK
; id
++ )
881 hook
= HOOK_GetHook( id
);
884 next
= HOOK_GetNextHook(hook
);
886 hptr
= (HOOKDATA
*)USER_HEAP_LIN_ADDR( hook
);
887 if( hptr
&& hptr
->ownerQueue
)
889 hptr
->flags
&= HOOK_MAPTYPE
;
890 HOOK_RemoveHook(hook
);
898 /***********************************************************************
899 * SetWindowsHook (USER.121)
901 FARPROC16 WINAPI
SetWindowsHook16( INT16 id
, HOOKPROC16 proc
)
903 HINSTANCE16 hInst
= FarGetOwner16( HIWORD(proc
) );
905 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
906 HTASK16 hTask
= (id
== WH_MSGFILTER
) ? GetCurrentTask() : 0;
908 return (FARPROC16
)SetWindowsHookEx16( id
, proc
, hInst
, hTask
);
911 /***********************************************************************
912 * SetWindowsHookA (USER32.@)
914 HHOOK WINAPI
SetWindowsHookA( INT id
, HOOKPROC proc
)
916 return SetWindowsHookExA( id
, proc
, 0, GetCurrentThreadId() );
919 /***********************************************************************
920 * SetWindowsHookW (USER32.@)
922 HHOOK WINAPI
SetWindowsHookW( INT id
, HOOKPROC proc
)
924 return SetWindowsHookExW( id
, proc
, 0, GetCurrentThreadId() );
928 /***********************************************************************
929 * SetWindowsHookEx (USER.291)
931 HHOOK WINAPI
SetWindowsHookEx16( INT16 id
, HOOKPROC16 proc
, HINSTANCE16 hInst
,
936 FIXME("WH_DEBUG is broken in 16-bit Windows.\n");
939 return HOOK_SetHook( id
, proc
, HOOK_WIN16
, GetExePtr(hInst
), (DWORD
)hTask
);
942 /***********************************************************************
943 * SetWindowsHookExA (USER32.@)
945 HHOOK WINAPI
SetWindowsHookExA( INT id
, HOOKPROC proc
, HINSTANCE hInst
,
948 return HOOK_SetHook( id
, proc
, HOOK_WIN32A
, MapHModuleLS(hInst
), dwThreadId
);
951 /***********************************************************************
952 * SetWindowsHookExW (USER32.@)
954 HHOOK WINAPI
SetWindowsHookExW( INT id
, HOOKPROC proc
, HINSTANCE hInst
,
957 return HOOK_SetHook( id
, proc
, HOOK_WIN32W
, MapHModuleLS(hInst
), dwThreadId
);
961 /***********************************************************************
962 * UnhookWindowsHook (USER.234)
964 BOOL16 WINAPI
UnhookWindowsHook16( INT16 id
, HOOKPROC16 proc
)
966 return UnhookWindowsHook( id
, (HOOKPROC
)proc
);
969 /***********************************************************************
970 * UnhookWindowsHook (USER32.@)
972 BOOL WINAPI
UnhookWindowsHook( INT id
, HOOKPROC proc
)
974 HHOOK hook
= HOOK_GetHook( id
);
976 TRACE("%d %08lx\n", id
, (DWORD
)proc
);
980 HOOKDATA
*data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR( hook
);
981 if (data
->proc
== proc
) break;
982 hook
= HOOK_GetNextHook( hook
);
984 if (!hook
) return FALSE
;
985 return HOOK_RemoveHook( hook
);
989 /***********************************************************************
990 * UnhookWindowsHookEx (USER.292)
992 BOOL16 WINAPI
UnhookWindowsHookEx16( HHOOK hhook
)
994 return HOOK_RemoveHook(hhook
);
997 /***********************************************************************
998 * UnhookWindowsHookEx (USER32.@)
1000 BOOL WINAPI
UnhookWindowsHookEx( HHOOK hhook
)
1002 return HOOK_RemoveHook(hhook
);
1006 /***********************************************************************
1007 * CallNextHookEx (USER.293)
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 (!(next
= HOOK_GetNextHook(hhook
))) return 0;
1019 return HOOK_CallHook( next
, HOOK_WIN16
, code
, wParam
, lParam
);
1023 /***********************************************************************
1024 * CallNextHookEx (USER32.@)
1026 * There aren't ANSI and UNICODE versions of this.
1028 LRESULT WINAPI
CallNextHookEx( HHOOK hhook
, INT code
, WPARAM wParam
,
1032 INT fromtype
; /* figure out Ansi/Unicode */
1035 if (!(next
= HOOK_GetNextHook(hhook
))) return 0;
1037 oldhook
= (HOOKDATA
*)USER_HEAP_LIN_ADDR( hhook
);
1038 fromtype
= oldhook
->flags
& HOOK_MAPTYPE
;
1040 if (fromtype
== HOOK_WIN16
)
1041 ERR("called from 16bit hook!\n");
1043 return HOOK_CallHook( next
, fromtype
, code
, wParam
, lParam
);
1047 /***********************************************************************
1048 * DefHookProc (USER.235)
1050 LRESULT WINAPI
DefHookProc16( INT16 code
, WPARAM16 wParam
, LPARAM lParam
,
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
;
1057 if (!(queue
= QUEUE_Current())) return 0;
1058 return CallNextHookEx16(HHOOK_32(queue
->hCurHook
), code
, wParam
, lParam
);
1062 /***********************************************************************
1063 * CallMsgFilter (USER.123)
1065 BOOL16 WINAPI
CallMsgFilter16( SEGPTR msg
, INT16 code
)
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
);
1073 /***********************************************************************
1074 * CallMsgFilter32 (USER.823)
1076 BOOL16 WINAPI
CallMsgFilter32_16( SEGPTR msg16_32
, INT16 code
, BOOL16 wHaveParamHigh
)
1078 MSG32_16
*lpmsg16_32
= MapSL(msg16_32
);
1080 if (wHaveParamHigh
== FALSE
)
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
);
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
;
1099 ret
= (BOOL16
)CallMsgFilterA(&msg32
, (INT
)code
);
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
);
1115 /***********************************************************************
1116 * CallMsgFilterA (USER32.@)
1118 * FIXME: There are ANSI and UNICODE versions of this, plus an unspecified
1119 * version, plus USER (the 16bit one) has a CallMsgFilter32 function.
1121 BOOL WINAPI
CallMsgFilterA( LPMSG msg
, INT code
)
1123 if (GetSysModalWindow16()) return FALSE
; /* ??? */
1124 if (HOOK_CallHooksA( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)msg
))
1126 return HOOK_CallHooksA( WH_MSGFILTER
, code
, 0, (LPARAM
)msg
);
1130 /***********************************************************************
1131 * CallMsgFilterW (USER32.@)
1133 BOOL WINAPI
CallMsgFilterW( LPMSG msg
, INT code
)
1135 if (GetSysModalWindow16()) return FALSE
; /* ??? */
1136 if (HOOK_CallHooksW( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)msg
))
1138 return HOOK_CallHooksW( WH_MSGFILTER
, code
, 0, (LPARAM
)msg
);
1142 /***********************************************************************
1143 * SetWinEventHook [USER32.@]
1145 * Set up an event hook for a set of events.
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
1157 * Success: A handle representing the hook.
1158 * Failure: A NULL handle.
1163 HWINEVENTHOOK WINAPI
SetWinEventHook(DWORD dwMin
, DWORD dwMax
, HMODULE hModule
,
1164 WINEVENTPROC pfnProc
, DWORD dwProcess
,
1165 DWORD dwThread
, DWORD dwFlags
)
1167 FIXME("(%ld,%ld,0x%08x,%p,%ld,%ld,0x%08lx)-stub!\n", dwMin
, dwMax
, hModule
,
1168 pfnProc
, dwProcess
, dwThread
, dwFlags
);
1170 return (HWINEVENTHOOK
)0;
1173 /***********************************************************************
1174 * UnhookWinEvent [USER32.@]
1176 * Remove an event hook for a set of events.
1179 * hEventHook [I] Event hook to remove
1182 * Success: TRUE. The event hook has been removed.
1183 * Failure: FALSE, if hEventHook is invalid.
1188 BOOL WINAPI
UnhookWinEvent(HWINEVENTHOOK hEventHook
)
1190 FIXME("(%p)-stub!\n", (void*)hEventHook
);
1198 /***********************************************************************
1199 * NotifyWinEvent [USER32.@]
1201 * Inform the OS that an event has occurred.
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.
1215 VOID WINAPI
NotifyWinEvent(DWORD dwEvent
, HWND hWnd
, LONG nId
, LONG nChildId
)
1217 FIXME("(%ld,0x%08x,%ld,%ld)-stub!\n", dwEvent
, hWnd
, nId
, nChildId
);
1220 /***********************************************************************
1221 * IsWinEventHookInstalled [USER32.@]
1223 * Determine if an event hook is installed for an event.
1226 * dwEvent [I] Id of the event
1229 * TRUE, If there are any hooks installed for the event.
1235 BOOL WINAPI
IsWinEventHookInstalled(DWORD dwEvent
)
1237 FIXME("(%ld)-stub!\n", dwEvent
);