kernel32: Add more obscure PE images that XP is able to load.
[wine] / dlls / kernel32 / 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 hModule = GetModuleHandle16( "KERNEL" );
171         UTGlue16_Segptr = GetProcAddress16( hModule, "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
245     /* Load 16-bit DLL and get UTProc16 entry point */
246
247     if (   (hModule16 = LoadLibrary16( lpsz16BITDLL )) <= 32
248         || (target16  = GetProcAddress16( hModule16, lpszProcName )) == 0 )
249         return FALSE;
250
251     /* Allocate UTINFO struct */
252
253     RtlAcquirePebLock();
254     if ( (ut = UTFind( hModule )) != NULL )
255         ut = NULL;
256     else
257         ut = UTAlloc( hModule, hModule16, target16, pfnUT32CallBack );
258     RtlReleasePebLock();
259
260     if ( !ut )
261     {
262         FreeLibrary16( hModule16 );
263         return FALSE;
264     }
265
266     /* Call UTInit16 if present */
267
268     if (     lpszInitName
269          && (init16 = GetProcAddress16( hModule16, lpszInitName )) != 0 )
270     {
271         SEGPTR callback = MapLS( &ut->ut16 );
272         SEGPTR segBuff  = MapLS( lpBuff );
273         WORD args[4];
274         DWORD ret;
275
276         args[3] = SELECTOROF(callback);
277         args[2] = OFFSETOF(callback);
278         args[1] = SELECTOROF(segBuff);
279         args[0] = OFFSETOF(segBuff);
280         WOWCallback16Ex( (DWORD)init16, WCB16_PASCAL, sizeof(args), args, &ret );
281         UnMapLS( segBuff );
282         UnMapLS( callback );
283         if (!ret)
284         {
285             UTUnRegister( hModule );
286             return FALSE;
287         }
288     }
289
290     /* Return 32-bit thunk */
291
292     *ppfn32Thunk = (FARPROC) &ut->ut32;
293
294     return TRUE;
295 }
296
297 /****************************************************************************
298  *              UTUnRegister (KERNEL32.@)
299  */
300 VOID WINAPI UTUnRegister( HMODULE hModule )
301 {
302     UTINFO *ut;
303     HMODULE16 hModule16 = 0;
304
305     RtlAcquirePebLock();
306     ut = UTFind( hModule );
307     if ( !ut )
308     {
309         hModule16 = ut->hModule16;
310         UTFree( ut );
311     }
312     RtlReleasePebLock();
313
314     if ( hModule16 )
315         FreeLibrary16( hModule16 );
316 }
317
318 /****************************************************************************
319  *              UTInit     (KERNEL.493)
320  */
321 WORD WINAPI UTInit16( DWORD x1, DWORD x2, DWORD x3, DWORD x4 )
322 {
323     FIXME("(%08x, %08x, %08x, %08x): stub\n", x1, x2, x3, x4 );
324     return 0;
325 }