2 * Windows hook functions
4 * Copyright 1994, 1995 Alexandre Julliard
7 * Based on investigations by Alex Korobka
12 * A HHOOK is a 32-bit handle for compatibility with Windows 3.0 where it was
13 * a pointer to the next function. Now it is in fact composed of a USER heap
14 * handle in the low 16 bits and of a HOOK_MAGIC value in the high 16 bits.
20 #include "wine/winuser16.h"
21 #include "wine/winbase16.h"
31 #include "debugtools.h"
33 DEFAULT_DEBUG_CHANNEL(hook)
37 /* Hook data (pointed to by a HHOOK) */
40 HANDLE16 next; /* 00 Next hook in chain */
41 HOOKPROC proc; /* 02 Hook procedure (original) */
42 INT16 id; /* 06 Hook id (WH_xxx) */
43 HQUEUE16 ownerQueue; /* 08 Owner queue (0 for system hook) */
44 HMODULE16 ownerModule; /* 0a Owner module */
45 WORD flags; /* 0c flags */
46 HOOKPROC thunk; /* 0e Hook procedure (CallTo16 thunk) */
51 #define HOOK_MAGIC ((int)'H' | (int)'K' << 8) /* 'HK' */
53 /* This should probably reside in USER heap */
54 static HANDLE16 HOOK_systemHooks[WH_NB_HOOKS] = { 0, };
56 typedef VOID (*HOOK_MapFunc)(INT, INT, WPARAM *, LPARAM *);
57 typedef VOID (*HOOK_UnMapFunc)(INT, INT, WPARAM, LPARAM, WPARAM,
60 /***********************************************************************
61 * HOOK_Map16To32Common
63 static void HOOK_Map16To32Common(INT id, INT code, WPARAM *pwParam,
64 LPARAM *plParam, BOOL bA )
72 case WH_JOURNALRECORD:
74 LPMSG16 lpmsg16 = PTR_SEG_TO_LIN(*plParam);
75 LPMSG lpmsg32 = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpmsg32) );
77 STRUCT32_MSG16to32( lpmsg16, lpmsg32 );
78 *plParam = (LPARAM)lpmsg32;
82 case WH_JOURNALPLAYBACK:
84 LPEVENTMSG16 lpem16 = PTR_SEG_TO_LIN(*plParam);
85 LPEVENTMSG lpem32 = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpem32) );
87 lpem32->message = lpem16->message;
88 lpem32->paramL = lpem16->paramL;
89 lpem32->paramH = lpem16->paramH;
90 lpem32->time = lpem16->time;
91 lpem32->hwnd = 0; /* FIXME */
93 *plParam = (LPARAM)lpem32;
99 LPCWPSTRUCT16 lpcwp16 = PTR_SEG_TO_LIN(*plParam);
100 LPCWPSTRUCT lpcwp32 = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpcwp32) );
102 lpcwp32->hwnd = lpcwp16->hwnd;
103 lpcwp32->lParam = lpcwp16->lParam;
105 if (bA) WINPROC_MapMsg16To32A( lpcwp16->message, lpcwp16->wParam,
106 &lpcwp32->message, &lpcwp32->wParam,
108 else WINPROC_MapMsg16To32W( lpcwp16->hwnd,lpcwp16->message, lpcwp16->wParam,
109 &lpcwp32->message, &lpcwp32->wParam,
111 *plParam = (LPARAM)lpcwp32;
120 LPCBT_CREATEWND16 lpcbtcw16 = PTR_SEG_TO_LIN(*plParam);
121 LPCREATESTRUCT16 lpcs16 = PTR_SEG_TO_LIN(lpcbtcw16->lpcs);
122 LPCBT_CREATEWNDA lpcbtcw32 = HeapAlloc( GetProcessHeap(), 0,
123 sizeof(*lpcbtcw32) );
124 lpcbtcw32->lpcs = HeapAlloc( GetProcessHeap(), 0,
125 sizeof(*lpcbtcw32->lpcs) );
127 STRUCT32_CREATESTRUCT16to32A( lpcs16,
128 (LPCREATESTRUCTA)lpcbtcw32->lpcs );
130 if (HIWORD(lpcs16->lpszName))
131 lpcbtcw32->lpcs->lpszName =
132 (bA) ? PTR_SEG_TO_LIN(lpcs16->lpszName)
133 : HEAP_strdupAtoW( GetProcessHeap(), 0,
134 PTR_SEG_TO_LIN(lpcs16->lpszName) );
136 lpcbtcw32->lpcs->lpszName = (LPCSTR)lpcs16->lpszName;
138 if (HIWORD(lpcs16->lpszClass))
139 lpcbtcw32->lpcs->lpszClass =
140 (bA) ? PTR_SEG_TO_LIN(lpcs16->lpszClass)
141 : HEAP_strdupAtoW( GetProcessHeap(), 0,
142 PTR_SEG_TO_LIN(lpcs16->lpszClass) );
144 lpcbtcw32->lpcs->lpszClass = (LPCSTR)lpcs16->lpszClass;
146 lpcbtcw32->hwndInsertAfter = lpcbtcw16->hwndInsertAfter;
148 *plParam = (LPARAM)lpcbtcw32;
153 LPCBTACTIVATESTRUCT16 lpcas16 = PTR_SEG_TO_LIN(*plParam);
154 LPCBTACTIVATESTRUCT lpcas32 = HeapAlloc( GetProcessHeap(), 0,
156 lpcas32->fMouse = lpcas16->fMouse;
157 lpcas32->hWndActive = lpcas16->hWndActive;
158 *plParam = (LPARAM)lpcas32;
161 case HCBT_CLICKSKIPPED:
163 LPMOUSEHOOKSTRUCT16 lpms16 = PTR_SEG_TO_LIN(*plParam);
164 LPMOUSEHOOKSTRUCT lpms32 = HeapAlloc( GetProcessHeap(), 0,
167 CONV_POINT16TO32( &lpms16->pt, &lpms32->pt );
169 /* wHitTestCode may be negative, so convince compiler to do
170 correct sign extension. Yay. :| */
171 lpms32->wHitTestCode = (INT)((INT16)lpms16->wHitTestCode);
173 lpms32->dwExtraInfo = lpms16->dwExtraInfo;
174 lpms32->hwnd = lpms16->hwnd;
175 *plParam = (LPARAM)lpms32;
180 LPRECT16 lprect16 = PTR_SEG_TO_LIN(*plParam);
181 LPRECT lprect32 = HeapAlloc( GetProcessHeap(), 0,
184 CONV_RECT16TO32( lprect16, lprect32 );
185 *plParam = (LPARAM)lprect32;
193 LPMOUSEHOOKSTRUCT16 lpms16 = PTR_SEG_TO_LIN(*plParam);
194 LPMOUSEHOOKSTRUCT lpms32 = HeapAlloc( GetProcessHeap(), 0,
197 CONV_POINT16TO32( &lpms16->pt, &lpms32->pt );
199 /* wHitTestCode may be negative, so convince compiler to do
200 correct sign extension. Yay. :| */
201 lpms32->wHitTestCode = (INT)((INT16)lpms16->wHitTestCode);
202 lpms32->dwExtraInfo = lpms16->dwExtraInfo;
203 lpms32->hwnd = lpms16->hwnd;
204 *plParam = (LPARAM)lpms32;
210 LPDEBUGHOOKINFO16 lpdh16 = PTR_SEG_TO_LIN(*plParam);
211 LPDEBUGHOOKINFO lpdh32 = HeapAlloc( GetProcessHeap(), 0,
214 lpdh32->idThread = 0; /* FIXME */
215 lpdh32->idThreadInstaller = 0; /* FIXME */
216 lpdh32->lParam = lpdh16->lParam; /* FIXME Check for sign ext */
217 lpdh32->wParam = lpdh16->wParam;
218 lpdh32->code = lpdh16->code;
220 /* do sign extension if it was WH_MSGFILTER */
221 if (*pwParam == 0xffff) *pwParam = WH_MSGFILTER;
223 *plParam = (LPARAM)lpdh32;
232 case WH_FOREGROUNDIDLE:
233 case WH_CALLWNDPROCRET:
234 FIXME("\t[%i] 16to32 translation unimplemented\n", id);
239 /***********************************************************************
242 static void HOOK_Map16To32A(INT id, INT code, WPARAM *pwParam,
245 HOOK_Map16To32Common( id, code, pwParam, plParam, TRUE );
249 /***********************************************************************
252 static void HOOK_Map16To32W(INT id, INT code, WPARAM *pwParam,
255 HOOK_Map16To32Common( id, code, pwParam, plParam, FALSE );
259 /***********************************************************************
260 * HOOK_UnMap16To32Common
262 static void HOOK_UnMap16To32Common(INT id, INT code, WPARAM wParamOrig,
263 LPARAM lParamOrig, WPARAM wParam,
264 LPARAM lParam, BOOL bA)
269 case WH_SYSMSGFILTER:
270 case WH_JOURNALRECORD:
271 case WH_JOURNALPLAYBACK:
273 HeapFree( GetProcessHeap(), 0, (LPVOID)lParam );
278 LPCWPSTRUCT lpcwp32 = (LPCWPSTRUCT)lParam;
279 if (bA) WINPROC_UnmapMsg16To32A( lpcwp32->hwnd,lpcwp32->message, lpcwp32->wParam,
280 lpcwp32->lParam, 0 );
281 else WINPROC_UnmapMsg16To32W( lpcwp32->hwnd,lpcwp32->message, lpcwp32->wParam,
282 lpcwp32->lParam, 0 );
283 HeapFree( GetProcessHeap(), 0, lpcwp32 );
289 LPMSG16 lpmsg16 = PTR_SEG_TO_LIN(lParamOrig);
290 STRUCT32_MSG32to16( (LPMSG)lParam, lpmsg16 );
291 HeapFree( GetProcessHeap(), 0, (LPVOID)lParam );
298 HeapFree( GetProcessHeap(), 0, (LPVOID)lParam );
306 LPCBT_CREATEWNDA lpcbtcw32 = (LPCBT_CREATEWNDA)lParam;
307 LPCBT_CREATEWND16 lpcbtcw16 = PTR_SEG_TO_LIN(lParamOrig);
311 if (HIWORD(lpcbtcw32->lpcs->lpszName))
312 HeapFree( GetProcessHeap(), 0, (LPWSTR)lpcbtcw32->lpcs->lpszName );
313 if (HIWORD(lpcbtcw32->lpcs->lpszClass))
314 HeapFree( GetProcessHeap(), 0, (LPWSTR)lpcbtcw32->lpcs->lpszClass );
317 lpcbtcw16->hwndInsertAfter = lpcbtcw32->hwndInsertAfter;
319 HeapFree( GetProcessHeap(), 0, lpcbtcw32->lpcs );
323 case HCBT_CLICKSKIPPED:
326 HeapFree( GetProcessHeap(), 0, (LPVOID)lParam);
336 case WH_FOREGROUNDIDLE:
337 case WH_CALLWNDPROCRET:
338 FIXME("\t[%i] skipping unmap\n", id);
344 /***********************************************************************
347 static void HOOK_UnMap16To32A(INT id, INT code, WPARAM wParamOrig,
348 LPARAM lParamOrig, WPARAM wParam,
351 HOOK_UnMap16To32Common( id, code, wParamOrig, lParamOrig, wParam,
356 /***********************************************************************
359 static void HOOK_UnMap16To32W(INT id, INT code, WPARAM wParamOrig,
360 LPARAM lParamOrig, WPARAM wParam,
363 HOOK_UnMap16To32Common( id, code, wParamOrig, lParamOrig, wParam,
368 /***********************************************************************
369 * HOOK_Map32To16Common
371 static void HOOK_Map32To16Common(INT id, INT code, WPARAM *pwParam,
372 LPARAM *plParam, BOOL bA)
377 case WH_SYSMSGFILTER:
379 case WH_JOURNALRECORD:
381 LPMSG lpmsg32 = (LPMSG)*plParam;
382 LPMSG16 lpmsg16 = SEGPTR_NEW( MSG16 );
384 STRUCT32_MSG32to16( lpmsg32, lpmsg16 );
386 *plParam = (LPARAM)SEGPTR_GET( lpmsg16 );
390 case WH_JOURNALPLAYBACK:
392 LPEVENTMSG lpem32 = (LPEVENTMSG)*plParam;
393 LPEVENTMSG16 lpem16 = SEGPTR_NEW( EVENTMSG16 );
395 lpem16->message = lpem32->message;
396 lpem16->paramL = lpem32->paramL;
397 lpem16->paramH = lpem32->paramH;
398 lpem16->time = lpem32->time;
400 *plParam = (LPARAM)SEGPTR_GET( lpem16 );
406 LPCWPSTRUCT lpcwp32 = (LPCWPSTRUCT)*plParam;
407 LPCWPSTRUCT16 lpcwp16 = SEGPTR_NEW( CWPSTRUCT16 );
409 lpcwp16->hwnd = lpcwp32->hwnd;
410 lpcwp16->lParam = lpcwp32->lParam;
412 if (bA) WINPROC_MapMsg32ATo16( lpcwp32->hwnd, lpcwp32->message,
413 lpcwp32->wParam, &lpcwp16->message,
414 &lpcwp16->wParam, &lpcwp16->lParam );
415 else WINPROC_MapMsg32WTo16( lpcwp32->hwnd, lpcwp32->message,
416 lpcwp32->wParam, &lpcwp16->message,
417 &lpcwp16->wParam, &lpcwp16->lParam );
418 *plParam = (LPARAM)SEGPTR_GET( lpcwp16 );
427 LPCBTACTIVATESTRUCT lpcas32 = (LPCBTACTIVATESTRUCT)*plParam;
428 LPCBTACTIVATESTRUCT16 lpcas16 =SEGPTR_NEW( CBTACTIVATESTRUCT16 );
430 lpcas16->fMouse = lpcas32->fMouse;
431 lpcas16->hWndActive = lpcas32->hWndActive;
433 *plParam = (LPARAM)SEGPTR_GET( lpcas16 );
437 case HCBT_CLICKSKIPPED:
439 LPMOUSEHOOKSTRUCT lpms32 = (LPMOUSEHOOKSTRUCT)*plParam;
440 LPMOUSEHOOKSTRUCT16 lpms16 = SEGPTR_NEW( MOUSEHOOKSTRUCT16 );
442 CONV_POINT32TO16( &lpms32->pt, &lpms16->pt );
444 lpms16->hwnd = lpms32->hwnd;
445 lpms16->wHitTestCode = lpms32->wHitTestCode;
446 lpms16->dwExtraInfo = lpms32->dwExtraInfo;
448 *plParam = (LPARAM)SEGPTR_GET( lpms16 );
454 LPRECT lprect32 = (LPRECT)*plParam;
455 LPRECT16 lprect16 = SEGPTR_NEW( RECT16 );
457 CONV_RECT32TO16( lprect32, lprect16 );
459 *plParam = (LPARAM)SEGPTR_GET( lprect16 );
467 LPMOUSEHOOKSTRUCT lpms32 = (LPMOUSEHOOKSTRUCT)*plParam;
468 LPMOUSEHOOKSTRUCT16 lpms16 = SEGPTR_NEW( MOUSEHOOKSTRUCT16 );
470 CONV_POINT32TO16( &lpms32->pt, &lpms16->pt );
472 lpms16->hwnd = lpms32->hwnd;
473 lpms16->wHitTestCode = lpms32->wHitTestCode;
474 lpms16->dwExtraInfo = lpms32->dwExtraInfo;
476 *plParam = (LPARAM)SEGPTR_GET( lpms16 );
482 LPDEBUGHOOKINFO lpdh32 = (LPDEBUGHOOKINFO)*plParam;
483 LPDEBUGHOOKINFO16 lpdh16 = SEGPTR_NEW( DEBUGHOOKINFO16 );
485 lpdh16->hModuleHook = 0; /* FIXME */
486 lpdh16->reserved = 0;
487 lpdh16->lParam = lpdh32->lParam;
488 lpdh16->wParam = lpdh32->wParam;
489 lpdh16->code = lpdh32->code;
491 *plParam = (LPARAM)SEGPTR_GET( lpdh16 );
500 case WH_FOREGROUNDIDLE:
501 case WH_CALLWNDPROCRET:
502 FIXME("\t[%i] 32to16 translation unimplemented\n", id);
507 /***********************************************************************
510 static void HOOK_Map32ATo16(INT id, INT code, WPARAM *pwParam,
513 if (id == WH_CBT && code == HCBT_CREATEWND)
515 LPCBT_CREATEWNDA lpcbtcw32 = (LPCBT_CREATEWNDA)*plParam;
516 LPCBT_CREATEWND16 lpcbtcw16 = SEGPTR_NEW( CBT_CREATEWND16 );
517 LPCREATESTRUCT16 lpcs16 = SEGPTR_NEW( CREATESTRUCT16 );
519 lpcbtcw16->lpcs = (LPCREATESTRUCT16)SEGPTR_GET( lpcs16 );
520 STRUCT32_CREATESTRUCT32Ato16( lpcbtcw32->lpcs, lpcs16 );
522 if (HIWORD(lpcbtcw32->lpcs->lpszName))
524 SEGPTR_GET( SEGPTR_STRDUP( lpcbtcw32->lpcs->lpszName ) );
526 lpcs16->lpszName = (SEGPTR)lpcbtcw32->lpcs->lpszName;
528 if (HIWORD(lpcbtcw32->lpcs->lpszClass))
530 SEGPTR_GET( SEGPTR_STRDUP( lpcbtcw32->lpcs->lpszClass ) );
532 lpcs16->lpszClass = (SEGPTR)lpcbtcw32->lpcs->lpszClass;
534 lpcbtcw16->hwndInsertAfter = lpcbtcw32->hwndInsertAfter;
536 *plParam = (LPARAM)SEGPTR_GET( lpcbtcw16 );
538 else HOOK_Map32To16Common(id, code, pwParam, plParam, TRUE);
542 /***********************************************************************
545 static void HOOK_Map32WTo16(INT id, INT code, WPARAM *pwParam,
548 if (id == WH_CBT && code == HCBT_CREATEWND)
551 LPCBT_CREATEWNDW lpcbtcw32 = (LPCBT_CREATEWNDW)*plParam;
552 LPCBT_CREATEWND16 lpcbtcw16 = SEGPTR_NEW( CBT_CREATEWND16 );
553 LPCREATESTRUCT16 lpcs16 = SEGPTR_NEW( CREATESTRUCT16 );
555 lpcbtcw16->lpcs = (LPCREATESTRUCT16)SEGPTR_GET( lpcs16 );
556 STRUCT32_CREATESTRUCT32Ato16( (LPCREATESTRUCTA)lpcbtcw32->lpcs,
559 name = SEGPTR_STRDUP_WtoA( lpcbtcw32->lpcs->lpszName );
560 cls = SEGPTR_STRDUP_WtoA( lpcbtcw32->lpcs->lpszClass );
561 lpcs16->lpszName = SEGPTR_GET( name );
562 lpcs16->lpszClass = SEGPTR_GET( cls );
563 lpcbtcw16->hwndInsertAfter = lpcbtcw32->hwndInsertAfter;
565 *plParam = (LPARAM)SEGPTR_GET( lpcbtcw16 );
567 else HOOK_Map32To16Common(id, code, pwParam, plParam, FALSE);
571 /***********************************************************************
572 * HOOK_UnMap32To16Common
574 static void HOOK_UnMap32To16Common(INT id, INT code, WPARAM wParamOrig,
575 LPARAM lParamOrig, WPARAM wParam,
576 LPARAM lParam, BOOL bA)
581 case WH_SYSMSGFILTER:
582 case WH_JOURNALRECORD:
583 case WH_JOURNALPLAYBACK:
586 SEGPTR_FREE( PTR_SEG_TO_LIN(lParam) );
591 LPCWPSTRUCT16 lpcwp16 = (LPCWPSTRUCT16)PTR_SEG_TO_LIN(lParam);
592 LPCWPSTRUCT lpcwp32 = (LPCWPSTRUCT)lParamOrig;
595 mp16.wParam = lpcwp16->wParam;
596 mp16.lParam = lpcwp16->lParam;
599 if (bA) WINPROC_UnmapMsg32ATo16( lpcwp32->hwnd,lpcwp32->message, lpcwp32->wParam,
600 lpcwp32->lParam, &mp16 );
601 else WINPROC_UnmapMsg32WTo16( lpcwp32->hwnd,lpcwp32->message, lpcwp32->wParam,
602 lpcwp32->lParam, &mp16 );
603 SEGPTR_FREE( PTR_SEG_TO_LIN(lParam) );
609 LPMSG lpmsg32 = (LPMSG)lParamOrig;
611 STRUCT32_MSG16to32( (LPMSG16)PTR_SEG_TO_LIN(lParam), lpmsg32 );
612 SEGPTR_FREE( PTR_SEG_TO_LIN(lParam) );
621 LPCBT_CREATEWNDA lpcbtcw32 = (LPCBT_CREATEWNDA)(lParamOrig);
622 LPCBT_CREATEWND16 lpcbtcw16 = PTR_SEG_TO_LIN(lParam);
623 LPCREATESTRUCT16 lpcs16 = PTR_SEG_TO_LIN(lpcbtcw16->lpcs);
625 if (HIWORD(lpcs16->lpszName))
626 SEGPTR_FREE( PTR_SEG_TO_LIN(lpcs16->lpszName) );
628 if (HIWORD(lpcs16->lpszClass))
629 SEGPTR_FREE( PTR_SEG_TO_LIN(lpcs16->lpszClass) );
631 lpcbtcw32->hwndInsertAfter = lpcbtcw16->hwndInsertAfter;
633 SEGPTR_FREE( lpcs16 );
637 case HCBT_CLICKSKIPPED:
640 SEGPTR_FREE( PTR_SEG_TO_LIN(lParam) );
650 case WH_FOREGROUNDIDLE:
651 case WH_CALLWNDPROCRET:
652 FIXME("\t[%i] skipping unmap\n", id);
657 /***********************************************************************
660 static void HOOK_UnMap32ATo16(INT id, INT code, WPARAM wParamOrig,
661 LPARAM lParamOrig, WPARAM wParam,
664 HOOK_UnMap32To16Common( id, code, wParamOrig, lParamOrig, wParam,
669 /***********************************************************************
672 static void HOOK_UnMap32WTo16(INT id, INT code, WPARAM wParamOrig,
673 LPARAM lParamOrig, WPARAM wParam,
676 HOOK_UnMap32To16Common( id, code, wParamOrig, lParamOrig, wParam,
681 /***********************************************************************
684 static void HOOK_Map32ATo32W(INT id, INT code, WPARAM *pwParam,
687 if (id == WH_CBT && code == HCBT_CREATEWND)
689 LPCBT_CREATEWNDA lpcbtcwA = (LPCBT_CREATEWNDA)*plParam;
690 LPCBT_CREATEWNDW lpcbtcwW = HeapAlloc( GetProcessHeap(), 0,
692 lpcbtcwW->lpcs = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpcbtcwW->lpcs) );
694 lpcbtcwW->hwndInsertAfter = lpcbtcwA->hwndInsertAfter;
695 *lpcbtcwW->lpcs = *(LPCREATESTRUCTW)lpcbtcwA->lpcs;
697 if (HIWORD(lpcbtcwA->lpcs->lpszName))
699 lpcbtcwW->lpcs->lpszName = HEAP_strdupAtoW( GetProcessHeap(), 0,
700 lpcbtcwA->lpcs->lpszName );
703 lpcbtcwW->lpcs->lpszName = (LPWSTR)lpcbtcwA->lpcs->lpszName;
705 if (HIWORD(lpcbtcwA->lpcs->lpszClass))
707 lpcbtcwW->lpcs->lpszClass = HEAP_strdupAtoW( GetProcessHeap(), 0,
708 lpcbtcwA->lpcs->lpszClass );
711 lpcbtcwW->lpcs->lpszClass = (LPCWSTR)lpcbtcwA->lpcs->lpszClass;
712 *plParam = (LPARAM)lpcbtcwW;
718 /***********************************************************************
721 static void HOOK_UnMap32ATo32W(INT id, INT code, WPARAM wParamOrig,
722 LPARAM lParamOrig, WPARAM wParam,
725 if (id == WH_CBT && code == HCBT_CREATEWND)
727 LPCBT_CREATEWNDW lpcbtcwW = (LPCBT_CREATEWNDW)lParam;
728 if (HIWORD(lpcbtcwW->lpcs->lpszName))
729 HeapFree( GetProcessHeap(), 0, (LPWSTR)lpcbtcwW->lpcs->lpszName );
730 if (HIWORD(lpcbtcwW->lpcs->lpszClass))
731 HeapFree( GetProcessHeap(), 0, (LPWSTR)lpcbtcwW->lpcs->lpszClass );
732 HeapFree( GetProcessHeap(), 0, lpcbtcwW->lpcs );
733 HeapFree( GetProcessHeap(), 0, lpcbtcwW );
739 /***********************************************************************
742 static void HOOK_Map32WTo32A(INT id, INT code, WPARAM *pwParam,
745 if (id == WH_CBT && code == HCBT_CREATEWND)
747 LPCBT_CREATEWNDW lpcbtcwW = (LPCBT_CREATEWNDW)*plParam;
748 LPCBT_CREATEWNDA lpcbtcwA = HeapAlloc( GetProcessHeap(), 0,
750 lpcbtcwA->lpcs = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpcbtcwA->lpcs) );
752 lpcbtcwA->hwndInsertAfter = lpcbtcwW->hwndInsertAfter;
753 *lpcbtcwA->lpcs = *(LPCREATESTRUCTA)lpcbtcwW->lpcs;
755 if (HIWORD(lpcbtcwW->lpcs->lpszName))
756 lpcbtcwA->lpcs->lpszName = HEAP_strdupWtoA( GetProcessHeap(), 0,
757 lpcbtcwW->lpcs->lpszName );
759 lpcbtcwA->lpcs->lpszName = (LPSTR)lpcbtcwW->lpcs->lpszName;
761 if (HIWORD(lpcbtcwW->lpcs->lpszClass))
762 lpcbtcwA->lpcs->lpszClass = HEAP_strdupWtoA( GetProcessHeap(), 0,
763 lpcbtcwW->lpcs->lpszClass );
765 lpcbtcwA->lpcs->lpszClass = (LPSTR)lpcbtcwW->lpcs->lpszClass;
766 *plParam = (LPARAM)lpcbtcwA;
772 /***********************************************************************
775 static void HOOK_UnMap32WTo32A(INT id, INT code, WPARAM wParamOrig,
776 LPARAM lParamOrig, WPARAM wParam,
779 if (id == WH_CBT && code == HCBT_CREATEWND)
781 LPCBT_CREATEWNDA lpcbtcwA = (LPCBT_CREATEWNDA)lParam;
782 if (HIWORD(lpcbtcwA->lpcs->lpszName))
783 HeapFree( GetProcessHeap(), 0, (LPSTR)lpcbtcwA->lpcs->lpszName );
784 if (HIWORD(lpcbtcwA->lpcs->lpszClass))
785 HeapFree( GetProcessHeap(), 0, (LPSTR)lpcbtcwA->lpcs->lpszClass );
786 HeapFree( GetProcessHeap(), 0, lpcbtcwA->lpcs );
787 HeapFree( GetProcessHeap(), 0, lpcbtcwA );
793 /***********************************************************************
794 * Map Function Tables
796 static const HOOK_MapFunc HOOK_MapFuncs[3][3] =
798 { NULL, HOOK_Map16To32A, HOOK_Map16To32W },
799 { HOOK_Map32ATo16, NULL, HOOK_Map32ATo32W },
800 { HOOK_Map32WTo16, HOOK_Map32WTo32A, NULL }
803 static const HOOK_UnMapFunc HOOK_UnMapFuncs[3][3] =
805 { NULL, HOOK_UnMap16To32A, HOOK_UnMap16To32W },
806 { HOOK_UnMap32ATo16, NULL, HOOK_UnMap32ATo32W },
807 { HOOK_UnMap32WTo16, HOOK_UnMap32WTo32A, NULL }
811 /***********************************************************************
815 /***********************************************************************
818 * Get the next hook of a given hook.
820 static HANDLE16 HOOK_GetNextHook( HANDLE16 hook )
822 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR( hook );
824 if (!data || !hook) return 0;
825 if (data->next) return data->next;
826 if (!data->ownerQueue) return 0; /* Already system hook */
828 /* Now start enumerating the system hooks */
829 return HOOK_systemHooks[data->id - WH_MINHOOK];
833 /***********************************************************************
836 * Get the first hook for a given type.
838 static HANDLE16 HOOK_GetHook( INT16 id, HQUEUE16 hQueue )
843 if ((queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue )) != NULL)
844 hook = queue->hooks[id - WH_MINHOOK];
845 if (!hook) hook = HOOK_systemHooks[id - WH_MINHOOK];
847 QUEUE_Unlock( queue );
852 /***********************************************************************
855 * Install a given hook.
857 /* ### start build ### */
858 extern LONG CALLBACK HOOK_CallTo16_long_wwl(FARPROC16,WORD,WORD,LONG);
859 /* ### stop build ### */
860 static HHOOK HOOK_SetHook( INT16 id, LPVOID proc, INT type,
861 HMODULE16 hModule, DWORD dwThreadId )
867 if ((id < WH_MINHOOK) || (id > WH_MAXHOOK)) return 0;
869 TRACE("Setting hook %d: %08x %04x %08lx\n",
870 id, (UINT)proc, hModule, dwThreadId );
872 /* Create task queue if none present */
875 if (id == WH_JOURNALPLAYBACK) EnableHardwareInput16(FALSE);
877 if (dwThreadId) /* Task-specific hook */
879 if ((id == WH_JOURNALRECORD) || (id == WH_JOURNALPLAYBACK) ||
880 (id == WH_SYSMSGFILTER)) return 0; /* System-only hooks */
881 if (!(hQueue = GetThreadQueue16( dwThreadId )))
885 /* Create the hook structure */
887 if (!(handle = USER_HEAP_ALLOC( sizeof(HOOKDATA) ))) return 0;
888 data = (HOOKDATA *) USER_HEAP_LIN_ADDR( handle );
891 data->ownerQueue = hQueue;
892 data->ownerModule = hModule;
895 /* Create CallTo16 thunk for 16-bit hooks */
897 if ( (data->flags & HOOK_MAPTYPE) == HOOK_WIN16 )
898 data->thunk = (HOOKPROC)THUNK_Alloc( (FARPROC16)data->proc,
899 (RELAY)HOOK_CallTo16_long_wwl );
901 data->thunk = data->proc;
903 if ( !data->thunk && data->proc )
905 USER_HEAP_FREE( handle );
909 /* Insert it in the correct linked list */
913 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
914 data->next = queue->hooks[id - WH_MINHOOK];
915 queue->hooks[id - WH_MINHOOK] = handle;
916 QUEUE_Unlock( queue );
920 data->next = HOOK_systemHooks[id - WH_MINHOOK];
921 HOOK_systemHooks[id - WH_MINHOOK] = handle;
923 TRACE("Setting hook %d: ret=%04x [next=%04x]\n",
924 id, handle, data->next );
926 return (HHOOK)( handle? MAKELONG( handle, HOOK_MAGIC ) : 0 );
930 /***********************************************************************
933 * Remove a hook from the list.
935 static BOOL HOOK_RemoveHook( HANDLE16 hook )
940 TRACE("Removing hook %04x\n", hook );
942 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return FALSE;
943 if (data->flags & HOOK_INUSE)
945 /* Mark it for deletion later on */
946 WARN("Hook still running, deletion delayed\n" );
947 data->proc = (HOOKPROC)0;
951 if (data->id == WH_JOURNALPLAYBACK) EnableHardwareInput16(TRUE);
953 /* Remove it from the linked list */
955 if (data->ownerQueue)
957 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)QUEUE_Lock( data->ownerQueue );
958 if (!queue) return FALSE;
959 prevHook = &queue->hooks[data->id - WH_MINHOOK];
960 QUEUE_Unlock( queue );
962 else prevHook = &HOOK_systemHooks[data->id - WH_MINHOOK];
964 while (*prevHook && *prevHook != hook)
965 prevHook = &((HOOKDATA *)USER_HEAP_LIN_ADDR(*prevHook))->next;
967 if (!*prevHook) return FALSE;
968 *prevHook = data->next;
970 if ( (data->flags & HOOK_MAPTYPE) == HOOK_WIN16 )
971 THUNK_Free( (FARPROC)data->thunk );
973 USER_HEAP_FREE( hook );
978 /***********************************************************************
981 static HANDLE16 HOOK_FindValidHook( HANDLE16 hook )
987 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return 0;
988 if (data->proc) return hook;
994 /***********************************************************************
997 * Call a hook procedure.
999 static LRESULT HOOK_CallHook( HANDLE16 hook, INT fromtype, INT code,
1000 WPARAM wParam, LPARAM lParam )
1002 MESSAGEQUEUE *queue;
1004 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
1008 WPARAM wParamOrig = wParam;
1009 LPARAM lParamOrig = lParam;
1010 HOOK_MapFunc MapFunc;
1011 HOOK_UnMapFunc UnMapFunc;
1013 MapFunc = HOOK_MapFuncs[fromtype][data->flags & HOOK_MAPTYPE];
1014 UnMapFunc = HOOK_UnMapFuncs[fromtype][data->flags & HOOK_MAPTYPE];
1017 MapFunc( data->id, code, &wParam, &lParam );
1021 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1022 prevHook = queue->hCurHook;
1023 queue->hCurHook = hook;
1024 data->flags |= HOOK_INUSE;
1026 TRACE("Calling hook %04x: %d %08x %08lx\n",
1027 hook, code, wParam, lParam );
1029 /* Suspend window structure locks before calling user code */
1030 iWndsLocks = WIN_SuspendWndsLock();
1032 ret = data->thunk(code, wParam, lParam);
1034 /* Grrr. While the hook procedure is supposed to have an LRESULT return
1035 value even in Win16, it seems that for those hook types where the
1036 return value is interpreted as BOOL, Windows doesn't actually check
1037 the HIWORD ... Some buggy Win16 programs, notably WINFILE, rely on
1038 that, because they neglect to clear DX ... */
1039 if ( (data->flags & HOOK_MAPTYPE) == HOOK_WIN16
1040 && data->id != WH_JOURNALPLAYBACK )
1041 ret = LOWORD( ret );
1043 WIN_RestoreWndsLock(iWndsLocks);
1045 TRACE("Ret hook %04x = %08lx\n", hook, ret );
1047 data->flags &= ~HOOK_INUSE;
1048 queue->hCurHook = prevHook;
1050 QUEUE_Unlock( queue );
1053 UnMapFunc( data->id, code, wParamOrig, lParamOrig, wParam, lParam );
1055 if (!data->proc) HOOK_RemoveHook( hook );
1060 /***********************************************************************
1061 * Exported Functions & APIs
1064 /***********************************************************************
1067 * Replacement for calling HOOK_GetHook from other modules.
1069 BOOL HOOK_IsHooked( INT16 id )
1071 /* Hmmm. Use GetThreadQueue(0) instead of GetFastQueue() here to
1072 avoid queue being created if someone wants to merely check ... */
1074 return HOOK_GetHook( id, GetThreadQueue16(0) ) != 0;
1078 /***********************************************************************
1081 * Call a hook chain.
1083 LRESULT HOOK_CallHooks16( INT16 id, INT16 code, WPARAM16 wParam,
1088 if (!(hook = HOOK_GetHook( id, GetFastQueue16() ))) return 0;
1089 if (!(hook = HOOK_FindValidHook(hook))) return 0;
1090 return HOOK_CallHook( hook, HOOK_WIN16, code, wParam, lParam );
1093 /***********************************************************************
1096 * Call a hook chain.
1098 LRESULT HOOK_CallHooksA( INT id, INT code, WPARAM wParam,
1103 if (!(hook = HOOK_GetHook( id, GetFastQueue16() ))) return 0;
1104 if (!(hook = HOOK_FindValidHook(hook))) return 0;
1105 return HOOK_CallHook( hook, HOOK_WIN32A, code, wParam, lParam );
1108 /***********************************************************************
1111 * Call a hook chain.
1113 LRESULT HOOK_CallHooksW( INT id, INT code, WPARAM wParam,
1118 if (!(hook = HOOK_GetHook( id, GetFastQueue16() ))) return 0;
1119 if (!(hook = HOOK_FindValidHook(hook))) return 0;
1120 return HOOK_CallHook( hook, HOOK_WIN32W, code, wParam,
1125 /***********************************************************************
1126 * HOOK_ResetQueueHooks
1128 void HOOK_ResetQueueHooks( HQUEUE16 hQueue )
1130 MESSAGEQUEUE *queue;
1132 if ((queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue )) != NULL)
1137 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
1139 hook = queue->hooks[id - WH_MINHOOK];
1142 if( (data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook)) )
1144 data->ownerQueue = hQueue;
1150 QUEUE_Unlock( queue );
1154 /***********************************************************************
1155 * HOOK_FreeModuleHooks
1157 void HOOK_FreeModuleHooks( HMODULE16 hModule )
1159 /* remove all system hooks registered by this module */
1165 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
1167 hook = HOOK_systemHooks[id - WH_MINHOOK];
1169 if( (hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook)) )
1172 if( hptr->ownerModule == hModule )
1174 hptr->flags &= HOOK_MAPTYPE;
1175 HOOK_RemoveHook(hook);
1183 /***********************************************************************
1184 * HOOK_FreeQueueHooks
1186 void HOOK_FreeQueueHooks( HQUEUE16 hQueue )
1188 /* remove all hooks registered by this queue */
1190 HOOKDATA* hptr = NULL;
1194 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
1196 hook = HOOK_GetHook( id, hQueue );
1199 next = HOOK_GetNextHook(hook);
1201 hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
1202 if( hptr && hptr->ownerQueue == hQueue )
1204 hptr->flags &= HOOK_MAPTYPE;
1205 HOOK_RemoveHook(hook);
1213 /***********************************************************************
1214 * SetWindowsHook16 (USER.121)
1216 FARPROC16 WINAPI SetWindowsHook16( INT16 id, HOOKPROC16 proc )
1218 HINSTANCE16 hInst = FarGetOwner16( HIWORD(proc) );
1220 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
1221 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
1223 return (FARPROC16)SetWindowsHookEx16( id, proc, hInst, hTask );
1226 /***********************************************************************
1227 * SetWindowsHookA (USER32.525)
1229 HHOOK WINAPI SetWindowsHookA( INT id, HOOKPROC proc )
1231 return SetWindowsHookExA( id, proc, 0, GetCurrentThreadId() );
1234 /***********************************************************************
1235 * SetWindowsHookW (USER32.528)
1237 HHOOK WINAPI SetWindowsHookW( INT id, HOOKPROC proc )
1239 return SetWindowsHookExW( id, proc, 0, GetCurrentThreadId() );
1243 /***********************************************************************
1244 * SetWindowsHookEx16 (USER.291)
1246 HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst,
1251 FIXME("WH_DEBUG is broken in 16-bit Windows.\n");
1254 return HOOK_SetHook( id, proc, HOOK_WIN16, GetExePtr(hInst), (DWORD)hTask );
1257 /***********************************************************************
1258 * SetWindowsHookExA (USER32.526)
1260 HHOOK WINAPI SetWindowsHookExA( INT id, HOOKPROC proc, HINSTANCE hInst,
1263 return HOOK_SetHook( id, proc, HOOK_WIN32A, MapHModuleLS(hInst), dwThreadId );
1266 /***********************************************************************
1267 * SetWindowsHookExW (USER32.527)
1269 HHOOK WINAPI SetWindowsHookExW( INT id, HOOKPROC proc, HINSTANCE hInst,
1272 return HOOK_SetHook( id, proc, HOOK_WIN32W, MapHModuleLS(hInst), dwThreadId );
1276 /***********************************************************************
1277 * UnhookWindowsHook16 (USER.234)
1279 BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
1281 return UnhookWindowsHook( id, (HOOKPROC)proc );
1284 /***********************************************************************
1285 * UnhookWindowsHook (USER32.557)
1287 BOOL WINAPI UnhookWindowsHook( INT id, HOOKPROC proc )
1289 HANDLE16 hook = HOOK_GetHook( id, GetFastQueue16() );
1291 TRACE("%d %08lx\n", id, (DWORD)proc );
1295 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
1296 if (data->proc == proc) break;
1297 hook = HOOK_GetNextHook( hook );
1299 if (!hook) return FALSE;
1300 return HOOK_RemoveHook( hook );
1304 /***********************************************************************
1305 * UnhookWindowsHookEx16 (USER.292)
1307 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
1309 return UnhookWindowsHookEx( hhook );
1312 /***********************************************************************
1313 * UnhookWindowsHookEx (USER32.558)
1315 BOOL WINAPI UnhookWindowsHookEx( HHOOK hhook )
1317 if (HIWORD(hhook) != HOOK_MAGIC) return FALSE; /* Not a new format hook */
1318 return HOOK_RemoveHook( LOWORD(hhook) );
1322 /***********************************************************************
1323 * CallNextHookEx16 (USER.293)
1325 * I wouldn't have separated this into 16 and 32 bit versions, but I
1326 * need a way to figure out if I need to do a mapping or not.
1328 LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wParam,
1333 if (HIWORD(hhook) != HOOK_MAGIC) return 0; /* Not a new format hook */
1334 if (!(next = HOOK_GetNextHook( LOWORD(hhook) ))) return 0;
1336 return HOOK_CallHook( next, HOOK_WIN16, code, wParam, lParam );
1340 /***********************************************************************
1341 * CallNextHookEx (USER32.17)
1343 * There aren't ANSI and UNICODE versions of this.
1345 LRESULT WINAPI CallNextHookEx( HHOOK hhook, INT code, WPARAM wParam,
1349 INT fromtype; /* figure out Ansi/Unicode */
1352 if (HIWORD(hhook) != HOOK_MAGIC) return 0; /* Not a new format hook */
1353 if (!(next = HOOK_GetNextHook( LOWORD(hhook) ))) return 0;
1355 oldhook = (HOOKDATA *)USER_HEAP_LIN_ADDR( LOWORD(hhook) );
1356 fromtype = oldhook->flags & HOOK_MAPTYPE;
1358 if (fromtype == HOOK_WIN16)
1359 ERR("called from 16bit hook!\n");
1361 return HOOK_CallHook( next, fromtype, code, wParam, lParam );
1365 /***********************************************************************
1366 * DefHookProc16 (USER.235)
1368 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wParam, LPARAM lParam,
1371 /* Note: the *hhook parameter is never used, since we rely on the
1372 * current hook value from the task queue to find the next hook. */
1373 MESSAGEQUEUE *queue;
1376 if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
1377 ret = CallNextHookEx16( queue->hCurHook, code, wParam, lParam );
1378 QUEUE_Unlock( queue );
1383 /***********************************************************************
1384 * CallMsgFilter16 (USER.123)
1386 BOOL16 WINAPI CallMsgFilter16( SEGPTR msg, INT16 code )
1388 if (GetSysModalWindow16()) return FALSE;
1389 if (HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) return TRUE;
1390 return HOOK_CallHooks16( WH_MSGFILTER, code, 0, (LPARAM)msg );
1394 /***********************************************************************
1395 * CallMsgFilter32 (USER.823)
1397 BOOL16 WINAPI CallMsgFilter32_16( SEGPTR msg16_32, INT16 code, BOOL16 wHaveParamHigh )
1399 MSG32_16 *lpmsg16_32 = (MSG32_16 *)PTR_SEG_TO_LIN(msg16_32);
1401 if (wHaveParamHigh == FALSE)
1403 lpmsg16_32->wParamHigh = 0;
1404 /* WARNING: msg16_32->msg has to be the first variable in the struct */
1405 return CallMsgFilter16(msg16_32, code);
1412 msg32.hwnd = lpmsg16_32->msg.hwnd;
1413 msg32.message = lpmsg16_32->msg.message;
1415 MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh);
1416 msg32.lParam = lpmsg16_32->msg.lParam;
1417 msg32.time = lpmsg16_32->msg.time;
1418 msg32.pt.x = (INT)lpmsg16_32->msg.pt.x;
1419 msg32.pt.y = (INT)lpmsg16_32->msg.pt.y;
1421 ret = (BOOL16)CallMsgFilterA(&msg32, (INT)code);
1423 lpmsg16_32->msg.hwnd = msg32.hwnd;
1424 lpmsg16_32->msg.message = msg32.message;
1425 lpmsg16_32->msg.wParam = LOWORD(msg32.wParam);
1426 lpmsg16_32->msg.lParam = msg32.lParam;
1427 lpmsg16_32->msg.time = msg32.time;
1428 lpmsg16_32->msg.pt.x = (INT16)msg32.pt.x;
1429 lpmsg16_32->msg.pt.y = (INT16)msg32.pt.y;
1430 lpmsg16_32->wParamHigh = HIWORD(msg32.wParam);
1437 /***********************************************************************
1438 * CallMsgFilterA (USER32.15)
1441 * FIXME: There are ANSI and UNICODE versions of this, plus an unspecified
1442 * version, plus USER (the 16bit one) has a CallMsgFilter32 function.
1444 BOOL WINAPI CallMsgFilterA( LPMSG msg, INT code )
1446 if (GetSysModalWindow16()) return FALSE; /* ??? */
1447 if (HOOK_CallHooksA( WH_SYSMSGFILTER, code, 0, (LPARAM)msg ))
1449 return HOOK_CallHooksA( WH_MSGFILTER, code, 0, (LPARAM)msg );
1453 /***********************************************************************
1454 * CallMsgFilterW (USER32.16)
1456 BOOL WINAPI CallMsgFilterW( LPMSG msg, INT code )
1458 if (GetSysModalWindow16()) return FALSE; /* ??? */
1459 if (HOOK_CallHooksW( WH_SYSMSGFILTER, code, 0, (LPARAM)msg ))
1461 return HOOK_CallHooksW( WH_MSGFILTER, code, 0, (LPARAM)msg );