msvcrt: Add -ret64 flag on some functions that return a 64-bit value.
[wine] / dlls / krnl386.exe16 / utthunk.c
1 /*
2  * Win32s Universal Thunk API
3  *
4  * Copyright 1999 Ulrich Weigand
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #include "wine/winbase16.h"
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winternl.h"
27 #include "wownt32.h"
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(thunk);
31
32 #include "pshpack1.h"
33
34 typedef struct
35 {
36     BYTE    popl_eax;
37     BYTE    pushl;
38     DWORD   target;
39     BYTE    pushl_eax;
40     BYTE    ljmp;
41     DWORD   utglue16;
42
43 } UT16THUNK;
44
45 typedef struct
46 {
47     BYTE    popl_eax;
48     BYTE    pushl;
49     DWORD   target;
50     BYTE    pushl_eax;
51     BYTE    jmp;
52     DWORD   utglue32;
53
54 } UT32THUNK;
55
56 #include "poppack.h"
57
58 typedef struct _UTINFO
59 {
60     struct _UTINFO    *next;
61     HMODULE            hModule;
62     HMODULE16          hModule16;
63
64     UT16THUNK          ut16;
65     UT32THUNK          ut32;
66
67 } UTINFO;
68
69 static UTINFO *UT_head; /* head of Universal Thunk list */
70
71 typedef DWORD (CALLBACK *UTGLUEPROC)( LPVOID lpBuff, DWORD dwUserDefined );
72
73 BOOL WINAPI UTRegister( HMODULE hModule, LPSTR lpsz16BITDLL,
74                         LPSTR lpszInitName, LPSTR lpszProcName,
75                         FARPROC *ppfn32Thunk, FARPROC pfnUT32CallBack,
76                         LPVOID lpBuff );
77
78 VOID WINAPI UTUnRegister( HMODULE hModule );
79
80
81 /****************************************************************************
82  *              UTGlue16 (KERNEL.666) (KERNEL Wine-specific export)
83  */
84 DWORD WINAPI UTGlue16( LPVOID lpBuff, DWORD dwUserDefined, SEGPTR *translationList,
85                        UTGLUEPROC target )
86 {
87     INT i;
88
89     /* Convert arguments to flat pointers */
90
91     if ( translationList )
92         for ( i = 0; translationList[i]; i++ )
93         {
94             LPVOID flatPtr = MapSL( translationList[i] );
95             *(LPVOID *)flatPtr = MapSL( *(SEGPTR *)flatPtr );
96         }
97
98     /* Call 32-bit routine */
99
100     return target( lpBuff, dwUserDefined );
101 }
102
103 /****************************************************************************
104  *              UTGlue32
105  */
106 static DWORD WINAPI UTGlue32( FARPROC16 target, LPVOID lpBuff, DWORD dwUserDefined,
107                               LPVOID translationList[] )
108 {
109     SEGPTR segBuff, *segptrList = NULL;
110     INT i, nList = 0;
111     DWORD retv;
112     WORD args[4];
113
114     /* Convert arguments to SEGPTRs */
115
116     if ( translationList )
117         for ( nList = 0; translationList[nList]; nList++ )
118             ;
119
120     if ( nList )
121     {
122         segptrList = HeapAlloc( GetProcessHeap(), 0, sizeof(SEGPTR)*nList );
123         if ( !segptrList )
124         {
125             FIXME("Unable to allocate segptrList!\n" );
126             return 0;
127         }
128
129         for ( i = 0; i < nList; i++ )
130             segptrList[i] = *(SEGPTR *)translationList[i]
131                           = MapLS( *(LPVOID *)translationList[i] );
132     }
133
134     segBuff = MapLS( lpBuff );
135
136     /* Call 16-bit routine */
137
138     args[3] = SELECTOROF(segBuff);
139     args[2] = OFFSETOF(segBuff);
140     args[1] = HIWORD(dwUserDefined);
141     args[0] = LOWORD(dwUserDefined);
142     WOWCallback16Ex( (DWORD)target, WCB16_PASCAL, sizeof(args), args, &retv );
143
144     /* Free temporary selectors */
145
146     UnMapLS( segBuff );
147
148     if ( nList )
149     {
150         for ( i = 0; i < nList; i++ )
151             UnMapLS( segptrList[i] );
152
153         HeapFree( GetProcessHeap(), 0, segptrList );
154     }
155
156     return retv;
157 }
158
159 /****************************************************************************
160  *              UTAlloc
161  */
162 static UTINFO *UTAlloc( HMODULE hModule, HMODULE16 hModule16,
163                         FARPROC16 target16, FARPROC target32 )
164 {
165     static FARPROC16 UTGlue16_Segptr = NULL;
166     UTINFO *ut;
167
168     if ( !UTGlue16_Segptr )
169     {
170         HMODULE16 hMod = GetModuleHandle16( "KERNEL" );
171         UTGlue16_Segptr = GetProcAddress16( hMod, "UTGlue16" );
172         if ( !UTGlue16_Segptr ) return NULL;
173     }
174
175     ut = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(UTINFO) );
176     if ( !ut ) return NULL;
177
178     ut->hModule   = hModule;
179     ut->hModule16 = hModule16;
180
181     ut->ut16.popl_eax  = 0x58;
182     ut->ut16.pushl     = 0x68;
183     ut->ut16.target    = (DWORD)target32;
184     ut->ut16.pushl_eax = 0x50;
185     ut->ut16.ljmp      = 0xea;
186     ut->ut16.utglue16  = (DWORD)UTGlue16_Segptr;
187
188     ut->ut32.popl_eax  = 0x58;
189     ut->ut32.pushl     = 0x68;
190     ut->ut32.target    = (DWORD)target16;
191     ut->ut32.pushl_eax = 0x50;
192     ut->ut32.jmp       = 0xe9;
193     ut->ut32.utglue32  = (DWORD)UTGlue32 - ((DWORD)&ut->ut32.utglue32 + sizeof(DWORD));
194
195     ut->next = UT_head;
196     UT_head = ut;
197
198     return ut;
199 }
200
201 /****************************************************************************
202  *              UTFree
203  */
204 static void UTFree( UTINFO *ut )
205 {
206     UTINFO **ptr;
207
208     for ( ptr = &UT_head; *ptr; ptr = &(*ptr)->next )
209         if ( *ptr == ut )
210         {
211             *ptr = ut->next;
212             break;
213         }
214
215     HeapFree( GetProcessHeap(), 0, ut );
216 }
217
218 /****************************************************************************
219  *              UTFind
220  */
221 static UTINFO *UTFind( HMODULE hModule )
222 {
223     UTINFO *ut;
224
225     for ( ut = UT_head; ut; ut =ut->next )
226         if ( ut->hModule == hModule )
227             break;
228
229     return ut;
230 }
231
232
233 /****************************************************************************
234  *              UTRegister (KERNEL32.@)
235  */
236 BOOL WINAPI UTRegister( HMODULE hModule, LPSTR lpsz16BITDLL,
237                         LPSTR lpszInitName, LPSTR lpszProcName,
238                         FARPROC *ppfn32Thunk, FARPROC pfnUT32CallBack,
239                         LPVOID lpBuff )
240 {
241     UTINFO *ut;
242     HMODULE16 hModule16;
243     FARPROC16 target16, init16;
244     static int done;
245
246     if (!done)
247     {
248         LoadLibrary16( "gdi.exe" );
249         LoadLibrary16( "user.exe" );
250         done = TRUE;
251     }
252
253     /* Load 16-bit DLL and get UTProc16 entry point */
254
255     if (   (hModule16 = LoadLibrary16( lpsz16BITDLL )) <= 32
256         || (target16  = GetProcAddress16( hModule16, lpszProcName )) == 0 )
257         return FALSE;
258
259     /* Allocate UTINFO struct */
260
261     RtlAcquirePebLock();
262     if ( (ut = UTFind( hModule )) != NULL )
263         ut = NULL;
264     else
265         ut = UTAlloc( hModule, hModule16, target16, pfnUT32CallBack );
266     RtlReleasePebLock();
267
268     if ( !ut )
269     {
270         FreeLibrary16( hModule16 );
271         return FALSE;
272     }
273
274     /* Call UTInit16 if present */
275
276     if (     lpszInitName
277          && (init16 = GetProcAddress16( hModule16, lpszInitName )) != 0 )
278     {
279         SEGPTR callback = MapLS( &ut->ut16 );
280         SEGPTR segBuff  = MapLS( lpBuff );
281         WORD args[4];
282         DWORD ret;
283
284         args[3] = SELECTOROF(callback);
285         args[2] = OFFSETOF(callback);
286         args[1] = SELECTOROF(segBuff);
287         args[0] = OFFSETOF(segBuff);
288         WOWCallback16Ex( (DWORD)init16, WCB16_PASCAL, sizeof(args), args, &ret );
289         UnMapLS( segBuff );
290         UnMapLS( callback );
291         if (!ret)
292         {
293             UTUnRegister( hModule );
294             return FALSE;
295         }
296     }
297
298     /* Return 32-bit thunk */
299
300     *ppfn32Thunk = (FARPROC) &ut->ut32;
301
302     return TRUE;
303 }
304
305 /****************************************************************************
306  *              UTUnRegister (KERNEL32.@)
307  */
308 VOID WINAPI UTUnRegister( HMODULE hModule )
309 {
310     UTINFO *ut;
311     HMODULE16 hModule16 = 0;
312
313     RtlAcquirePebLock();
314     ut = UTFind( hModule );
315     if ( ut )
316     {
317         hModule16 = ut->hModule16;
318         UTFree( ut );
319     }
320     RtlReleasePebLock();
321
322     if ( hModule16 )
323         FreeLibrary16( hModule16 );
324 }
325
326 /****************************************************************************
327  *              UTInit     (KERNEL.493)
328  */
329 WORD WINAPI UTInit16( DWORD x1, DWORD x2, DWORD x3, DWORD x4 )
330 {
331     FIXME("(%08x, %08x, %08x, %08x): stub\n", x1, x2, x3, x4 );
332     return 0;
333 }