Convert most of the file APIs to Unicode.
[wine/wine64.git] / windows / hook.c
blobadd34d6a68eca066b8b87f72d024798f8f56a73d
1 /*
2 * Windows hook functions
4 * Copyright 1994, 1995 Alexandre Julliard
5 * 1996 Andrew Lewycky
7 * Based on investigations by Alex Korobka
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 * Warning!
26 * A HHOOK is a 32-bit handle for compatibility with Windows 3.0 where it was
27 * a pointer to the next function. Now it is in fact composed of a USER heap
28 * handle in the low 16 bits and of a HOOK_MAGIC value in the high 16 bits.
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "wine/winuser16.h"
36 #include "wine/winbase16.h"
37 #include "hook.h"
38 #include "win.h"
39 #include "queue.h"
40 #include "user.h"
41 #include "heap.h"
42 #include "struct32.h"
43 #include "winproc.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(hook);
48 #include "pshpack1.h"
50 /* Hook data (pointed to by a HHOOK) */
51 typedef struct
53 HANDLE16 next; /* 00 Next hook in chain */
54 HOOKPROC proc; /* 02 Hook procedure (original) */
55 INT16 id; /* 06 Hook id (WH_xxx) */
56 HQUEUE16 ownerQueue; /* 08 Owner queue (0 for system hook) */
57 HMODULE16 ownerModule; /* 0a Owner module */
58 WORD flags; /* 0c flags */
59 } HOOKDATA;
61 #include "poppack.h"
63 #define HOOK_MAGIC ((int)'H' | (int)'K' << 8) /* 'HK' */
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 /***********************************************************************
76 * call_hook_16
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 );
87 return ret;
91 /***********************************************************************
92 * call_hook_16_to_32
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,
97 BOOL unicode )
99 LRESULT ret = 0;
101 switch( id )
103 case WH_MSGFILTER:
104 case WH_SYSMSGFILTER:
105 case WH_JOURNALRECORD:
107 MSG16 *msg16 = MapSL(lparam);
108 MSG msg32;
110 STRUCT32_MSG16to32( msg16, &msg32 );
111 ret = proc( code, wparam, (LPARAM)&msg32 );
112 break;
115 case WH_GETMESSAGE:
117 MSG16 *msg16 = MapSL(lparam);
118 MSG msg32;
120 STRUCT32_MSG16to32( msg16, &msg32 );
121 ret = proc( code, wparam, (LPARAM)&msg32 );
122 STRUCT32_MSG32to16( &msg32, msg16 );
123 break;
126 case WH_JOURNALPLAYBACK:
128 EVENTMSG16 *em16 = MapSL(lparam);
129 EVENTMSG em32;
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 );
137 break;
140 case WH_CALLWNDPROC:
142 CWPSTRUCT16 *cwp16 = MapSL(lparam);
143 CWPSTRUCT cwp32;
145 cwp32.hwnd = WIN_Handle32(cwp16->hwnd);
146 cwp32.lParam = cwp16->lParam;
148 if (unicode)
149 WINPROC_MapMsg16To32W( cwp32.hwnd, cwp16->message, cwp16->wParam,
150 &cwp32.message, &cwp32.wParam, &cwp32.lParam );
151 else
152 WINPROC_MapMsg16To32A( cwp32.hwnd, cwp16->message, cwp16->wParam,
153 &cwp32.message, &cwp32.wParam, &cwp32.lParam );
155 ret = proc( code, wparam, (LPARAM)&cwp32 );
157 if (unicode)
158 WINPROC_UnmapMsg16To32W( cwp32.hwnd, cwp32.message, cwp32.wParam, cwp32.lParam, 0 );
159 else
160 WINPROC_UnmapMsg16To32A( cwp32.hwnd, cwp32.message, cwp32.wParam, cwp32.lParam, 0 );
161 break;
164 case WH_CBT:
165 switch (code)
167 case HCBT_CREATEWND:
169 CBT_CREATEWNDA cbtcw32;
170 CREATESTRUCTA cs32;
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 );
178 if (unicode)
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 );
186 else
188 cs32.lpszName = MapSL( cs16->lpszName );
189 cs32.lpszClass = MapSL( cs16->lpszClass );
190 ret = proc( code, wparam, (LPARAM)&cbtcw32 );
192 cbtcw16->hwndInsertAfter = WIN_Handle16( cbtcw32.hwndInsertAfter );
193 break;
195 case HCBT_ACTIVATE:
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 );
202 break;
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 );
217 break;
219 case HCBT_MOVESIZE:
221 RECT16 *rect16 = MapSL(lparam);
222 RECT rect32;
224 CONV_RECT16TO32( rect16, &rect32 );
225 ret = proc( code, wparam, (LPARAM)&rect32 );
226 break;
229 break;
231 case WH_MOUSE:
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 );
244 break;
247 case WH_DEBUG:
249 DEBUGHOOKINFO16 *dh16 = MapSL(lparam);
250 DEBUGHOOKINFO dh32;
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 );
261 break;
264 case WH_SHELL:
265 case WH_KEYBOARD:
266 ret = proc( code, wparam, lparam );
267 break;
269 case WH_HARDWARE:
270 case WH_FOREGROUNDIDLE:
271 case WH_CALLWNDPROCRET:
272 default:
273 FIXME("\t[%i] 16to32 translation unimplemented\n", id);
274 ret = proc( code, wparam, lparam );
275 break;
277 return ret;
281 /***********************************************************************
282 * call_hook_32_to_16
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,
287 BOOL unicode )
289 LRESULT ret = 0;
291 switch (id)
293 case WH_MSGFILTER:
294 case WH_SYSMSGFILTER:
295 case WH_JOURNALRECORD:
297 MSG *msg32 = (MSG *)lparam;
298 MSG16 msg16;
300 STRUCT32_MSG32to16( msg32, &msg16 );
301 lparam = MapLS( &msg16 );
302 ret = call_hook_16( proc, id, code, wparam, lparam );
303 UnMapLS( lparam );
304 break;
307 case WH_GETMESSAGE:
309 MSG *msg32 = (MSG *)lparam;
310 MSG16 msg16;
312 STRUCT32_MSG32to16( msg32, &msg16 );
313 lparam = MapLS( &msg16 );
314 ret = call_hook_16( proc, id, code, wparam, lparam );
315 UnMapLS( lparam );
316 STRUCT32_MSG16to32( &msg16, msg32 );
317 break;
320 case WH_JOURNALPLAYBACK:
322 EVENTMSG *em32 = (EVENTMSG *)lparam;
323 EVENTMSG16 em16;
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 );
331 UnMapLS( lparam );
332 break;
335 case WH_CALLWNDPROC:
337 CWPSTRUCT *cwp32 = (CWPSTRUCT *)lparam;
338 CWPSTRUCT16 cwp16;
339 MSGPARAM16 mp16;
341 cwp16.hwnd = WIN_Handle16(cwp32->hwnd);
342 cwp16.lParam = cwp32->lParam;
344 if (unicode)
345 WINPROC_MapMsg32WTo16( cwp32->hwnd, cwp32->message, cwp32->wParam,
346 &cwp16.message, &cwp16.wParam, &cwp16.lParam );
347 else
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 );
353 UnMapLS( lparam );
355 mp16.wParam = cwp16.wParam;
356 mp16.lParam = cwp16.lParam;
357 mp16.lResult = 0;
358 if (unicode)
359 WINPROC_UnmapMsg32WTo16( cwp32->hwnd, cwp32->message, cwp32->wParam,
360 cwp32->lParam, &mp16 );
361 else
362 WINPROC_UnmapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam,
363 cwp32->lParam, &mp16 );
364 break;
367 case WH_CBT:
368 switch (code)
370 case HCBT_CREATEWND:
372 CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lparam;
373 CBT_CREATEWND16 cbtcw16;
374 CREATESTRUCT16 cs16;
376 STRUCT32_CREATESTRUCT32Ato16( cbtcw32->lpcs, &cs16 );
377 cbtcw16.lpcs = (CREATESTRUCT16 *)MapLS( &cs16 );
378 cbtcw16.hwndInsertAfter = WIN_Handle16( cbtcw32->hwndInsertAfter );
379 lparam = MapLS( &cbtcw16 );
381 if (unicode)
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 );
389 else
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 );
399 UnMapLS( lparam );
400 break;
403 case HCBT_ACTIVATE:
405 CBTACTIVATESTRUCT *cas32 = (CBTACTIVATESTRUCT *)lparam;
406 CBTACTIVATESTRUCT16 cas16;
408 cas16.fMouse = cas32->fMouse;
409 cas16.hWndActive = WIN_Handle16( cas32->hWndActive );
411 lparam = MapLS( &cas16 );
412 ret = call_hook_16( proc, id, code, wparam, lparam );
413 UnMapLS( lparam );
414 break;
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 = WIN_Handle16( 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 );
429 UnMapLS( lparam );
430 break;
432 case HCBT_MOVESIZE:
434 RECT *rect32 = (RECT *)lparam;
435 RECT16 rect16;
437 CONV_RECT32TO16( rect32, &rect16 );
438 lparam = MapLS( &rect16 );
439 ret = call_hook_16( proc, id, code, wparam, lparam );
440 UnMapLS( lparam );
441 break;
444 break;
446 case WH_MOUSE:
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 = WIN_Handle16( 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 );
459 UnMapLS( lparam );
460 break;
463 case WH_DEBUG:
465 DEBUGHOOKINFO *dh32 = (DEBUGHOOKINFO *)lparam;
466 DEBUGHOOKINFO16 dh16;
468 dh16.hModuleHook = 0; /* FIXME */
469 dh16.reserved = 0;
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 );
476 UnMapLS( lparam );
477 break;
480 case WH_SHELL:
481 case WH_KEYBOARD:
482 ret = call_hook_16( proc, id, code, wparam, lparam );
483 break;
485 case WH_HARDWARE:
486 case WH_FOREGROUNDIDLE:
487 case WH_CALLWNDPROCRET:
488 default:
489 FIXME("\t[%i] 32to16 translation unimplemented\n", id);
490 ret = call_hook_16( proc, id, code, wparam, lparam );
491 break;
493 return ret;
497 /***********************************************************************
498 * call_hook_32_to_32
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,
503 BOOL to_unicode )
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;
511 CREATESTRUCTW csW;
512 LRESULT ret;
514 cbtcwW.lpcs = &csW;
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 );
526 return ret;
528 else /* Unicode to ASCII */
530 CBT_CREATEWNDW *cbtcwW = (CBT_CREATEWNDW *)lparam;
531 CBT_CREATEWNDA cbtcwA;
532 CREATESTRUCTA csA;
533 LRESULT ret;
535 cbtcwA.lpcs = &csA;
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 );
547 return ret;
552 /***********************************************************************
553 * call_hook
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);
561 LRESULT ret;
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 );
570 else /* 32->16 */
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 );
581 else
582 ret = call_hook_32_to_32( data->proc, data->id, code, wparam,
583 lparam, (type == HOOK_WIN32W) );
585 WIN_RestoreWndsLock(iWndsLocks);
586 return ret;
590 /***********************************************************************
591 * HOOK_GetNextHook
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 /***********************************************************************
609 * HOOK_GetHook
611 * Get the first hook for a given type.
613 static HHOOK HOOK_GetHook( INT16 id )
615 MESSAGEQUEUE *queue;
616 HANDLE16 handle = 0;
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 /***********************************************************************
626 * HOOK_SetHook
628 * Install a given hook.
630 static HHOOK HOOK_SetHook( INT16 id, LPVOID proc, INT type,
631 HMODULE16 hModule, DWORD dwThreadId )
633 HOOKDATA *data;
634 HANDLE16 handle;
635 HQUEUE16 hQueue = 0;
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 )))
652 return 0;
655 /* Create the hook structure */
657 if (!(handle = USER_HEAP_ALLOC( sizeof(HOOKDATA) ))) return 0;
658 data = (HOOKDATA *) USER_HEAP_LIN_ADDR( handle );
659 data->proc = proc;
660 data->id = id;
661 data->ownerQueue = hQueue;
662 data->ownerModule = hModule;
663 data->flags = type;
665 /* Insert it in the correct linked list */
667 if (hQueue)
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 );
674 else
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 /***********************************************************************
687 * HOOK_RemoveHook
689 * Remove a hook from the list.
691 static BOOL HOOK_RemoveHook( HHOOK hook )
693 HOOKDATA *data;
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;
704 return TRUE;
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));
727 return TRUE;
731 /***********************************************************************
732 * HOOK_FindValidHook
734 static HHOOK HOOK_FindValidHook( HHOOK hook )
736 HOOKDATA *data;
738 for (;;)
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 /***********************************************************************
747 * HOOK_CallHook
749 * Call a hook procedure.
751 static LRESULT HOOK_CallHook( HHOOK hook, INT fromtype, INT code,
752 WPARAM wParam, LPARAM lParam )
754 MESSAGEQUEUE *queue;
755 HANDLE16 prevHandle;
756 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(HHOOK_16(hook));
757 LRESULT ret;
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 );
773 return ret;
776 /***********************************************************************
777 * Exported Functions & APIs
780 /***********************************************************************
781 * HOOK_IsHooked
783 * Replacement for calling HOOK_GetHook from other modules.
785 BOOL HOOK_IsHooked( INT16 id )
787 return HOOK_GetHook( id ) != 0;
791 /***********************************************************************
792 * HOOK_CallHooks16
794 * Call a hook chain.
796 LRESULT HOOK_CallHooks16( INT16 id, INT16 code, WPARAM16 wParam,
797 LPARAM lParam )
799 HHOOK hook;
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 /***********************************************************************
807 * HOOK_CallHooksA
809 * Call a hook chain.
811 LRESULT HOOK_CallHooksA( INT id, INT code, WPARAM wParam,
812 LPARAM lParam )
814 HHOOK hook;
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 /***********************************************************************
822 * HOOK_CallHooksW
824 * Call a hook chain.
826 LRESULT HOOK_CallHooksW( INT id, INT code, WPARAM wParam,
827 LPARAM lParam )
829 HHOOK hook;
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,
834 lParam );
838 /***********************************************************************
839 * HOOK_FreeModuleHooks
841 void HOOK_FreeModuleHooks( HMODULE16 hModule )
843 /* remove all system hooks registered by this module */
845 HOOKDATA* hptr;
846 HANDLE16 handle, next;
847 int id;
849 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
851 handle = HOOK_systemHooks[id - WH_MINHOOK];
852 while( handle )
853 if( (hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(handle)) )
855 next = hptr->next;
856 if( hptr->ownerModule == hModule )
858 hptr->flags &= HOOK_MAPTYPE;
859 HOOK_RemoveHook(HHOOK_32(handle));
861 handle = next;
863 else handle = 0;
867 /***********************************************************************
868 * HOOK_FreeQueueHooks
870 void HOOK_FreeQueueHooks(void)
872 /* remove all hooks registered by the current queue */
874 HOOKDATA* hptr = NULL;
875 HHOOK hook, next;
876 int id;
878 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
880 hook = HOOK_GetHook( id );
881 while( hook )
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);
891 hook = next;
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)
929 * SetWindowsHookEx16 (USER32.@)
931 HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst,
932 HTASK16 hTask )
934 if (id == WH_DEBUG)
936 FIXME("WH_DEBUG is broken in 16-bit Windows.\n");
937 return 0;
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,
946 DWORD dwThreadId )
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,
955 DWORD dwThreadId )
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 );
978 while (hook)
980 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(HHOOK_16(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)
1008 * CallNextHookEx16 (USER32.@)
1010 * I wouldn't have separated this into 16 and 32 bit versions, but I
1011 * need a way to figure out if I need to do a mapping or not.
1013 LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wParam,
1014 LPARAM lParam )
1016 HHOOK next;
1018 if (!(next = HOOK_GetNextHook(hhook))) return 0;
1020 return HOOK_CallHook( next, HOOK_WIN16, code, wParam, lParam );
1024 /***********************************************************************
1025 * CallNextHookEx (USER32.@)
1027 * There aren't ANSI and UNICODE versions of this.
1029 LRESULT WINAPI CallNextHookEx( HHOOK hhook, INT code, WPARAM wParam,
1030 LPARAM lParam )
1032 HHOOK next;
1033 INT fromtype; /* figure out Ansi/Unicode */
1034 HOOKDATA *oldhook;
1036 if (!(next = HOOK_GetNextHook(hhook))) return 0;
1038 oldhook = (HOOKDATA *)USER_HEAP_LIN_ADDR(HHOOK_16(hhook));
1039 fromtype = oldhook->flags & HOOK_MAPTYPE;
1041 if (fromtype == HOOK_WIN16)
1042 ERR("called from 16bit hook!\n");
1044 return HOOK_CallHook( next, fromtype, code, wParam, lParam );
1048 /***********************************************************************
1049 * DefHookProc (USER.235)
1051 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wParam, LPARAM lParam,
1052 HHOOK *hhook )
1054 /* Note: the *hhook parameter is never used, since we rely on the
1055 * current hook value from the task queue to find the next hook. */
1056 MESSAGEQUEUE *queue;
1058 if (!(queue = QUEUE_Current())) return 0;
1059 return CallNextHookEx16(HHOOK_32(queue->hCurHook), code, wParam, lParam);
1063 /***********************************************************************
1064 * CallMsgFilter (USER.123)
1066 BOOL16 WINAPI CallMsgFilter16( SEGPTR msg, INT16 code )
1068 if (GetSysModalWindow16()) return FALSE;
1069 if (HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) return TRUE;
1070 return HOOK_CallHooks16( WH_MSGFILTER, code, 0, (LPARAM)msg );
1074 /***********************************************************************
1075 * CallMsgFilter32 (USER.823)
1077 BOOL16 WINAPI CallMsgFilter32_16( SEGPTR msg16_32, INT16 code, BOOL16 wHaveParamHigh )
1079 MSG32_16 *lpmsg16_32 = MapSL(msg16_32);
1081 if (wHaveParamHigh == FALSE)
1083 lpmsg16_32->wParamHigh = 0;
1084 /* WARNING: msg16_32->msg has to be the first variable in the struct */
1085 return CallMsgFilter16(msg16_32, code);
1087 else
1089 MSG msg32;
1090 BOOL16 ret;
1092 msg32.hwnd = WIN_Handle32( lpmsg16_32->msg.hwnd );
1093 msg32.message = lpmsg16_32->msg.message;
1094 msg32.wParam = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh);
1095 msg32.lParam = lpmsg16_32->msg.lParam;
1096 msg32.time = lpmsg16_32->msg.time;
1097 msg32.pt.x = lpmsg16_32->msg.pt.x;
1098 msg32.pt.y = lpmsg16_32->msg.pt.y;
1100 ret = (BOOL16)CallMsgFilterA(&msg32, (INT)code);
1102 lpmsg16_32->msg.hwnd = WIN_Handle16( msg32.hwnd );
1103 lpmsg16_32->msg.message = msg32.message;
1104 lpmsg16_32->msg.wParam = LOWORD(msg32.wParam);
1105 lpmsg16_32->msg.lParam = msg32.lParam;
1106 lpmsg16_32->msg.time = msg32.time;
1107 lpmsg16_32->msg.pt.x = msg32.pt.x;
1108 lpmsg16_32->msg.pt.y = msg32.pt.y;
1109 lpmsg16_32->wParamHigh = HIWORD(msg32.wParam);
1111 return ret;
1116 /***********************************************************************
1117 * CallMsgFilterA (USER32.@)
1119 * FIXME: There are ANSI and UNICODE versions of this, plus an unspecified
1120 * version, plus USER (the 16bit one) has a CallMsgFilter32 function.
1122 BOOL WINAPI CallMsgFilterA( LPMSG msg, INT code )
1124 if (GetSysModalWindow16()) return FALSE; /* ??? */
1125 if (HOOK_CallHooksA( WH_SYSMSGFILTER, code, 0, (LPARAM)msg ))
1126 return TRUE;
1127 return HOOK_CallHooksA( WH_MSGFILTER, code, 0, (LPARAM)msg );
1131 /***********************************************************************
1132 * CallMsgFilterW (USER32.@)
1134 BOOL WINAPI CallMsgFilterW( LPMSG msg, INT code )
1136 if (GetSysModalWindow16()) return FALSE; /* ??? */
1137 if (HOOK_CallHooksW( WH_SYSMSGFILTER, code, 0, (LPARAM)msg ))
1138 return TRUE;
1139 return HOOK_CallHooksW( WH_MSGFILTER, code, 0, (LPARAM)msg );
1143 /***********************************************************************
1144 * SetWinEventHook [USER32.@]
1146 * Set up an event hook for a set of events.
1148 * PARAMS
1149 * dwMin [I] Lowest event handled by pfnProc
1150 * dwMax [I] Highest event handled by pfnProc
1151 * hModule [I] DLL containing pfnProc
1152 * pfnProc [I] Callback event hook function
1153 * dwProcess [I] Process to get events from, or 0 for all processes
1154 * dwThread [I] Thread to get events from, or 0 for all threads
1155 * dwFlags [I] Flags indicating the status of pfnProc
1157 * RETURNS
1158 * Success: A handle representing the hook.
1159 * Failure: A NULL handle.
1161 * BUGS
1162 * Not implemented.
1164 HWINEVENTHOOK WINAPI SetWinEventHook(DWORD dwMin, DWORD dwMax, HMODULE hModule,
1165 WINEVENTPROC pfnProc, DWORD dwProcess,
1166 DWORD dwThread, DWORD dwFlags)
1168 FIXME("(%ld,%ld,0x%08x,%p,%ld,%ld,0x%08lx)-stub!\n", dwMin, dwMax, hModule,
1169 pfnProc, dwProcess, dwThread, dwFlags);
1171 return (HWINEVENTHOOK)0;
1174 /***********************************************************************
1175 * UnhookWinEvent [USER32.@]
1177 * Remove an event hook for a set of events.
1179 * PARAMS
1180 * hEventHook [I] Event hook to remove
1182 * RETURNS
1183 * Success: TRUE. The event hook has been removed.
1184 * Failure: FALSE, if hEventHook is invalid.
1186 * BUGS
1187 * Not implemented.
1189 BOOL WINAPI UnhookWinEvent(HWINEVENTHOOK hEventHook)
1191 FIXME("(%p)-stub!\n", (void*)hEventHook);
1193 if (!hEventHook)
1194 return FALSE;
1196 return TRUE;
1199 /***********************************************************************
1200 * NotifyWinEvent [USER32.@]
1202 * Inform the OS that an event has occurred.
1204 * PARAMS
1205 * dwEvent [I] Id of the event
1206 * hWnd [I] Window holding the object that created the event
1207 * nId [I] Type of object that created the event
1208 * nChildId [I] Child object of nId, or CHILDID_SELF.
1210 * RETURNS
1211 * Nothing.
1213 * BUGS
1214 * Not implemented.
1216 VOID WINAPI NotifyWinEvent(DWORD dwEvent, HWND hWnd, LONG nId, LONG nChildId)
1218 FIXME("(%ld,0x%08x,%ld,%ld)-stub!\n", dwEvent, hWnd, nId, nChildId);
1221 /***********************************************************************
1222 * IsWinEventHookInstalled [USER32.@]
1224 * Determine if an event hook is installed for an event.
1226 * PARAMS
1227 * dwEvent [I] Id of the event
1229 * RETURNS
1230 * TRUE, If there are any hooks installed for the event.
1231 * FALSE, Otherwise.
1233 * BUGS
1234 * Not implemented.
1236 BOOL WINAPI IsWinEventHookInstalled(DWORD dwEvent)
1238 FIXME("(%ld)-stub!\n", dwEvent);
1239 return TRUE;