Don't use old_spacing-1 if old_spacing already has the minimum value.
[wine] / dlls / kernel / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "wine/winbase16.h"
22 #include "winternl.h"
23 #include "module.h"
24 #include "wine/debug.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(thunk);
27
28 #include "pshpack1.h"
29
30 typedef struct
31 {
32     BYTE    popl_eax;
33     BYTE    pushl;
34     DWORD   target;
35     BYTE    pushl_eax;
36     BYTE    ljmp;
37     DWORD   utglue16;
38
39 } UT16THUNK;
40
41 typedef struct
42 {
43     BYTE    popl_eax;
44     BYTE    pushl;
45     DWORD   target;
46     BYTE    pushl_eax;
47     BYTE    jmp;
48     DWORD   utglue32;
49
50 } UT32THUNK;
51
52 #include "poppack.h"
53
54 typedef struct _UTINFO
55 {
56     struct _UTINFO    *next;
57     HMODULE            hModule;
58     HMODULE16          hModule16;
59
60     UT16THUNK          ut16;
61     UT32THUNK          ut32;
62
63 } UTINFO;
64
65 static UTINFO *UT_head; /* head of Universal Thunk list */
66
67 typedef DWORD (CALLBACK *UTGLUEPROC)( LPVOID lpBuff, DWORD dwUserDefined );
68
69 BOOL WINAPI UTRegister( HMODULE hModule, LPSTR lpsz16BITDLL,
70                         LPSTR lpszInitName, LPSTR lpszProcName,
71                         FARPROC *ppfn32Thunk, FARPROC pfnUT32CallBack,
72                         LPVOID lpBuff );
73
74 VOID WINAPI UTUnRegister( HMODULE hModule );
75
76 /* ### start build ### */
77 extern LONG CALLBACK UTTHUNK_CallTo16_long_ll(FARPROC16,LONG,LONG);
78 /* ### stop build ### */
79
80 /****************************************************************************
81  *              UTGlue16 (KERNEL.666) (KERNEL Wine-specific export)
82  */
83 DWORD WINAPI UTGlue16( LPVOID lpBuff, DWORD dwUserDefined, SEGPTR *translationList,
84                        UTGLUEPROC target )
85 {
86     INT i;
87
88     /* Convert arguments to flat pointers */
89
90     if ( translationList )
91         for ( i = 0; translationList[i]; i++ )
92         {
93             LPVOID flatPtr = MapSL( translationList[i] );
94             *(LPVOID *)flatPtr = MapSL( *(SEGPTR *)flatPtr );
95         }
96
97     /* Call 32-bit routine */
98
99     return target( lpBuff, dwUserDefined );
100 }
101
102 /****************************************************************************
103  *              UTGlue32
104  */
105 static DWORD WINAPI UTGlue32( FARPROC16 target, LPVOID lpBuff, DWORD dwUserDefined,
106                               LPVOID translationList[] )
107 {
108     SEGPTR segBuff, *segptrList = NULL;
109     INT i, nList = 0;
110     DWORD retv;
111
112     /* Convert arguments to SEGPTRs */
113
114     if ( translationList )
115         for ( nList = 0; translationList[nList]; nList++ )
116             ;
117
118     if ( nList )
119     {
120         segptrList = HeapAlloc( GetProcessHeap(), 0, sizeof(SEGPTR)*nList );
121         if ( !segptrList )
122         {
123             FIXME("Unable to allocate segptrList!\n" );
124             return 0;
125         }
126
127         for ( i = 0; i < nList; i++ )
128             segptrList[i] = *(SEGPTR *)translationList[i]
129                           = MapLS( *(LPVOID *)translationList[i] );
130     }
131
132     segBuff = MapLS( lpBuff );
133
134     /* Call 16-bit routine */
135
136     retv = UTTHUNK_CallTo16_long_ll( target, segBuff, dwUserDefined );
137
138     /* Free temporary selectors */
139
140     UnMapLS( segBuff );
141
142     if ( nList )
143     {
144         for ( i = 0; i < nList; i++ )
145             UnMapLS( segptrList[i] );
146
147         HeapFree( GetProcessHeap(), 0, segptrList );
148     }
149
150     return retv;
151 }
152
153 /****************************************************************************
154  *              UTAlloc
155  */
156 static UTINFO *UTAlloc( HMODULE hModule, HMODULE16 hModule16,
157                         FARPROC16 target16, FARPROC target32 )
158 {
159     static FARPROC16 UTGlue16_Segptr = NULL;
160     UTINFO *ut;
161
162     if ( !UTGlue16_Segptr )
163     {
164         HMODULE16 hModule = GetModuleHandle16( "KERNEL" );
165         UTGlue16_Segptr = GetProcAddress16( hModule, "UTGlue16" );
166         if ( !UTGlue16_Segptr ) return NULL;
167     }
168
169     ut = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(UTINFO) );
170     if ( !ut ) return NULL;
171
172     ut->hModule   = hModule;
173     ut->hModule16 = hModule16;
174
175     ut->ut16.popl_eax  = 0x58;
176     ut->ut16.pushl     = 0x68;
177     ut->ut16.target    = (DWORD)target32;
178     ut->ut16.pushl_eax = 0x50;
179     ut->ut16.ljmp      = 0xea;
180     ut->ut16.utglue16  = (DWORD)UTGlue16_Segptr;
181
182     ut->ut32.popl_eax  = 0x58;
183     ut->ut32.pushl     = 0x68;
184     ut->ut32.target    = (DWORD)target16;
185     ut->ut32.pushl_eax = 0x50;
186     ut->ut32.jmp       = 0xe9;
187     ut->ut32.utglue32  = (DWORD)UTGlue32 - ((DWORD)&ut->ut32.utglue32 + sizeof(DWORD));
188
189     ut->next = UT_head;
190     UT_head = ut;
191
192     return ut;
193 }
194
195 /****************************************************************************
196  *              UTFree
197  */
198 static void UTFree( UTINFO *ut )
199 {
200     UTINFO **ptr;
201
202     for ( ptr = &UT_head; *ptr; ptr = &(*ptr)->next )
203         if ( *ptr == ut )
204         {
205             *ptr = ut->next;
206             break;
207         }
208
209     HeapFree( GetProcessHeap(), 0, ut );
210 }
211
212 /****************************************************************************
213  *              UTFind
214  */
215 static UTINFO *UTFind( HMODULE hModule )
216 {
217     UTINFO *ut;
218
219     for ( ut = UT_head; ut; ut =ut->next )
220         if ( ut->hModule == hModule )
221             break;
222
223     return ut;
224 }
225
226
227 /****************************************************************************
228  *              UTRegister (KERNEL32.@)
229  */
230 BOOL WINAPI UTRegister( HMODULE hModule, LPSTR lpsz16BITDLL,
231                         LPSTR lpszInitName, LPSTR lpszProcName,
232                         FARPROC *ppfn32Thunk, FARPROC pfnUT32CallBack,
233                         LPVOID lpBuff )
234 {
235     UTINFO *ut;
236     HMODULE16 hModule16;
237     FARPROC16 target16, init16;
238
239     /* Load 16-bit DLL and get UTProc16 entry point */
240
241     if (   (hModule16 = LoadLibrary16( lpsz16BITDLL )) <= 32
242         || (target16  = GetProcAddress16( hModule16, lpszProcName )) == 0 )
243         return FALSE;
244
245     /* Allocate UTINFO struct */
246
247     RtlAcquirePebLock();
248     if ( (ut = UTFind( hModule )) != NULL )
249         ut = NULL;
250     else
251         ut = UTAlloc( hModule, hModule16, target16, pfnUT32CallBack );
252     RtlReleasePebLock();
253
254     if ( !ut )
255     {
256         FreeLibrary16( hModule16 );
257         return FALSE;
258     }
259
260     /* Call UTInit16 if present */
261
262     if (     lpszInitName
263          && (init16 = GetProcAddress16( hModule16, lpszInitName )) != 0 )
264     {
265         SEGPTR callback = MapLS( &ut->ut16 );
266         SEGPTR segBuff  = MapLS( lpBuff );
267
268         if ( !UTTHUNK_CallTo16_long_ll( init16, callback, segBuff ) )
269         {
270             UnMapLS( segBuff );
271             UnMapLS( callback );
272             UTUnRegister( hModule );
273             return FALSE;
274         }
275         UnMapLS( segBuff );
276         UnMapLS( callback );
277     }
278
279     /* Return 32-bit thunk */
280
281     *ppfn32Thunk = (FARPROC) &ut->ut32;
282
283     return TRUE;
284 }
285
286 /****************************************************************************
287  *              UTUnRegister (KERNEL32.@)
288  */
289 VOID WINAPI UTUnRegister( HMODULE hModule )
290 {
291     UTINFO *ut;
292     HMODULE16 hModule16 = 0;
293
294     RtlAcquirePebLock();
295     ut = UTFind( hModule );
296     if ( !ut )
297     {
298         hModule16 = ut->hModule16;
299         UTFree( ut );
300     }
301     RtlReleasePebLock();
302
303     if ( hModule16 )
304         FreeLibrary16( hModule16 );
305 }
306
307 /****************************************************************************
308  *              UTInit     (KERNEL.493)
309  */
310 WORD WINAPI UTInit16( DWORD x1, DWORD x2, DWORD x3, DWORD x4 )
311 {
312     FIXME("(%08lx, %08lx, %08lx, %08lx): stub\n", x1, x2, x3, x4 );
313     return 0;
314 }