blob: 3a1dbcd885de7de0118a3db7dd3f51ad1c4ad38e [file] [log] [blame]
Alexandre Julliardf1aa3031996-08-05 17:42:43 +00001/*
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00002 * Emulator thunks
Alexandre Julliardf1aa3031996-08-05 17:42:43 +00003 *
Alexandre Julliard491502b1997-11-01 19:08:16 +00004 * Copyright 1996, 1997 Alexandre Julliard
Alexandre Julliarda845b881998-06-01 10:44:35 +00005 * Copyright 1998 Ulrich Weigand
Alexandre Julliardf1aa3031996-08-05 17:42:43 +00006 */
7
Marcus Meissner317af321999-02-17 13:51:06 +00008#include <string.h>
9#include "wine/winbase16.h"
Alexandre Julliardf1aa3031996-08-05 17:42:43 +000010#include "callback.h"
Ulrich Weigandb4860a81999-07-24 10:15:55 +000011#include "builtin16.h"
Alexandre Julliardbf9130a1996-10-13 17:45:47 +000012#include "heap.h"
Alexandre Julliardd5041fc2000-07-25 16:42:25 +000013#include "module.h"
Ulrich Weigande6cc6fd1999-05-08 09:56:00 +000014#include "neexe.h"
Alexandre Julliard84c70f51997-05-09 08:40:27 +000015#include "stackframe.h"
Alexandre Julliard916f9752000-02-26 16:51:13 +000016#include "selectors.h"
Alexandre Julliard06c275a1999-05-02 14:32:27 +000017#include "debugtools.h"
Alexandre Julliardf1aa3031996-08-05 17:42:43 +000018
Alexandre Julliardd5041fc2000-07-25 16:42:25 +000019DEFAULT_DEBUG_CHANNEL(thunk);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000020
Alexandre Julliard491502b1997-11-01 19:08:16 +000021
22/* List of the 16-bit callback functions. This list is used */
23/* by the build program to generate the file if1632/callto16.S */
24
25/* ### start build ### */
Ulrich Weigand22d2c521999-07-23 19:27:36 +000026extern WORD CALLBACK THUNK_CallTo16_word_ (FARPROC16);
Ulrich Weigand22d2c521999-07-23 19:27:36 +000027extern WORD CALLBACK THUNK_CallTo16_word_l (FARPROC16,LONG);
28extern LONG CALLBACK THUNK_CallTo16_long_l (FARPROC16,LONG);
Ulrich Weigand979000e1999-12-05 02:48:53 +000029extern WORD CALLBACK THUNK_CallTo16_word_lllw (FARPROC16,LONG,LONG,LONG,WORD);
Ulrich Weigand22d2c521999-07-23 19:27:36 +000030extern WORD CALLBACK THUNK_CallTo16_word_lwww (FARPROC16,LONG,WORD,WORD,WORD);
Ulrich Weigand22d2c521999-07-23 19:27:36 +000031extern LONG CALLBACK THUNK_CallTo16_long_wwwl (FARPROC16,WORD,WORD,WORD,LONG);
Ulrich Weigand22d2c521999-07-23 19:27:36 +000032extern WORD CALLBACK THUNK_CallTo16_word_lwwww(FARPROC16,LONG,WORD,WORD,WORD,WORD);
Alexandre Julliard198746d2000-08-14 14:29:22 +000033extern WORD CALLBACK THUNK_CallTo16_word_w (FARPROC16,WORD);
34extern WORD CALLBACK THUNK_CallTo16_word_wlww (FARPROC16,WORD,LONG,WORD,WORD);
35extern WORD CALLBACK THUNK_CallTo16_word_ww (FARPROC16,WORD,WORD);
36extern WORD CALLBACK THUNK_CallTo16_word_wwwl (FARPROC16,WORD,WORD,WORD,LONG);
Alexandre Julliard491502b1997-11-01 19:08:16 +000037/* ### stop build ### */
38
Alexandre Julliardbf9130a1996-10-13 17:45:47 +000039static THUNK *firstThunk = NULL;
40
Patrik Stridvalla9f6a9d2000-10-24 02:22:16 +000041CALLOUT_TABLE Callout = {
42 /* PeekMessageA */ NULL,
43 /* GetMessageA */ NULL,
44 /* SendMessageA */ NULL,
45 /* PostMessageA */ NULL,
Patrik Stridvalla9f6a9d2000-10-24 02:22:16 +000046 /* TranslateMessage */ NULL,
47 /* DispatchMessageA */ NULL,
48 /* RedrawWindow */ NULL,
49 /* UserSignalProc */ NULL,
50 /* FinalUserInit16 */ NULL,
51 /* InitThreadInput16 */ NULL,
52 /* UserYield16) */ NULL,
53 /* DestroyIcon32 */ NULL,
54 /* WaitForInputIdle */ NULL,
55 /* MsgWaitForMultipleObjects */ NULL,
56 /* WindowFromDC */ NULL,
57 /* MessageBoxA */ NULL,
58 /* MessageBoxW */ NULL
59};
Alexandre Julliard84c70f51997-05-09 08:40:27 +000060
61/***********************************************************************
Alexandre Julliardf1aa3031996-08-05 17:42:43 +000062 * THUNK_Alloc
63 */
Huw D M Davies304d9a41999-09-13 15:15:45 +000064FARPROC THUNK_Alloc( FARPROC16 func, RELAY relay )
Alexandre Julliardf1aa3031996-08-05 17:42:43 +000065{
Ulrich Weigand2dec1ba1999-09-20 18:43:52 +000066 HANDLE16 hSeg;
67 NE_MODULE *pModule;
68 THUNK *thunk;
69
70 /* NULL maps to NULL */
71 if ( !func ) return NULL;
72
73 /*
74 * If we got an 16-bit built-in API entry point, retrieve the Wine
75 * 32-bit handler for that API routine.
76 *
77 * NOTE: For efficiency reasons, we only check whether the selector
78 * of 'func' points to the code segment of a built-in module.
79 * It might be theoretically possible that the offset is such
80 * that 'func' does not point, in fact, to an API entry point.
81 * In this case, however, the pointer is corrupt anyway.
82 */
83 hSeg = GlobalHandle16( SELECTOROF( func ) );
84 pModule = NE_GetPtr( FarGetOwner16( hSeg ) );
85
86 if ( pModule && (pModule->flags & NE_FFLAGS_BUILTIN)
87 && NE_SEG_TABLE(pModule)[0].hSeg == hSeg )
88 {
89 FARPROC proc = (FARPROC)((ENTRYPOINT16 *)PTR_SEG_TO_LIN( func ))->target;
90
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +000091 TRACE( "(%04x:%04x, %p) -> built-in API %p\n",
92 SELECTOROF( func ), OFFSETOF( func ), relay, proc );
Ulrich Weigand2dec1ba1999-09-20 18:43:52 +000093 return proc;
94 }
95
96 /* Otherwise, we need to alloc a thunk */
Alexandre Julliard90476d62000-02-16 22:47:24 +000097 thunk = HeapAlloc( GetProcessHeap(), 0, sizeof(*thunk) );
Alexandre Julliardf1aa3031996-08-05 17:42:43 +000098 if (thunk)
99 {
100 thunk->popl_eax = 0x58;
101 thunk->pushl_func = 0x68;
102 thunk->proc = func;
103 thunk->pushl_eax = 0x50;
104 thunk->jmp = 0xe9;
Alexandre Julliardbf9130a1996-10-13 17:45:47 +0000105 thunk->relay = (RELAY)((char *)relay - (char *)(&thunk->next));
Huw D M Davies304d9a41999-09-13 15:15:45 +0000106 thunk->magic = CALLTO16_THUNK_MAGIC;
Alexandre Julliardbf9130a1996-10-13 17:45:47 +0000107 thunk->next = firstThunk;
108 firstThunk = thunk;
Alexandre Julliardf1aa3031996-08-05 17:42:43 +0000109 }
Ulrich Weigand2dec1ba1999-09-20 18:43:52 +0000110
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000111 TRACE( "(%04x:%04x, %p) -> allocated thunk %p\n",
112 SELECTOROF( func ), OFFSETOF( func ), relay, thunk );
Huw D M Davies304d9a41999-09-13 15:15:45 +0000113 return (FARPROC)thunk;
Alexandre Julliardf1aa3031996-08-05 17:42:43 +0000114}
115
Alexandre Julliardbf9130a1996-10-13 17:45:47 +0000116/***********************************************************************
Alexandre Julliardf1aa3031996-08-05 17:42:43 +0000117 * THUNK_Free
118 */
Huw D M Davies304d9a41999-09-13 15:15:45 +0000119void THUNK_Free( FARPROC thunk )
Alexandre Julliardf1aa3031996-08-05 17:42:43 +0000120{
Huw D M Davies304d9a41999-09-13 15:15:45 +0000121 THUNK *t = (THUNK*)thunk;
Ulrich Weigand2dec1ba1999-09-20 18:43:52 +0000122 if ( !t || IsBadReadPtr( t, sizeof(*t) )
123 || t->magic != CALLTO16_THUNK_MAGIC )
Huw D M Davies304d9a41999-09-13 15:15:45 +0000124 return;
125
Alexandre Julliard90476d62000-02-16 22:47:24 +0000126 if (HEAP_IsInsideHeap( GetProcessHeap(), 0, t ))
Alexandre Julliardbf9130a1996-10-13 17:45:47 +0000127 {
128 THUNK **prev = &firstThunk;
Huw D M Davies304d9a41999-09-13 15:15:45 +0000129 while (*prev && (*prev != t)) prev = &(*prev)->next;
Alexandre Julliardbf9130a1996-10-13 17:45:47 +0000130 if (*prev)
131 {
Huw D M Davies304d9a41999-09-13 15:15:45 +0000132 *prev = t->next;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000133 HeapFree( GetProcessHeap(), 0, t );
Alexandre Julliardbf9130a1996-10-13 17:45:47 +0000134 return;
135 }
136 }
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000137 ERR("invalid thunk addr %p\n", thunk );
Huw D M Davies304d9a41999-09-13 15:15:45 +0000138 return;
Alexandre Julliardf1aa3031996-08-05 17:42:43 +0000139}
140
141
142/***********************************************************************
Ulrich Weigandb4860a81999-07-24 10:15:55 +0000143 * THUNK_GetCalloutThunk
144 *
145 * Retrieve API entry point with given name from given module.
146 * If module is builtin, return the 32-bit entry point, otherwise
147 * create a 32->16 thunk to the 16-bit entry point, using the
148 * given relay code.
149 *
150 */
151static FARPROC THUNK_GetCalloutThunk( NE_MODULE *pModule, LPSTR name, RELAY relay )
152{
153 FARPROC16 proc = WIN32_GetProcAddress16( pModule->self, name );
154 if ( !proc ) return 0;
155
156 if ( pModule->flags & NE_FFLAGS_BUILTIN )
157 return (FARPROC)((ENTRYPOINT16 *)PTR_SEG_TO_LIN( proc ))->target;
158 else
159 return (FARPROC)THUNK_Alloc( proc, relay );
160}
161
162/***********************************************************************
Ulrich Weigand61439d21998-12-24 15:12:20 +0000163 * THUNK_InitCallout
164 */
165void THUNK_InitCallout(void)
166{
Ulrich Weigande6cc6fd1999-05-08 09:56:00 +0000167 HMODULE hModule;
Ulrich Weigande6cc6fd1999-05-08 09:56:00 +0000168 NE_MODULE *pModule;
169
Alexandre Julliard4e951ea2000-11-08 22:47:53 +0000170 hModule = GetModuleHandleA( "user32.dll" );
Ulrich Weigandb4860a81999-07-24 10:15:55 +0000171 if ( hModule )
Ulrich Weigand61439d21998-12-24 15:12:20 +0000172 {
Alexandre Julliardd6c0d862000-03-24 21:38:30 +0000173#define GETADDR( name ) \
Dimitrie O. Paun334a42f2000-10-29 18:07:04 +0000174 *(FARPROC *)&Callout.name = GetProcAddress( hModule, #name )
Ulrich Weigand61439d21998-12-24 15:12:20 +0000175
Alexandre Julliardd6c0d862000-03-24 21:38:30 +0000176 GETADDR( PeekMessageA );
Alexandre Julliardd6c0d862000-03-24 21:38:30 +0000177 GETADDR( GetMessageA );
Alexandre Julliardd6c0d862000-03-24 21:38:30 +0000178 GETADDR( SendMessageA );
Alexandre Julliardd6c0d862000-03-24 21:38:30 +0000179 GETADDR( PostMessageA );
Alexandre Julliardd6c0d862000-03-24 21:38:30 +0000180 GETADDR( TranslateMessage );
Alexandre Julliardd6c0d862000-03-24 21:38:30 +0000181 GETADDR( DispatchMessageA );
182 GETADDR( RedrawWindow );
183 GETADDR( WaitForInputIdle );
Alexandre Julliard946a4442000-07-30 13:50:27 +0000184 GETADDR( MsgWaitForMultipleObjects );
185 GETADDR( WindowFromDC );
Alexandre Julliardd6c0d862000-03-24 21:38:30 +0000186 GETADDR( MessageBoxA );
187 GETADDR( MessageBoxW );
Ulrich Weigand61439d21998-12-24 15:12:20 +0000188#undef GETADDR
189 }
Alexandre Julliard4e951ea2000-11-08 22:47:53 +0000190 else WARN("no 32-bit USER\n");
Ulrich Weigand61439d21998-12-24 15:12:20 +0000191
Alexandre Julliard4e951ea2000-11-08 22:47:53 +0000192 pModule = NE_GetPtr( GetModuleHandle16( "USER.EXE" ) );
Ulrich Weigandb4860a81999-07-24 10:15:55 +0000193 if ( pModule )
Ulrich Weigand61439d21998-12-24 15:12:20 +0000194 {
195#define GETADDR( var, name, thk ) \
Dimitrie O. Paun334a42f2000-10-29 18:07:04 +0000196 *(FARPROC *)&Callout.var = THUNK_GetCalloutThunk( pModule, name, \
197 (RELAY)THUNK_CallTo16_##thk )
Ulrich Weigand61439d21998-12-24 15:12:20 +0000198
Ulrich Weigand98c30531999-07-27 17:10:06 +0000199 GETADDR( FinalUserInit16, "FinalUserInit", word_ );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000200 GETADDR( InitThreadInput16, "InitThreadInput", word_ww );
201 GETADDR( UserYield16, "UserYield", word_ );
Ulrich Weigande5624531999-03-10 14:06:53 +0000202 GETADDR( DestroyIcon32, "DestroyIcon32", word_ww );
Ulrich Weigand979000e1999-12-05 02:48:53 +0000203 GETADDR( UserSignalProc, "SignalProc32", word_lllw );
Ulrich Weigand61439d21998-12-24 15:12:20 +0000204#undef GETADDR
205 }
Alexandre Julliard4e951ea2000-11-08 22:47:53 +0000206 else WARN("no 16-bit USER\n");
Ulrich Weigand61439d21998-12-24 15:12:20 +0000207}