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