Fix MsiRecordSetString for NULL strings and update test case.
[wine.git] / dlls / user / hook16.c
blob073d91dfe3cd53acd07a64deb2fa85719c18c737
1 /*
2 * Windows 16-bit hook functions
4 * Copyright 1994, 1995, 2002 Alexandre Julliard
5 * Copyright 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
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "wownt32.h"
30 #include "wine/winuser16.h"
31 #include "message.h"
32 #include "win.h"
33 #include "user_private.h"
34 #include "winproc.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(hook);
40 static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp );
41 static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp );
42 static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp );
43 static LRESULT CALLBACK call_WH_CALLWNDPROC( INT code, WPARAM wp, LPARAM lp );
44 static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp );
45 static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp );
46 static LRESULT CALLBACK call_WH_SHELL( INT code, WPARAM wp, LPARAM lp );
48 #define WH_MAXHOOK16 WH_SHELL /* Win16 only supports up to WH_SHELL */
49 #define NB_HOOKS16 (WH_MAXHOOK16 - WH_MINHOOK + 1)
51 static const HOOKPROC hook_procs[NB_HOOKS16] =
53 call_WH_MSGFILTER, /* WH_MSGFILTER */
54 NULL, /* WH_JOURNALRECORD */
55 NULL, /* WH_JOURNALPLAYBACK */
56 call_WH_KEYBOARD, /* WH_KEYBOARD */
57 call_WH_GETMESSAGE, /* WH_GETMESSAGE */
58 call_WH_CALLWNDPROC, /* WH_CALLWNDPROC */
59 call_WH_CBT, /* WH_CBT */
60 NULL, /* WH_SYSMSGFILTER */
61 call_WH_MOUSE, /* WH_MOUSE */
62 NULL, /* WH_HARDWARE */
63 NULL, /* WH_DEBUG */
64 call_WH_SHELL /* WH_SHELL */
68 /* this structure is stored in the thread queue */
69 struct hook16_queue_info
71 INT id; /* id of current hook */
72 HHOOK hook[NB_HOOKS16]; /* Win32 hook handles */
73 HOOKPROC16 proc[NB_HOOKS16]; /* 16-bit hook procedures */
78 /***********************************************************************
79 * map_msg_16_to_32
81 inline static void map_msg_16_to_32( const MSG16 *msg16, MSG *msg32 )
83 msg32->hwnd = WIN_Handle32(msg16->hwnd);
84 msg32->message = msg16->message;
85 msg32->wParam = msg16->wParam;
86 msg32->lParam = msg16->lParam;
87 msg32->time = msg16->time;
88 msg32->pt.x = msg16->pt.x;
89 msg32->pt.y = msg16->pt.y;
93 /***********************************************************************
94 * map_msg_32_to_16
96 inline static void map_msg_32_to_16( const MSG *msg32, MSG16 *msg16 )
98 msg16->hwnd = HWND_16(msg32->hwnd);
99 msg16->message = msg32->message;
100 msg16->wParam = msg32->wParam;
101 msg16->lParam = msg32->lParam;
102 msg16->time = msg32->time;
103 msg16->pt.x = msg32->pt.x;
104 msg16->pt.y = msg32->pt.y;
108 /***********************************************************************
109 * call_hook_16
111 static LRESULT call_hook_16( INT id, INT code, WPARAM wp, LPARAM lp )
113 struct hook16_queue_info *info = QUEUE_Current()->hook16_info;
114 WORD args[4];
115 LRESULT ret;
116 INT prev_id = info->id;
117 info->id = id;
119 args[3] = code;
120 args[2] = wp;
121 args[1] = HIWORD(lp);
122 args[0] = LOWORD(lp);
123 WOWCallback16Ex( (DWORD)info->proc[id - WH_MINHOOK], WCB16_PASCAL, sizeof(args), args, &ret );
125 info->id = prev_id;
127 /* Grrr. While the hook procedure is supposed to have an LRESULT return
128 value even in Win16, it seems that for those hook types where the
129 return value is interpreted as BOOL, Windows doesn't actually check
130 the HIWORD ... Some buggy Win16 programs, notably WINFILE, rely on
131 that, because they neglect to clear DX ... */
132 if (id != WH_JOURNALPLAYBACK) ret = LOWORD( ret );
133 return ret;
137 /***********************************************************************
138 * call_WH_MSGFILTER
140 static LRESULT CALLBACK call_WH_MSGFILTER( INT code, WPARAM wp, LPARAM lp )
142 MSG *msg32 = (MSG *)lp;
143 MSG16 msg16;
144 LRESULT ret;
146 map_msg_32_to_16( msg32, &msg16 );
147 lp = MapLS( &msg16 );
148 ret = call_hook_16( WH_MSGFILTER, code, wp, lp );
149 UnMapLS( lp );
150 return ret;
154 /***********************************************************************
155 * call_WH_KEYBOARD
157 static LRESULT CALLBACK call_WH_KEYBOARD( INT code, WPARAM wp, LPARAM lp )
159 return call_hook_16( WH_KEYBOARD, code, wp, lp );
163 /***********************************************************************
164 * call_WH_GETMESSAGE
166 static LRESULT CALLBACK call_WH_GETMESSAGE( INT code, WPARAM wp, LPARAM lp )
168 MSG *msg32 = (MSG *)lp;
169 MSG16 msg16;
170 LRESULT ret;
172 map_msg_32_to_16( msg32, &msg16 );
174 lp = MapLS( &msg16 );
175 ret = call_hook_16( WH_GETMESSAGE, code, wp, lp );
176 UnMapLS( lp );
178 map_msg_16_to_32( &msg16, msg32 );
179 return ret;
183 /***********************************************************************
184 * call_WH_CALLWNDPROC
186 static LRESULT CALLBACK call_WH_CALLWNDPROC( INT code, WPARAM wp, LPARAM lp )
188 CWPSTRUCT *cwp32 = (CWPSTRUCT *)lp;
189 CWPSTRUCT16 cwp16;
190 MSGPARAM16 mp16;
191 LRESULT ret;
193 cwp16.hwnd = HWND_16(cwp32->hwnd);
194 cwp16.lParam = cwp32->lParam;
196 WINPROC_MapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam,
197 &cwp16.message, &cwp16.wParam, &cwp16.lParam );
199 lp = MapLS( &cwp16 );
200 ret = call_hook_16( WH_CALLWNDPROC, code, wp, lp );
201 UnMapLS( lp );
203 mp16.wParam = cwp16.wParam;
204 mp16.lParam = cwp16.lParam;
205 mp16.lResult = 0;
206 WINPROC_UnmapMsg32ATo16( cwp32->hwnd, cwp32->message, cwp32->wParam, cwp32->lParam, &mp16 );
207 return ret;
211 /***********************************************************************
212 * call_WH_CBT
214 static LRESULT CALLBACK call_WH_CBT( INT code, WPARAM wp, LPARAM lp )
216 LRESULT ret = 0;
218 switch (code)
220 case HCBT_CREATEWND:
222 CBT_CREATEWNDA *cbtcw32 = (CBT_CREATEWNDA *)lp;
223 CBT_CREATEWND16 cbtcw16;
224 CREATESTRUCT16 cs16;
226 cs16.lpCreateParams = (SEGPTR)cbtcw32->lpcs->lpCreateParams;
227 cs16.hInstance = HINSTANCE_16(cbtcw32->lpcs->hInstance);
228 cs16.hMenu = HMENU_16(cbtcw32->lpcs->hMenu);
229 cs16.hwndParent = HWND_16(cbtcw32->lpcs->hwndParent);
230 cs16.cy = cbtcw32->lpcs->cy;
231 cs16.cx = cbtcw32->lpcs->cx;
232 cs16.y = cbtcw32->lpcs->y;
233 cs16.x = cbtcw32->lpcs->x;
234 cs16.style = cbtcw32->lpcs->style;
235 cs16.lpszName = MapLS( cbtcw32->lpcs->lpszName );
236 cs16.lpszClass = MapLS( cbtcw32->lpcs->lpszClass );
237 cs16.dwExStyle = cbtcw32->lpcs->dwExStyle;
239 cbtcw16.lpcs = (CREATESTRUCT16 *)MapLS( &cs16 );
240 cbtcw16.hwndInsertAfter = HWND_16( cbtcw32->hwndInsertAfter );
242 lp = MapLS( &cbtcw16 );
243 ret = call_hook_16( WH_CBT, code, wp, lp );
244 UnMapLS( cs16.lpszName );
245 UnMapLS( cs16.lpszClass );
247 cbtcw32->hwndInsertAfter = WIN_Handle32( cbtcw16.hwndInsertAfter );
248 UnMapLS( (SEGPTR)cbtcw16.lpcs );
249 UnMapLS( lp );
250 break;
253 case HCBT_ACTIVATE:
255 CBTACTIVATESTRUCT *cas32 = (CBTACTIVATESTRUCT *)lp;
256 CBTACTIVATESTRUCT16 cas16;
258 cas16.fMouse = cas32->fMouse;
259 cas16.hWndActive = HWND_16( cas32->hWndActive );
261 lp = MapLS( &cas16 );
262 ret = call_hook_16( WH_CBT, code, wp, lp );
263 UnMapLS( lp );
264 break;
266 case HCBT_CLICKSKIPPED:
268 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
269 MOUSEHOOKSTRUCT16 ms16;
271 ms16.pt.x = ms32->pt.x;
272 ms16.pt.y = ms32->pt.y;
273 ms16.hwnd = HWND_16( ms32->hwnd );
274 ms16.wHitTestCode = ms32->wHitTestCode;
275 ms16.dwExtraInfo = ms32->dwExtraInfo;
277 lp = MapLS( &ms16 );
278 ret = call_hook_16( WH_CBT, code, wp, lp );
279 UnMapLS( lp );
280 break;
282 case HCBT_MOVESIZE:
284 RECT *rect32 = (RECT *)lp;
285 RECT16 rect16;
287 rect16.left = rect32->left;
288 rect16.top = rect32->top;
289 rect16.right = rect32->right;
290 rect16.bottom = rect32->bottom;
291 lp = MapLS( &rect16 );
292 ret = call_hook_16( WH_CBT, code, wp, lp );
293 UnMapLS( lp );
294 break;
297 return ret;
301 /***********************************************************************
302 * call_WH_MOUSE
304 static LRESULT CALLBACK call_WH_MOUSE( INT code, WPARAM wp, LPARAM lp )
306 MOUSEHOOKSTRUCT *ms32 = (MOUSEHOOKSTRUCT *)lp;
307 MOUSEHOOKSTRUCT16 ms16;
308 LRESULT ret;
310 ms16.pt.x = ms32->pt.x;
311 ms16.pt.y = ms32->pt.y;
312 ms16.hwnd = HWND_16( ms32->hwnd );
313 ms16.wHitTestCode = ms32->wHitTestCode;
314 ms16.dwExtraInfo = ms32->dwExtraInfo;
316 lp = MapLS( &ms16 );
317 ret = call_hook_16( WH_MOUSE, code, wp, lp );
318 UnMapLS( lp );
319 return ret;
323 /***********************************************************************
324 * call_WH_SHELL
326 static LRESULT CALLBACK call_WH_SHELL( INT code, WPARAM wp, LPARAM lp )
328 return call_hook_16( WH_SHELL, code, wp, lp );
332 /***********************************************************************
333 * SetWindowsHook (USER.121)
335 FARPROC16 WINAPI SetWindowsHook16( INT16 id, HOOKPROC16 proc )
337 HINSTANCE16 hInst = FarGetOwner16( HIWORD(proc) );
339 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
340 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
342 return (FARPROC16)SetWindowsHookEx16( id, proc, hInst, hTask );
346 /***********************************************************************
347 * SetWindowsHookEx (USER.291)
349 HHOOK WINAPI SetWindowsHookEx16( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst, HTASK16 hTask )
351 MESSAGEQUEUE *queue = QUEUE_Current();
352 struct hook16_queue_info *info;
353 HHOOK hook;
354 int index = id - WH_MINHOOK;
356 if (!queue) return 0;
357 if (id < WH_MINHOOK || id > WH_MAXHOOK16) return 0;
358 if (!hook_procs[index])
360 FIXME( "hook type %d broken in Win16\n", id );
361 return 0;
363 if (!hTask) FIXME( "System-global hooks (%d) broken in Win16\n", id );
364 else if (hTask != GetCurrentTask())
366 FIXME( "setting hook (%d) on other task not supported\n", id );
367 return 0;
370 if (!(info = queue->hook16_info))
372 if (!(info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*info) ))) return 0;
373 queue->hook16_info = info;
375 if (info->hook[index])
377 FIXME( "Multiple hooks (%d) for the same task not supported yet\n", id );
378 return 0;
380 if (!(hook = SetWindowsHookExA( id, hook_procs[index], 0, GetCurrentThreadId() ))) return 0;
381 info->hook[index] = hook;
382 info->proc[index] = proc;
383 return hook;
387 /***********************************************************************
388 * UnhookWindowsHook (USER.234)
390 BOOL16 WINAPI UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
392 MESSAGEQUEUE *queue = QUEUE_Current();
393 struct hook16_queue_info *info;
394 int index = id - WH_MINHOOK;
396 if (id < WH_MINHOOK || id > WH_MAXHOOK16) return FALSE;
397 if (!queue || !(info = queue->hook16_info)) return FALSE;
398 if (info->proc[index] != proc) return FALSE;
399 if (!UnhookWindowsHookEx( info->hook[index] )) return FALSE;
400 info->hook[index] = 0;
401 info->proc[index] = 0;
402 return TRUE;
406 /***********************************************************************
407 * UnhookWindowsHookEx (USER.292)
409 BOOL16 WINAPI UnhookWindowsHookEx16( HHOOK hhook )
411 MESSAGEQUEUE *queue = QUEUE_Current();
412 struct hook16_queue_info *info;
413 int index;
415 if (!queue || !(info = queue->hook16_info)) return FALSE;
416 for (index = 0; index < NB_HOOKS16; index++)
418 if (info->hook[index] == hhook)
420 info->hook[index] = 0;
421 info->proc[index] = 0;
422 return UnhookWindowsHookEx( hhook );
425 return FALSE;
429 /***********************************************************************
430 * CallMsgFilter32 (USER.823)
432 BOOL16 WINAPI CallMsgFilter32_16( MSG32_16 *lpmsg16_32, INT16 code, BOOL16 wHaveParamHigh )
434 MSG msg32;
435 BOOL16 ret;
437 if (GetSysModalWindow16()) return FALSE;
438 msg32.hwnd = WIN_Handle32( lpmsg16_32->msg.hwnd );
439 msg32.message = lpmsg16_32->msg.message;
440 msg32.lParam = lpmsg16_32->msg.lParam;
441 msg32.time = lpmsg16_32->msg.time;
442 msg32.pt.x = lpmsg16_32->msg.pt.x;
443 msg32.pt.y = lpmsg16_32->msg.pt.y;
444 if (wHaveParamHigh) msg32.wParam = MAKELONG(lpmsg16_32->msg.wParam, lpmsg16_32->wParamHigh);
445 else msg32.wParam = lpmsg16_32->msg.wParam;
447 ret = (BOOL16)CallMsgFilterA(&msg32, code);
449 lpmsg16_32->msg.hwnd = HWND_16( msg32.hwnd );
450 lpmsg16_32->msg.message = msg32.message;
451 lpmsg16_32->msg.wParam = LOWORD(msg32.wParam);
452 lpmsg16_32->msg.lParam = msg32.lParam;
453 lpmsg16_32->msg.time = msg32.time;
454 lpmsg16_32->msg.pt.x = msg32.pt.x;
455 lpmsg16_32->msg.pt.y = msg32.pt.y;
456 if (wHaveParamHigh) lpmsg16_32->wParamHigh = HIWORD(msg32.wParam);
457 return ret;
461 /***********************************************************************
462 * CallMsgFilter (USER.123)
464 BOOL16 WINAPI CallMsgFilter16( MSG16 *msg, INT16 code )
466 return CallMsgFilter32_16( (MSG32_16 *)msg, code, FALSE );
470 /***********************************************************************
471 * CallNextHookEx (USER.293)
473 LRESULT WINAPI CallNextHookEx16( HHOOK hhook, INT16 code, WPARAM16 wparam, LPARAM lparam )
475 MESSAGEQUEUE *queue = QUEUE_Current();
476 struct hook16_queue_info *info;
477 LRESULT ret = 0;
479 if (!queue || !(info = queue->hook16_info)) return 0;
481 switch (info->id)
483 case WH_MSGFILTER:
485 MSG16 *msg16 = MapSL(lparam);
486 MSG msg32;
488 map_msg_16_to_32( msg16, &msg32 );
489 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
490 break;
493 case WH_GETMESSAGE:
495 MSG16 *msg16 = MapSL(lparam);
496 MSG msg32;
498 map_msg_16_to_32( msg16, &msg32 );
499 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&msg32 );
500 map_msg_32_to_16( &msg32, msg16 );
501 break;
504 case WH_CALLWNDPROC:
506 CWPSTRUCT16 *cwp16 = MapSL(lparam);
507 CWPSTRUCT cwp32;
509 cwp32.hwnd = WIN_Handle32(cwp16->hwnd);
510 cwp32.lParam = cwp16->lParam;
512 WINPROC_MapMsg16To32A( cwp32.hwnd, cwp16->message, cwp16->wParam,
513 &cwp32.message, &cwp32.wParam, &cwp32.lParam );
514 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cwp32 );
515 WINPROC_UnmapMsg16To32A( cwp32.hwnd, cwp32.message, cwp32.wParam, cwp32.lParam, 0 );
516 break;
519 case WH_CBT:
520 switch (code)
522 case HCBT_CREATEWND:
524 CBT_CREATEWNDA cbtcw32;
525 CREATESTRUCTA cs32;
526 CBT_CREATEWND16 *cbtcw16 = MapSL(lparam);
527 CREATESTRUCT16 *cs16 = MapSL( (SEGPTR)cbtcw16->lpcs );
529 cbtcw32.lpcs = &cs32;
530 cbtcw32.hwndInsertAfter = WIN_Handle32( cbtcw16->hwndInsertAfter );
532 cs32.lpCreateParams = (LPVOID)cs16->lpCreateParams;
533 cs32.hInstance = HINSTANCE_32(cs16->hInstance);
534 cs32.hMenu = HMENU_32(cs16->hMenu);
535 cs32.hwndParent = WIN_Handle32(cs16->hwndParent);
536 cs32.cy = cs16->cy;
537 cs32.cx = cs16->cx;
538 cs32.y = cs16->y;
539 cs32.x = cs16->x;
540 cs32.style = cs16->style;
541 cs32.lpszName = MapSL( cs16->lpszName );
542 cs32.lpszClass = MapSL( cs16->lpszClass );
543 cs32.dwExStyle = cs16->dwExStyle;
545 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cbtcw32 );
546 cbtcw16->hwndInsertAfter = HWND_16( cbtcw32.hwndInsertAfter );
547 break;
549 case HCBT_ACTIVATE:
551 CBTACTIVATESTRUCT16 *cas16 = MapSL(lparam);
552 CBTACTIVATESTRUCT cas32;
553 cas32.fMouse = cas16->fMouse;
554 cas32.hWndActive = WIN_Handle32(cas16->hWndActive);
555 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&cas32 );
556 break;
558 case HCBT_CLICKSKIPPED:
560 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
561 MOUSEHOOKSTRUCT ms32;
563 ms32.pt.x = ms16->pt.x;
564 ms32.pt.y = ms16->pt.y;
565 /* wHitTestCode may be negative, so convince compiler to do
566 correct sign extension. Yay. :| */
567 ms32.wHitTestCode = (INT)(INT16)ms16->wHitTestCode;
568 ms32.dwExtraInfo = ms16->dwExtraInfo;
569 ms32.hwnd = WIN_Handle32( ms16->hwnd );
570 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 );
571 break;
573 case HCBT_MOVESIZE:
575 RECT16 *rect16 = MapSL(lparam);
576 RECT rect32;
578 rect32.left = rect16->left;
579 rect32.top = rect16->top;
580 rect32.right = rect16->right;
581 rect32.bottom = rect16->bottom;
582 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&rect32 );
583 break;
586 break;
588 case WH_MOUSE:
590 MOUSEHOOKSTRUCT16 *ms16 = MapSL(lparam);
591 MOUSEHOOKSTRUCT ms32;
593 ms32.pt.x = ms16->pt.x;
594 ms32.pt.y = ms16->pt.y;
595 /* wHitTestCode may be negative, so convince compiler to do
596 correct sign extension. Yay. :| */
597 ms32.wHitTestCode = (INT)((INT16)ms16->wHitTestCode);
598 ms32.dwExtraInfo = ms16->dwExtraInfo;
599 ms32.hwnd = WIN_Handle32(ms16->hwnd);
600 ret = CallNextHookEx( hhook, code, wparam, (LPARAM)&ms32 );
601 break;
604 case WH_SHELL:
605 case WH_KEYBOARD:
606 ret = CallNextHookEx( hhook, code, wparam, lparam );
607 break;
609 case WH_HARDWARE:
610 case WH_FOREGROUNDIDLE:
611 case WH_CALLWNDPROCRET:
612 case WH_SYSMSGFILTER:
613 case WH_JOURNALRECORD:
614 case WH_JOURNALPLAYBACK:
615 default:
616 FIXME("\t[%i] 16to32 translation unimplemented\n", info->id);
617 ret = CallNextHookEx( hhook, code, wparam, lparam );
618 break;
620 return ret;
624 /***********************************************************************
625 * DefHookProc (USER.235)
627 LRESULT WINAPI DefHookProc16( INT16 code, WPARAM16 wparam, LPARAM lparam, HHOOK *hhook )
629 return CallNextHookEx16( *hhook, code, wparam, lparam );