Release 970824
[wine/multimedia.git] / if1632 / thunk.c
bloba28c665741b3cd16b8d9a3db617b9533ebfe5e9d
1 /*
2 * Emulator and Win95 thunks
4 * Copyright 1996 Alexandre Julliard
5 * Copyright 1997 Marcus Meissner
6 */
8 #include "windows.h"
9 #include "callback.h"
10 #include "heap.h"
11 #include "hook.h"
12 #include "module.h"
13 #include "winproc.h"
14 #include "stackframe.h"
15 #include "except.h"
16 #include "stddebug.h"
17 #include "debug.h"
19 typedef void (*RELAY)();
21 #pragma pack(1)
23 typedef struct tagTHUNK
25 BYTE popl_eax; /* 0x58 popl %eax (return address)*/
26 BYTE pushl_func; /* 0x68 pushl $proc */
27 FARPROC32 proc WINE_PACKED;
28 BYTE pushl_eax; /* 0x50 pushl %eax */
29 BYTE jmp; /* 0xe9 jmp relay (relative jump)*/
30 RELAY relay WINE_PACKED;
31 struct tagTHUNK *next WINE_PACKED;
32 } THUNK;
34 #pragma pack(4)
36 #define DECL_THUNK(name,proc,relay) \
37 THUNK name = { 0x58, 0x68, (FARPROC32)(proc), 0x50, 0xe9, \
38 (RELAY)((char *)(relay) - (char *)(&(name).next)), NULL }
41 static THUNK *firstThunk = NULL;
43 static LRESULT THUNK_CallWndProc16( WNDPROC16 proc, HWND16 hwnd, UINT16 msg,
44 WPARAM16 wParam, LPARAM lParam );
46 /***********************************************************************
47 * THUNK_Init
49 BOOL32 THUNK_Init(void)
51 /* Set the window proc calling functions */
52 WINPROC_SetCallWndProc16( THUNK_CallWndProc16 );
53 WINPROC_SetCallWndProc32( (WINPROC_CALLWNDPROC32)CallTo32_4 );
54 return TRUE;
58 /***********************************************************************
59 * THUNK_Alloc
61 static THUNK *THUNK_Alloc( FARPROC32 func, RELAY relay )
63 THUNK *thunk = HeapAlloc( GetProcessHeap(), 0, sizeof(*thunk) );
64 if (thunk)
66 thunk->popl_eax = 0x58;
67 thunk->pushl_func = 0x68;
68 thunk->proc = func;
69 thunk->pushl_eax = 0x50;
70 thunk->jmp = 0xe9;
71 thunk->relay = (RELAY)((char *)relay - (char *)(&thunk->next));
72 thunk->next = firstThunk;
73 firstThunk = thunk;
75 return thunk;
79 /***********************************************************************
80 * THUNK_Find
82 static THUNK *THUNK_Find( FARPROC32 func )
84 THUNK *thunk = firstThunk;
85 while (thunk && (thunk->proc != func)) thunk = thunk->next;
86 return thunk;
90 /***********************************************************************
91 * THUNK_Free
93 static void THUNK_Free( THUNK *thunk )
95 if (HEAP_IsInsideHeap( GetProcessHeap(), 0, thunk ))
97 THUNK **prev = &firstThunk;
98 while (*prev && (*prev != thunk)) prev = &(*prev)->next;
99 if (*prev)
101 *prev = thunk->next;
102 HeapFree( GetProcessHeap(), 0, thunk );
103 return;
106 fprintf( stderr, "THUNK_Free: invalid thunk addr %p\n", thunk );
110 /***********************************************************************
111 * THUNK_CallWndProc16
113 * Call a 16-bit window procedure
115 static LRESULT THUNK_CallWndProc16( WNDPROC16 proc, HWND16 hwnd, UINT16 msg,
116 WPARAM16 wParam, LPARAM lParam )
118 if ((msg == WM_CREATE) || (msg == WM_NCCREATE))
120 CREATESTRUCT16 *cs = (CREATESTRUCT16 *)PTR_SEG_TO_LIN(lParam);
121 /* Build the CREATESTRUCT on the 16-bit stack. */
122 /* This is really ugly, but some programs (notably the */
123 /* "Undocumented Windows" examples) want it that way. */
124 return CallTo16_long_lllllllwlwwwl( (FARPROC16)proc,
125 cs->dwExStyle, cs->lpszClass, cs->lpszName, cs->style,
126 MAKELONG( cs->y, cs->x ), MAKELONG( cs->cy, cs->cx ),
127 MAKELONG( cs->hMenu, cs->hwndParent ), cs->hInstance,
128 (LONG)cs->lpCreateParams, hwnd, msg, wParam,
129 IF1632_Saved16_ss_sp - sizeof(CREATESTRUCT16) );
131 return CallTo16_long_wwwl( (FARPROC16)proc, hwnd, msg, wParam, lParam );
135 /***********************************************************************
136 * THUNK_EnumObjects16 (GDI.71)
138 INT16 WINAPI THUNK_EnumObjects16( HDC16 hdc, INT16 nObjType,
139 GOBJENUMPROC16 func, LPARAM lParam )
141 DECL_THUNK( thunk, func, CallTo16_word_ll );
142 return EnumObjects16( hdc, nObjType, (GOBJENUMPROC16)&thunk, lParam );
146 /***********************************************************************
147 * THUNK_EnumObjects32 (GDI32.89)
149 INT32 WINAPI THUNK_EnumObjects32( HDC32 hdc, INT32 nObjType,
150 GOBJENUMPROC32 func, LPARAM lParam )
152 DECL_THUNK( thunk, func, CallTo32_2 );
153 return EnumObjects32( hdc, nObjType, (GOBJENUMPROC32)&thunk, lParam );
157 /*************************************************************************
158 * THUNK_EnumFonts16 (GDI.70)
160 INT16 WINAPI THUNK_EnumFonts16( HDC16 hdc, LPCSTR lpFaceName,
161 FONTENUMPROC16 func, LPARAM lParam )
163 DECL_THUNK( thunk, func, CallTo16_word_llwl );
164 return EnumFonts16( hdc, lpFaceName, (FONTENUMPROC16)&thunk, lParam );
167 /*************************************************************************
168 * THUNK_EnumFonts32A (GDI32.84)
170 INT32 WINAPI THUNK_EnumFonts32A( HDC32 hdc, LPCSTR lpFaceName,
171 FONTENUMPROC32A func, LPARAM lParam )
173 DECL_THUNK( thunk, func, CallTo32_4 );
174 return EnumFonts32A( hdc, lpFaceName, (FONTENUMPROC32A)&thunk, lParam );
177 /*************************************************************************
178 * THUNK_EnumFonts32W (GDI32.85)
180 INT32 WINAPI THUNK_EnumFonts32W( HDC32 hdc, LPCWSTR lpFaceName,
181 FONTENUMPROC32W func, LPARAM lParam )
183 DECL_THUNK( thunk, func, CallTo32_4 );
184 return EnumFonts32W( hdc, lpFaceName, (FONTENUMPROC32W)&thunk, lParam );
187 /******************************************************************
188 * THUNK_EnumMetaFile16 (GDI.175)
190 BOOL16 WINAPI THUNK_EnumMetaFile16( HDC16 hdc, HMETAFILE16 hmf,
191 MFENUMPROC16 func, LPARAM lParam )
193 DECL_THUNK( thunk, func, CallTo16_word_wllwl );
194 return EnumMetaFile16( hdc, hmf, (MFENUMPROC16)&thunk, lParam );
198 /*************************************************************************
199 * THUNK_EnumFontFamilies16 (GDI.330)
201 INT16 WINAPI THUNK_EnumFontFamilies16( HDC16 hdc, LPCSTR lpszFamily,
202 FONTENUMPROC16 func, LPARAM lParam )
204 DECL_THUNK( thunk, func, CallTo16_word_llwl );
205 return EnumFontFamilies16(hdc, lpszFamily, (FONTENUMPROC16)&thunk, lParam);
209 /*************************************************************************
210 * THUNK_EnumFontFamilies32A (GDI32.80)
212 INT32 WINAPI THUNK_EnumFontFamilies32A( HDC32 hdc, LPCSTR lpszFamily,
213 FONTENUMPROC32A func, LPARAM lParam )
215 DECL_THUNK( thunk, func, CallTo32_4 );
216 return EnumFontFamilies32A(hdc,lpszFamily,(FONTENUMPROC32A)&thunk,lParam);
220 /*************************************************************************
221 * THUNK_EnumFontFamilies32W (GDI32.83)
223 INT32 WINAPI THUNK_EnumFontFamilies32W( HDC32 hdc, LPCWSTR lpszFamily,
224 FONTENUMPROC32W func, LPARAM lParam )
226 DECL_THUNK( thunk, func, CallTo32_4 );
227 return EnumFontFamilies32W(hdc,lpszFamily,(FONTENUMPROC32W)&thunk,lParam);
230 /*************************************************************************
231 * THUNK_EnumFontFamiliesEx16 (GDI.613)
233 INT16 WINAPI THUNK_EnumFontFamiliesEx16( HDC16 hdc, LPLOGFONT16 lpLF,
234 FONTENUMPROCEX16 func, LPARAM lParam,
235 DWORD reserved )
237 DECL_THUNK( thunk, func, CallTo16_word_llwl );
238 return EnumFontFamiliesEx16( hdc, lpLF, (FONTENUMPROCEX16)&thunk,
239 lParam, reserved );
243 /*************************************************************************
244 * THUNK_EnumFontFamiliesEx32A (GDI32.81)
246 INT32 WINAPI THUNK_EnumFontFamiliesEx32A( HDC32 hdc, LPLOGFONT32A lpLF,
247 FONTENUMPROCEX32A func, LPARAM lParam,
248 DWORD reserved)
250 DECL_THUNK( thunk, func, CallTo32_4 );
251 return EnumFontFamiliesEx32A( hdc, lpLF, (FONTENUMPROCEX32A)&thunk,
252 lParam, reserved );
256 /*************************************************************************
257 * THUNK_EnumFontFamiliesEx32W (GDI32.82)
259 INT32 WINAPI THUNK_EnumFontFamiliesEx32W( HDC32 hdc, LPLOGFONT32W lpLF,
260 FONTENUMPROCEX32W func, LPARAM lParam,
261 DWORD reserved )
263 DECL_THUNK( thunk, func, CallTo32_4 );
264 return EnumFontFamiliesEx32W( hdc, lpLF, (FONTENUMPROCEX32W)&thunk,
265 lParam, reserved );
269 /**********************************************************************
270 * THUNK_LineDDA16 (GDI.100)
272 void WINAPI THUNK_LineDDA16( INT16 nXStart, INT16 nYStart, INT16 nXEnd,
273 INT16 nYEnd, LINEDDAPROC16 func, LPARAM lParam )
275 DECL_THUNK( thunk, func, CallTo16_word_wwl );
276 LineDDA16( nXStart, nYStart, nXEnd, nYEnd, (LINEDDAPROC16)&thunk, lParam );
280 /**********************************************************************
281 * THUNK_LineDDA32 (GDI32.248)
283 BOOL32 WINAPI THUNK_LineDDA32( INT32 nXStart, INT32 nYStart, INT32 nXEnd,
284 INT32 nYEnd, LINEDDAPROC32 func, LPARAM lParam )
286 DECL_THUNK( thunk, func, CallTo32_3 );
287 return LineDDA32( nXStart, nYStart, nXEnd, nYEnd,
288 (LINEDDAPROC32)&thunk, lParam );
292 /*******************************************************************
293 * THUNK_EnumWindows16 (USER.54)
295 BOOL16 WINAPI THUNK_EnumWindows16( WNDENUMPROC16 func, LPARAM lParam )
297 DECL_THUNK( thunk, func, CallTo16_word_wl );
298 return EnumWindows16( (WNDENUMPROC16)&thunk, lParam );
302 /*******************************************************************
303 * THUNK_EnumWindows32 (USER32.192)
305 BOOL32 WINAPI THUNK_EnumWindows32( WNDENUMPROC32 func, LPARAM lParam )
307 DECL_THUNK( thunk, func, CallTo32_2 );
308 return EnumWindows32( (WNDENUMPROC32)&thunk, lParam );
312 /**********************************************************************
313 * THUNK_EnumChildWindows16 (USER.55)
315 BOOL16 WINAPI THUNK_EnumChildWindows16( HWND16 parent, WNDENUMPROC16 func,
316 LPARAM lParam )
318 DECL_THUNK( thunk, func, CallTo16_word_wl );
319 return EnumChildWindows16( parent, (WNDENUMPROC16)&thunk, lParam );
323 /**********************************************************************
324 * THUNK_EnumChildWindows32 (USER32.177)
326 BOOL32 WINAPI THUNK_EnumChildWindows32( HWND32 parent, WNDENUMPROC32 func,
327 LPARAM lParam )
329 DECL_THUNK( thunk, func, CallTo32_2 );
330 return EnumChildWindows32( parent, (WNDENUMPROC32)&thunk, lParam );
334 /**********************************************************************
335 * THUNK_EnumTaskWindows16 (USER.225)
337 BOOL16 WINAPI THUNK_EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
338 LPARAM lParam )
340 DECL_THUNK( thunk, func, CallTo16_word_wl );
341 return EnumTaskWindows16( hTask, (WNDENUMPROC16)&thunk, lParam );
345 /**********************************************************************
346 * THUNK_EnumThreadWindows (USER32.189)
348 BOOL32 WINAPI THUNK_EnumThreadWindows( DWORD id, WNDENUMPROC32 func,
349 LPARAM lParam )
351 DECL_THUNK( thunk, func, CallTo32_2 );
352 return EnumThreadWindows( id, (WNDENUMPROC32)&thunk, lParam );
356 /***********************************************************************
357 * THUNK_EnumProps16 (USER.27)
359 INT16 WINAPI THUNK_EnumProps16( HWND16 hwnd, PROPENUMPROC16 func )
361 DECL_THUNK( thunk, func, CallTo16_word_wlw );
362 return EnumProps16( hwnd, (PROPENUMPROC16)&thunk );
366 /***********************************************************************
367 * THUNK_EnumProps32A (USER32.185)
369 INT32 WINAPI THUNK_EnumProps32A( HWND32 hwnd, PROPENUMPROC32A func )
371 DECL_THUNK( thunk, func, CallTo32_3 );
372 return EnumProps32A( hwnd, (PROPENUMPROC32A)&thunk );
376 /***********************************************************************
377 * THUNK_EnumProps32W (USER32.188)
379 INT32 WINAPI THUNK_EnumProps32W( HWND32 hwnd, PROPENUMPROC32W func )
381 DECL_THUNK( thunk, func, CallTo32_3 );
382 return EnumProps32W( hwnd, (PROPENUMPROC32W)&thunk );
386 /***********************************************************************
387 * THUNK_EnumPropsEx32A (USER32.186)
389 INT32 WINAPI THUNK_EnumPropsEx32A( HWND32 hwnd, PROPENUMPROCEX32A func,
390 LPARAM lParam)
392 DECL_THUNK( thunk, func, CallTo32_4 );
393 return EnumPropsEx32A( hwnd, (PROPENUMPROCEX32A)&thunk, lParam );
397 /***********************************************************************
398 * THUNK_EnumPropsEx32W (USER32.187)
400 INT32 WINAPI THUNK_EnumPropsEx32W( HWND32 hwnd, PROPENUMPROCEX32W func,
401 LPARAM lParam)
403 DECL_THUNK( thunk, func, CallTo32_4 );
404 return EnumPropsEx32W( hwnd, (PROPENUMPROCEX32W)&thunk, lParam );
408 /***********************************************************************
409 * THUNK_EnumSystemCodePages32A (KERNEL32.92)
411 BOOL32 WINAPI THUNK_EnumSystemCodePages32A( CODEPAGE_ENUMPROC32A func,
412 DWORD flags )
414 DECL_THUNK( thunk, func, CallTo32_1 );
415 return EnumSystemCodePages32A( (CODEPAGE_ENUMPROC32A)&thunk, flags );
419 /***********************************************************************
420 * THUNK_EnumSystemCodePages32W (KERNEL32.93)
422 BOOL32 WINAPI THUNK_EnumSystemCodePages32W( CODEPAGE_ENUMPROC32W func,
423 DWORD flags )
425 DECL_THUNK( thunk, func, CallTo32_1 );
426 return EnumSystemCodePages32W( (CODEPAGE_ENUMPROC32W)&thunk, flags );
429 /***********************************************************************
430 * THUNK_EnumSystemLocales32A (KERNEL32.92)
432 BOOL32 WINAPI THUNK_EnumSystemLocales32A( LOCALE_ENUMPROC32A func, DWORD flags)
434 DECL_THUNK( thunk, func, CallTo32_1 );
435 return EnumSystemLocales32A( (LOCALE_ENUMPROC32A)&thunk, flags );
439 /***********************************************************************
440 * THUNK_EnumSystemLocales32W (KERNEL32.93)
442 BOOL32 WINAPI THUNK_EnumSystemLocales32W( LOCALE_ENUMPROC32W func, DWORD flags)
444 DECL_THUNK( thunk, func, CallTo32_1 );
445 return EnumSystemLocales32W( (LOCALE_ENUMPROC32W)&thunk, flags );
448 /***********************************************************************
449 * THUNK_EnumResourceLanguages32W (KERNEL32.87)
451 BOOL32 WINAPI THUNK_EnumResourceLanguages32W( HMODULE32 hmod, LPCWSTR type,
452 LPCWSTR name,
453 ENUMRESLANGPROC32W func,
454 LONG lParam )
456 DECL_THUNK( thunk, func, CallTo32_5 );
457 return EnumResourceLanguages32W( hmod,type,name,(ENUMRESLANGPROC32W)&thunk, lParam );
460 /***********************************************************************
461 * THUNK_EnumResourceLanguages32A (KERNEL32.86)
463 BOOL32 WINAPI THUNK_EnumResourceLanguages32A( HMODULE32 hmod, LPCSTR type,
464 LPCSTR name,
465 ENUMRESLANGPROC32A func,
466 LONG lParam )
468 DECL_THUNK( thunk, func, CallTo32_5 );
469 return EnumResourceLanguages32A( hmod,type,name,(ENUMRESLANGPROC32A)&thunk, lParam );
472 /***********************************************************************
473 * THUNK_EnumResourceNames32A (KERNEL32.88)
475 BOOL32 WINAPI THUNK_EnumResourceNames32A( HMODULE32 hmod, LPCSTR type,
476 ENUMRESNAMEPROC32A func, LONG lParam)
478 DECL_THUNK( thunk, func, CallTo32_4 );
479 return EnumResourceNames32A( hmod,type,(ENUMRESNAMEPROC32A)&thunk,lParam );
482 /***********************************************************************
483 * THUNK_EnumResourceNames32W (KERNEL32.89)
485 BOOL32 WINAPI THUNK_EnumResourceNames32W( HMODULE32 hmod, LPCWSTR type,
486 ENUMRESNAMEPROC32W func, LONG lParam)
488 DECL_THUNK( thunk, func, CallTo32_4 );
489 return EnumResourceNames32W( hmod,type,(ENUMRESNAMEPROC32W)&thunk, lParam);
492 /***********************************************************************
493 * THUNK_EnumResourceTypes32A (KERNEL32.90)
495 BOOL32 WINAPI THUNK_EnumResourceTypes32A( HMODULE32 hmod,
496 ENUMRESTYPEPROC32A func, LONG lParam)
498 DECL_THUNK( thunk, func, CallTo32_3 );
499 return EnumResourceTypes32A( hmod,(ENUMRESTYPEPROC32A)&thunk, lParam );
502 /***********************************************************************
503 * THUNK_EnumResourceTypes32W (KERNEL32.91)
505 BOOL32 WINAPI THUNK_EnumResourceTypes32W( HMODULE32 hmod,
506 ENUMRESTYPEPROC32W func,
507 LONG lParam )
509 DECL_THUNK( thunk, func, CallTo32_3 );
510 return EnumResourceTypes32W( hmod,(ENUMRESTYPEPROC32W)&thunk, lParam );
514 /***********************************************************************
515 * THUNK_GrayString16 (USER.185)
517 BOOL16 WINAPI THUNK_GrayString16( HDC16 hdc, HBRUSH16 hbr,
518 GRAYSTRINGPROC16 func, LPARAM lParam,
519 INT16 cch, INT16 x, INT16 y,
520 INT16 cx, INT16 cy )
522 DECL_THUNK( thunk, func, CallTo16_word_wlw );
523 if (!func)
524 return GrayString16( hdc, hbr, NULL, lParam, cch, x, y, cx, cy );
525 else
526 return GrayString16( hdc, hbr, (GRAYSTRINGPROC16)&thunk, lParam, cch,
527 x, y, cx, cy );
531 /***********************************************************************
532 * THUNK_GrayString32A (USER32.314)
534 BOOL32 WINAPI THUNK_GrayString32A( HDC32 hdc, HBRUSH32 hbr,
535 GRAYSTRINGPROC32 func, LPARAM lParam,
536 INT32 cch, INT32 x, INT32 y,
537 INT32 cx, INT32 cy )
539 DECL_THUNK( thunk, func, CallTo32_3 );
540 if (!func)
541 return GrayString32A( hdc, hbr, NULL, lParam, cch, x, y, cx, cy );
542 else
543 return GrayString32A( hdc, hbr, (GRAYSTRINGPROC32)&thunk, lParam, cch,
544 x, y, cx, cy );
548 /***********************************************************************
549 * THUNK_GrayString32W (USER32.315)
551 BOOL32 WINAPI THUNK_GrayString32W( HDC32 hdc, HBRUSH32 hbr,
552 GRAYSTRINGPROC32 func,
553 LPARAM lParam, INT32 cch, INT32 x, INT32 y,
554 INT32 cx, INT32 cy )
556 DECL_THUNK( thunk, func, CallTo32_3 );
557 if (!func)
558 return GrayString32W( hdc, hbr, NULL, lParam, cch, x, y, cx, cy );
559 else
560 return GrayString32W( hdc, hbr, (GRAYSTRINGPROC32)&thunk, lParam, cch,
561 x, y, cx, cy );
565 /***********************************************************************
566 * THUNK_SetWindowsHook16 (USER.121)
568 FARPROC16 WINAPI THUNK_SetWindowsHook16( INT16 id, HOOKPROC16 proc )
570 HINSTANCE16 hInst = FarGetOwner( HIWORD(proc) );
571 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
572 THUNK *thunk = THUNK_Alloc( (FARPROC16)proc, (RELAY)CallTo16_long_wwl );
573 if (!thunk) return 0;
574 return (FARPROC16)SetWindowsHookEx16( id, (HOOKPROC16)thunk, hInst, hTask);
578 /***********************************************************************
579 * THUNK_UnhookWindowsHook16 (USER.234)
581 BOOL16 WINAPI THUNK_UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
583 BOOL16 ret;
584 THUNK *thunk = THUNK_Find( (FARPROC16)proc );
585 if (!thunk) return FALSE;
586 ret = UnhookWindowsHook16( id, (HOOKPROC16)thunk );
587 THUNK_Free( thunk );
588 return ret;
592 /***********************************************************************
593 * THUNK_SetWindowsHookEx16 (USER.291)
595 HHOOK WINAPI THUNK_SetWindowsHookEx16( INT16 id, HOOKPROC16 proc,
596 HINSTANCE16 hInst, HTASK16 hTask )
598 THUNK *thunk = THUNK_Alloc( (FARPROC16)proc, (RELAY)CallTo16_long_wwl );
599 if (!thunk) return 0;
600 return SetWindowsHookEx16( id, (HOOKPROC16)thunk, hInst, hTask );
604 /***********************************************************************
605 * THUNK_UnhookWindowHookEx16 (USER.292)
607 BOOL16 WINAPI THUNK_UnhookWindowsHookEx16( HHOOK hhook )
609 THUNK *thunk = (THUNK *)HOOK_GetProc16( hhook );
610 BOOL16 ret = UnhookWindowsHookEx16( hhook );
611 if (thunk) THUNK_Free( thunk );
612 return ret;
616 /***********************************************************************
617 * THUNK_CreateSystemTimer (SYSTEM.2)
619 WORD WINAPI THUNK_CreateSystemTimer( WORD rate, FARPROC16 callback )
621 THUNK *thunk = THUNK_Alloc( callback, (RELAY)CallTo16_word_ );
622 if (!thunk) return 0;
623 return CreateSystemTimer( rate, (FARPROC16)thunk );
627 /***********************************************************************
628 * THUNK_KillSystemTimer (SYSTEM.3)
630 WORD WINAPI THUNK_KillSystemTimer( WORD timer )
632 extern WORD SYSTEM_KillSystemTimer( WORD timer ); /* misc/system.c */
633 extern FARPROC16 SYSTEM_GetTimerProc( WORD timer ); /* misc/system.c */
635 THUNK *thunk = (THUNK *)SYSTEM_GetTimerProc( timer );
636 WORD ret = SYSTEM_KillSystemTimer( timer );
637 if (thunk) THUNK_Free( thunk );
638 return ret;
642 /***********************************************************************
643 * THUNK_SetUnhandledExceptionFilter (KERNEL32.516)
645 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI THUNK_SetUnhandledExceptionFilter(
646 LPTOP_LEVEL_EXCEPTION_FILTER filter )
648 LPTOP_LEVEL_EXCEPTION_FILTER old;
649 THUNK *thunk = THUNK_Alloc( (FARPROC16)filter, (RELAY)CallTo32_1 );
650 if (!thunk) return NULL;
651 old = SetUnhandledExceptionFilter( (LPTOP_LEVEL_EXCEPTION_FILTER)thunk );
652 if (!old) return NULL;
653 thunk = (THUNK *)old;
654 old = (LPTOP_LEVEL_EXCEPTION_FILTER)thunk->proc;
655 THUNK_Free( thunk );
656 return old;
660 static FARPROC16 defDCHookProc = NULL;
662 /***********************************************************************
663 * THUNK_SetDCHook (GDI.190)
665 BOOL16 WINAPI THUNK_SetDCHook( HDC16 hdc, FARPROC16 proc, DWORD dwHookData )
667 THUNK *thunk, *oldThunk;
669 if (!defDCHookProc) /* Get DCHook Win16 entry point */
670 defDCHookProc = MODULE_GetEntryPoint( GetModuleHandle16("USER"), 362 );
672 if (proc != defDCHookProc)
674 thunk = THUNK_Alloc( proc, (RELAY)CallTo16_word_wwll );
675 if (!thunk) return FALSE;
677 else thunk = (THUNK *)DCHook;
679 /* Free the previous thunk */
680 GetDCHook( hdc, (FARPROC16 *)&oldThunk );
681 if (oldThunk && (oldThunk != (THUNK *)DCHook)) THUNK_Free( oldThunk );
683 return SetDCHook( hdc, (FARPROC16)thunk, dwHookData );
687 /***********************************************************************
688 * THUNK_GetDCHook (GDI.191)
690 DWORD WINAPI THUNK_GetDCHook( HDC16 hdc, FARPROC16 *phookProc )
692 THUNK *thunk = NULL;
693 DWORD ret = GetDCHook( hdc, (FARPROC16 *)&thunk );
694 if (thunk)
696 if (thunk == (THUNK *)DCHook)
698 if (!defDCHookProc) /* Get DCHook Win16 entry point */
699 defDCHookProc = MODULE_GetEntryPoint(GetModuleHandle16("USER"),
700 362 );
701 *phookProc = defDCHookProc;
703 else *phookProc = thunk->proc;
705 return ret;
708 /***********************************************************************
710 * Win95 internal thunks *
712 ***********************************************************************/
714 /***********************************************************************
715 * Generates a FT_Prolog call.
717 * 0FB6D1 movzbl edx,cl
718 * 8B1495xxxxxxxx mov edx,[4*edx + xxxxxxxx]
719 * 68xxxxxxxx push FT_Prolog
720 * C3 lret
722 static void _write_ftprolog(LPBYTE start,DWORD thunkstart) {
723 LPBYTE x;
725 x = start;
726 *x++ = 0x0f;*x++=0xb6;*x++=0xd1; /* movzbl edx,cl */
727 *x++ = 0x8B;*x++=0x14;*x++=0x95;*(DWORD*)x= thunkstart;
728 x+=4; /* mov edx, [4*edx + thunkstart] */
729 *x++ = 0x68; *(DWORD*)x = (DWORD)GetProcAddress32(WIN32_GetModuleHandleA("KERNEL32"),"FT_Prolog");
730 x+=4; /* push FT_Prolog */
731 *x++ = 0xC3; /* lret */
732 /* fill rest with 0xCC / int 3 */
735 /***********************************************************************
736 * Generates a QT_Thunk style call.
738 * 33C9 xor ecx, ecx
739 * 8A4DFC mov cl , [ebp-04]
740 * 8B148Dxxxxxxxx mov edx, [4*ecx + (EAX+EDX)]
741 * B8yyyyyyyy mov eax, QT_Thunk
742 * FFE0 jmp eax
744 static void _write_qtthunk(LPBYTE start,DWORD thunkstart) {
745 LPBYTE x;
747 x = start;
748 *x++ = 0x33;*x++=0xC9; /* xor ecx,ecx */
749 *x++ = 0x8A;*x++=0x4D;*x++=0xFC; /* movb cl,[ebp-04] */
750 *x++ = 0x8B;*x++=0x14;*x++=0x8D;*(DWORD*)x= thunkstart;
751 x+=4; /* mov edx, [4*ecx + (EAX+EDX) */
752 *x++ = 0xB8; *(DWORD*)x = (DWORD)GetProcAddress32(WIN32_GetModuleHandleA("KERNEL32"),"QT_Thunk");
753 x+=4; /* mov eax , QT_Thunk */
754 *x++ = 0xFF; *x++ = 0xE0; /* jmp eax */
755 /* should fill the rest of the 32 bytes with 0xCC */
758 /***********************************************************************
759 * ThunkConnect32 (KERNEL32)
760 * Connects a 32bit and a 16bit thunkbuffer.
762 struct thunkstruct
764 char magic[4];
765 DWORD length;
766 DWORD ptr;
767 DWORD x0C;
769 DWORD x10;
770 DWORD x14;
771 DWORD x18;
772 DWORD x1C;
773 DWORD x20;
776 UINT32 WINAPI ThunkConnect32( struct thunkstruct *ths, LPSTR thunkfun16,
777 LPSTR module16, LPSTR module32, HMODULE32 hmod32,
778 DWORD dllinitarg1 )
780 HINSTANCE16 hmm;
781 SEGPTR thkbuf;
782 struct thunkstruct *ths16;
784 fprintf(stdnimp,"ThunkConnect32(<struct>,%s,%s,%s,%x,%lx)\n",
785 thunkfun16,module32,module16,hmod32,dllinitarg1
787 fprintf(stdnimp," magic = %c%c%c%c\n",
788 ths->magic[0],
789 ths->magic[1],
790 ths->magic[2],
791 ths->magic[3]
793 fprintf(stdnimp," length = %lx\n",ths->length);
794 if (lstrncmp32A(ths->magic,"SL01",4)&&lstrncmp32A(ths->magic,"LS01",4))
795 return 0;
796 hmm=LoadModule16(module16,NULL);
797 if (hmm<=32)
798 return 0;
799 thkbuf=(SEGPTR)WIN32_GetProcAddress16(hmm,thunkfun16);
800 if (!thkbuf)
801 return 0;
802 ths16=(struct thunkstruct*)PTR_SEG_TO_LIN(thkbuf);
803 if (lstrncmp32A(ths16->magic,ths->magic,4))
804 return 0;
806 if (!lstrncmp32A(ths->magic,"SL01",4)) {
807 if (ths16->length != ths->length)
808 return 0;
809 ths->x0C = (DWORD)ths16;
811 fprintf(stderr," ths16 magic is 0x%08lx\n",*(DWORD*)ths16->magic);
812 if (*((DWORD*)ths16->magic) != 0x0000304C)
813 return 0;
814 if (!*(WORD*)(((LPBYTE)ths16)+0x12))
815 return 0;
818 if (!lstrncmp32A(ths->magic,"LS01",4)) {
819 if (ths16->length != ths->length)
820 return 0;
821 ths->ptr = (DWORD)PTR_SEG_TO_LIN(ths16->ptr);
822 /* code offset for QT_Thunk is at 0x1C... */
823 _write_qtthunk (((LPBYTE)ths) + ths->x1C,ths->ptr);
824 /* code offset for FT_Prolog is at 0x20... */
825 _write_ftprolog(((LPBYTE)ths) + ths->x20,ths->ptr);
826 return 1;
828 return TRUE;
832 /**********************************************************************
833 * The infamous and undocumented QT_Thunk procedure.
835 * We get arguments in [EBP+8] up to [EBP+38].
836 * We have to set up a frame in the 16 bit stackframe.
837 * saved_ss_sp: bp+0x40
838 * bp+0x3c
839 * ...
840 * bp: bp+0x00
841 * sp:
844 extern DWORD IF1632_Saved16_ss_sp;
845 VOID WINAPI QT_Thunk(CONTEXT *context)
847 CONTEXT context16;
848 LPBYTE curstack;
849 DWORD ret;
851 fprintf(stderr,"QT_Thunk(%08lx) ..",EDX_reg(context));
852 fprintf(stderr," argsize probably ebp-esp=%ld\n",
853 EBP_reg(context)-ESP_reg(context)
855 memcpy(&context16,context,sizeof(context16));
857 curstack = PTR_SEG_TO_LIN(IF1632_Saved16_ss_sp);
858 memcpy(curstack-0x40,(LPBYTE)EBP_reg(context),0x40);
859 EBP_reg(&context16) = LOWORD(IF1632_Saved16_ss_sp)-0x40;
860 IF1632_Saved16_ss_sp -= 0x3c;
862 CS_reg(&context16) = HIWORD(EDX_reg(context));
863 IP_reg(&context16) = LOWORD(EDX_reg(context));
864 #ifndef WINELIB
865 ret = CallTo16_regs_(&context16);
866 #endif
867 fprintf(stderr,". returned %08lx\n",ret);
868 EAX_reg(context) = ret;
869 IF1632_Saved16_ss_sp += 0x3c;
873 /**********************************************************************
874 * WOWCallback16 (KERNEL32.62)
876 DWORD WINAPI WOWCallback16(FARPROC16 fproc,DWORD arg)
878 DWORD ret;
879 fprintf(stderr,"WOWCallback16(%p,0x%08lx) ",fproc,arg);
880 ret = CallTo16_long_l(fproc,arg);
881 fprintf(stderr,"... returns %ld\n",ret);
882 return ret;
885 /***********************************************************************
886 * _KERNEL32_52 (KERNEL32.52)
887 * FIXME: what does it really do?
889 VOID WINAPI _KERNEL32_52(DWORD arg1,CONTEXT *regs)
891 fprintf(stderr,"_KERNE32_52(arg1=%08lx,%08lx)\n",arg1,EDI_reg(regs));
893 EAX_reg(regs) = (DWORD)WIN32_GetProcAddress16(EDI_reg(regs),"ThkBuf");
895 fprintf(stderr," GetProcAddress16(\"ThkBuf\") returns %08lx\n",
896 EAX_reg(regs)
900 /***********************************************************************
901 * _KERNEL32_43 (KERNEL32.42)
902 * A thunkbuffer link routine
903 * The thunkbuf looks like:
905 * 00: DWORD length ? don't know exactly
906 * 04: SEGPTR ptr ? where does it point to?
907 * The pointer ptr is written into the first DWORD of 'thunk'.
908 * (probably correct implemented)
910 BOOL32 WINAPI _KERNEL32_43(LPDWORD thunk,LPCSTR thkbuf,DWORD len,
911 LPCSTR dll16,LPCSTR dll32)
913 HINSTANCE16 hmod;
914 LPDWORD addr;
915 SEGPTR segaddr;
917 fprintf(stderr,"_KERNEL32_43(%p,%s,0x%08lx,%s,%s)\n",thunk,thkbuf,len,dll16,dll32);
919 hmod = LoadLibrary16(dll16);
920 if (hmod<32) {
921 fprintf(stderr,"->failed to load 16bit DLL %s, error %d\n",dll16,hmod);
922 return NULL;
924 segaddr = (DWORD)WIN32_GetProcAddress16(hmod,(LPSTR)thkbuf);
925 if (!segaddr) {
926 fprintf(stderr,"->no %s exported from %s!\n",thkbuf,dll16);
927 return NULL;
929 addr = (LPDWORD)PTR_SEG_TO_LIN(segaddr);
930 if (addr[0] != len) {
931 fprintf(stderr,"->thkbuf length mismatch? %ld vs %ld\n",len,addr[0]);
932 return NULL;
934 if (!addr[1])
935 return 0;
936 fprintf(stderr," addr[1] is %08lx\n",addr[1]);
937 *(DWORD*)thunk = addr[1];
938 return addr[1];
941 /***********************************************************************
942 * _KERNEL32_45 (KERNEL32.44)
943 * Looks like another 32->16 thunk. Dunno why they need two of them.
944 * calls the win16 address in EAX with the current stack.
946 * FIXME: doesn't seem to work correctly yet...
948 VOID WINAPI _KERNEL32_45(CONTEXT *context)
950 CONTEXT context16;
951 LPBYTE curstack;
952 DWORD ret,stacksize;
954 fprintf(stderr,"KERNEL32_45(%%eax=0x%08lx(%%cx=0x%04lx,%%edx=0x%08lx))\n",
955 (DWORD)EAX_reg(context),(DWORD)CX_reg(context),(DWORD)EDX_reg(context)
957 stacksize = EBP_reg(context)-ESP_reg(context);
958 fprintf(stderr," stacksize = %ld\n",stacksize);
960 memcpy(&context16,context,sizeof(context16));
962 curstack = PTR_SEG_TO_LIN(IF1632_Saved16_ss_sp);
963 memcpy(curstack-stacksize,(LPBYTE)EBP_reg(context),stacksize);
964 fprintf(stderr,"IF1632_Saved16_ss_sp is 0x%08lx\n",IF1632_Saved16_ss_sp);
965 EBP_reg(&context16) = LOWORD(IF1632_Saved16_ss_sp)-stacksize;
966 IF1632_Saved16_ss_sp -= stacksize;
968 DI_reg(&context16) = CX_reg(context);
969 CS_reg(&context16) = HIWORD(EAX_reg(context));
970 IP_reg(&context16) = LOWORD(EAX_reg(context));
971 /* some more registers spronged locally, but I don't think they are
972 * needed
974 #ifndef WINELIB
975 ret = CallTo16_regs_(&context16);
976 #endif
977 fprintf(stderr,". returned %08lx\n",ret);
978 EAX_reg(context) = ret;
979 IF1632_Saved16_ss_sp += stacksize;
983 /***********************************************************************
984 * (KERNEL32.40)
985 * A thunk setup routine.
986 * Expects a pointer to a preinitialized thunkbuffer in the first argument
987 * looking like:
988 * 00..03: unknown (pointer, check _41, _43, _46)
989 * 04: EB1E jmp +0x20
991 * 06..23: unknown (space for replacement code, check .90)
993 * 24:>E800000000 call offset 29
994 * 29:>58 pop eax ( target of call )
995 * 2A: 2D25000000 sub eax,0x00000025 ( now points to offset 4 )
996 * 2F: BAxxxxxxxx mov edx,xxxxxxxx
997 * 34: 68yyyyyyyy push KERNEL32.90
998 * 39: C3 ret
1000 * 3A: EB1E jmp +0x20
1001 * 3E ... 59: unknown (space for replacement code?)
1002 * 5A: E8xxxxxxxx call <32bitoffset xxxxxxxx>
1003 * 5F: 5A pop edx
1004 * 60: 81EA25xxxxxx sub edx, 0x25xxxxxx
1005 * 66: 52 push edx
1006 * 67: 68xxxxxxxx push xxxxxxxx
1007 * 6C: 68yyyyyyyy push KERNEL32.89
1008 * 71: C3 ret
1009 * 72: end?
1010 * This function checks if the code is there, and replaces the yyyyyyyy entries
1011 * by the functionpointers.
1012 * The thunkbuf looks like:
1014 * 00: DWORD length ? don't know exactly
1015 * 04: SEGPTR ptr ? where does it point to?
1016 * The segpointer ptr is written into the first DWORD of 'thunk'.
1017 * (probably correct implemented)
1020 LPVOID WINAPI _KERNEL32_41(LPBYTE thunk,LPCSTR thkbuf,DWORD len,LPCSTR dll16,
1021 LPCSTR dll32)
1023 HMODULE32 hkrnl32 = WIN32_GetModuleHandleA("KERNEL32");
1024 HMODULE16 hmod;
1025 LPDWORD addr,addr2;
1026 DWORD segaddr;
1028 fprintf(stderr,"KERNEL32_41(%p,%s,%ld,%s,%s)\n",
1029 thunk,thkbuf,len,dll16,dll32
1032 /* FIXME: add checks for valid code ... */
1033 /* write pointers to kernel32.89 and kernel32.90 (+ordinal base of 1) */
1034 *(DWORD*)(thunk+0x35) = (DWORD)GetProcAddress32(hkrnl32,(LPSTR)90);
1035 *(DWORD*)(thunk+0x6D) = (DWORD)GetProcAddress32(hkrnl32,(LPSTR)89);
1038 hmod = LoadLibrary16(dll16);
1039 if (hmod<32) {
1040 fprintf(stderr,"->failed to load 16bit DLL %s, error %d\n",dll16,hmod);
1041 return NULL;
1043 segaddr = (DWORD)WIN32_GetProcAddress16(hmod,(LPSTR)thkbuf);
1044 if (!segaddr) {
1045 fprintf(stderr,"->no %s exported from %s!\n",thkbuf,dll16);
1046 return NULL;
1048 addr = (LPDWORD)PTR_SEG_TO_LIN(segaddr);
1049 if (addr[0] != len) {
1050 fprintf(stderr,"->thkbuf length mismatch? %ld vs %ld\n",len,addr[0]);
1051 return NULL;
1053 addr2 = PTR_SEG_TO_LIN(addr[1]);
1054 fprintf(stderr," addr2 is %08lx:%p\n",addr[1],addr2);
1055 if (HIWORD(addr2))
1056 *(DWORD*)thunk = (DWORD)addr2;
1057 return addr2;
1060 /***********************************************************************
1061 * (KERNEL32.91)
1062 * Thunk priming? function
1063 * Rewrites the first part of the thunk to use the QT_Thunk interface
1064 * and jumps to the start of that code.
1066 VOID WINAPI _KERNEL32_90(CONTEXT *context)
1068 fprintf(stderr,"_KERNEL32_90(eax=0x%08lx,edx=0x%08lx,ebp[-4]=0x%02x,target = %08lx, *target =%08lx)\n",
1069 EAX_reg(context),EDX_reg(context),((BYTE*)EBP_reg(context))[-4],
1070 (*(DWORD*)(EAX_reg(context)+EDX_reg(context)))+4*(((BYTE*)EBP_reg(context))[-4]),
1071 *(DWORD*)((*(DWORD*)(EAX_reg(context)+EDX_reg(context)))+4*(((BYTE*)EBP_reg(context))[-4]))
1073 _write_qtthunk((LPBYTE)EAX_reg(context),*(DWORD*)(EAX_reg(context)+EDX_reg(context)));
1074 /* we just call the real QT_Thunk right now
1075 * we can bypass the relaycode, for we already have the registercontext
1077 EDX_reg(context) = *(DWORD*)((*(DWORD*)(EAX_reg(context)+EDX_reg(context)))+4*(((BYTE*)EBP_reg(context))[-4]));
1078 return QT_Thunk(context);
1081 /***********************************************************************
1082 * (KERNEL32.45)
1083 * Another thunkbuf link routine.
1084 * The start of the thunkbuf looks like this:
1085 * 00: DWORD length
1086 * 04: SEGPTR address for thunkbuffer pointer
1088 VOID WINAPI _KERNEL32_46(LPBYTE thunk,LPSTR thkbuf,DWORD len,LPSTR dll16,
1089 LPSTR dll32)
1091 LPDWORD addr;
1092 HMODULE16 hmod;
1093 SEGPTR segaddr;
1095 fprintf(stderr,"KERNEL32_46(%p,%s,%lx,%s,%s)\n",
1096 thunk,thkbuf,len,dll16,dll32
1098 hmod = LoadLibrary16(dll16);
1099 if (hmod < 32) {
1100 fprintf(stderr,"->couldn't load %s, error %d\n",dll16,hmod);
1101 return;
1103 segaddr = (SEGPTR)WIN32_GetProcAddress16(hmod,thkbuf);
1104 if (!segaddr) {
1105 fprintf(stderr,"-> haven't found %s in %s!\n",thkbuf,dll16);
1106 return;
1108 addr = (LPDWORD)PTR_SEG_TO_LIN(segaddr);
1109 if (addr[0] != len) {
1110 fprintf(stderr,"-> length of thkbuf differs from expected length! (%ld vs %ld)\n",addr[0],len);
1111 return;
1113 *(DWORD*)PTR_SEG_TO_LIN(addr[1]) = (DWORD)thunk;
1116 /**********************************************************************
1117 * _KERNEL32_87
1118 * Check if thunking is initialized (ss selector set up etc.)
1120 BOOL32 WINAPI _KERNEL32_87()
1122 fprintf(stderr,"KERNEL32_87 stub, returning TRUE\n");
1123 return TRUE;
1126 /**********************************************************************
1127 * _KERNEL32_88
1128 * One of the real thunking functions. This one seems to be for 32<->32
1129 * thunks. It should probably be capable of crossing processboundaries.
1131 * And YES, I've seen nr=48 (somewhere in the Win95 32<->16 OLE coupling)
1133 DWORD WINAPI _KERNEL32_88(DWORD *args)
1135 DWORD nr = args[0];
1136 DWORD flags = args[1];
1137 FARPROC32 fun = (FARPROC32)args[2];
1138 DWORD i,ret;
1140 fprintf(stderr,"KERNEL32_88(%ld,0x%08lx,%p,[ ",nr,flags,fun);
1141 for (i=0;i<nr/4;i++)
1142 fprintf(stderr,"0x%08lx,",args[3+i]);
1143 fprintf(stderr,"])");
1144 #ifndef WINELIB
1145 switch (nr) {
1146 case 0: ret = CallTo32_0(fun);
1147 break;
1148 case 4: ret = CallTo32_1(fun,args[3]);
1149 break;
1150 case 8: ret = CallTo32_2(fun,args[3],args[4]);
1151 break;
1152 case 12: ret = CallTo32_3(fun,args[3],args[4],args[5]);
1153 break;
1154 case 16: ret = CallTo32_4(fun,args[3],args[4],args[5],args[6]);
1155 break;
1156 case 20: ret = CallTo32_5(fun,args[3],args[4],args[5],args[6],args[7]);
1157 break;
1158 case 24: ret = CallTo32_6(fun,args[3],args[4],args[5],args[6],args[7],args[8]);
1159 break;
1160 case 28: ret = CallTo32_7(fun,args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
1161 break;
1162 case 32: ret = CallTo32_8(fun,args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
1163 break;
1164 case 36: ret = CallTo32_9(fun,args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11]);
1165 break;
1166 case 40: ret = CallTo32_10(fun,args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12]);
1167 break;
1168 case 44: ret = CallTo32_11(fun,args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13]);
1169 break;
1170 case 48: ret = CallTo32_12(fun,args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14]);
1171 break;
1172 default:
1173 fprintf(stderr," unsupported nr of arguments, %ld\n",nr);
1174 ret = 0;
1175 break;
1178 #endif
1179 fprintf(stderr," returning %ld ...\n",ret);
1180 return ret;
1183 /**********************************************************************
1184 * KERNEL_619 (KERNEL)
1185 * Seems to store y and z depending on x in some internal lists...
1187 WORD WINAPI _KERNEL_619(WORD x,DWORD y,DWORD z)
1189 fprintf(stderr,"KERNEL_619(0x%04x,0x%08lx,0x%08lx)\n",x,y,z);
1190 return x;