Made Universal Thunk list per-process, not system global.
[wine] / relay32 / utthunk.c
1 /*
2  * Win32s Universal Thunk API
3  *
4  * Copyright 1999 Ulrich Weigand 
5  */
6
7 #include "windef.h"
8 #include "heap.h"
9 #include "module.h"
10 #include "selectors.h"
11 #include "callback.h"
12 #include "process.h"
13 #include "debug.h"
14 #include "debugstr.h"
15
16 #pragma pack(1)
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 #pragma pack(4)
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 BOOL WINAPI UTRegister( HMODULE hModule, LPSTR lpsz16BITDLL, 
54                         LPSTR lpszInitName, LPSTR lpszProcName,
55                         FARPROC *ppfn32Thunk, FARPROC pfnUT32CallBack, 
56                         LPVOID lpBuff );
57
58 VOID WINAPI UTUnRegister( HMODULE hModule );
59
60
61 /****************************************************************************
62  *              UTGlue16     (WPROCS.*)
63  */
64 DWORD WINAPI UTGlue16( LPVOID lpBuff, DWORD dwUserDefined, SEGPTR translationList[], 
65                        DWORD (CALLBACK *target)( LPVOID lpBuff, DWORD dwUserDefined ) )
66 {
67     INT i;
68
69     /* Convert arguments to flat pointers */
70
71     if ( translationList )
72         for ( i = 0; translationList[i]; i++ )
73         {
74             LPVOID flatPtr = PTR_SEG_TO_LIN( translationList[i] );
75             *(LPVOID *)flatPtr = PTR_SEG_TO_LIN( *(SEGPTR *)flatPtr );
76         }
77
78     /* Call 32-bit routine */
79
80     return target( lpBuff, dwUserDefined );
81 }
82
83 /****************************************************************************
84  *              UTGlue32
85  */
86 DWORD WINAPI UTGlue32( FARPROC16 target, LPVOID lpBuff, DWORD dwUserDefined, 
87                        LPVOID translationList[] )
88 {
89     SEGPTR segBuff, *segptrList = NULL;
90     INT i, nList = 0;
91     DWORD retv;
92
93     /* Convert arguments to SEGPTRs */
94
95     if ( translationList )
96         for ( nList = 0; translationList[nList]; nList++ )
97             ;
98
99     if ( nList )
100     {
101         segptrList = HeapAlloc( GetProcessHeap(), 0, sizeof(SEGPTR)*nList );
102         if ( !segptrList )
103         {
104             FIXME( thunk, "Unable to allocate segptrList!" );
105             return 0;
106         }
107
108         for ( i = 0; i < nList; i++ )
109             segptrList[i] = *(SEGPTR *)translationList[i] 
110                           = MapLS( *(LPVOID *)translationList[i] );
111     }
112
113     segBuff = MapLS( lpBuff );
114
115     /* Call 16-bit routine */
116
117     retv = Callbacks->CallUTProc( target, segBuff, dwUserDefined );
118
119     /* Free temporary selectors */
120
121     UnMapLS( segBuff );
122
123     if ( nList )
124     {
125         for ( i = 0; i < nList; i++ )
126             UnMapLS( segptrList[i] );
127
128         HeapFree( GetProcessHeap(), 0, segptrList );
129     }
130
131     return retv;
132 }
133
134 /****************************************************************************
135  *              UTAlloc
136  */
137 static UTINFO *UTAlloc( HMODULE hModule, HMODULE16 hModule16,
138                         FARPROC16 target16, FARPROC target32 )
139 {
140     UTINFO *ut = HeapAlloc( SegptrHeap, HEAP_ZERO_MEMORY, sizeof(UTINFO) );
141     if ( !ut ) return NULL;
142
143     ut->hModule   = hModule;
144     ut->hModule16 = hModule16;
145
146     ut->ut16.popl_eax  = 0x58;
147     ut->ut16.pushl     = 0x68;
148     ut->ut16.target    = (DWORD)target32;
149     ut->ut16.pushl_eax = 0x50;
150     ut->ut16.ljmp      = 0xea;
151     ut->ut16.utglue16  = (DWORD)MODULE_GetWndProcEntry16( "UTGlue16" );
152
153     ut->ut32.popl_eax  = 0x58;
154     ut->ut32.pushl     = 0x68;
155     ut->ut32.target    = (DWORD)target16;
156     ut->ut32.pushl_eax = 0x50;
157     ut->ut32.jmp       = 0xe9;
158     ut->ut32.utglue32  = (DWORD)UTGlue32 - ((DWORD)&ut->ut32.utglue32 + sizeof(DWORD));
159
160     ut->next = PROCESS_Current()->UTState;
161     PROCESS_Current()->UTState = ut;
162
163     return ut;
164 }
165
166 /****************************************************************************
167  *              UTFree
168  */
169 static void UTFree( UTINFO *ut )
170 {
171     UTINFO **ptr;
172
173     for ( ptr = &PROCESS_Current()->UTState; *ptr; ptr = &(*ptr)->next )
174         if ( *ptr == ut )
175         {
176             *ptr = ut->next;
177             break;
178         }
179
180     HeapFree( SegptrHeap, 0, ut );
181 }
182
183 /****************************************************************************
184  *              UTFind
185  */
186 static UTINFO *UTFind( HMODULE hModule )
187 {
188     UTINFO *ut;
189
190     for ( ut = PROCESS_Current()->UTState; ut; ut =ut->next )
191         if ( ut->hModule == hModule )
192             break;
193
194     return ut;
195 }
196
197
198 /****************************************************************************
199  *              UTRegister (KERNEL32.697)
200  */
201 BOOL WINAPI UTRegister( HMODULE hModule, LPSTR lpsz16BITDLL, 
202                         LPSTR lpszInitName, LPSTR lpszProcName,
203                         FARPROC *ppfn32Thunk, FARPROC pfnUT32CallBack, 
204                         LPVOID lpBuff )
205 {
206     UTINFO *ut;
207     HMODULE16 hModule16; 
208     FARPROC16 target16, init16; 
209
210     /* Load 16-bit DLL and get UTProc16 entry point */
211
212     if (   (hModule16 = LoadLibrary16( lpsz16BITDLL )) <= 32
213         || (target16  = WIN32_GetProcAddress16( hModule16, lpszProcName )) == 0 )
214         return FALSE;
215
216     /* Allocate UTINFO struct */
217
218     EnterCriticalSection( &PROCESS_Current()->crit_section );
219     if ( (ut = UTFind( hModule )) != NULL )
220         ut = NULL;
221     else
222         ut = UTAlloc( hModule, hModule16, target16, pfnUT32CallBack );
223     LeaveCriticalSection( &PROCESS_Current()->crit_section );
224
225     if ( !ut )
226     {
227         FreeLibrary16( hModule16 );
228         return FALSE;
229     }
230
231     /* Call UTInit16 if present */
232
233     if (     lpszInitName
234          && (init16 = WIN32_GetProcAddress16( hModule16, lpszInitName )) != 0 )
235     {
236         SEGPTR callback = SEGPTR_GET( &ut->ut16 );
237         SEGPTR segBuff  = MapLS( lpBuff );
238
239         if ( !Callbacks->CallUTProc( init16, callback, segBuff ) )
240         {
241             UnMapLS( segBuff );
242             UTUnRegister( hModule );
243             return FALSE;
244         }
245         UnMapLS( segBuff );
246     }
247
248     /* Return 32-bit thunk */
249
250     *ppfn32Thunk = (FARPROC) &ut->ut32;
251     
252     return TRUE;
253 }
254
255 /****************************************************************************
256  *              UTUnRegister (KERNEL32.698)
257  */
258 VOID WINAPI UTUnRegister( HMODULE hModule )
259 {
260     UTINFO *ut;
261     HMODULE16 hModule16 = 0;
262
263     EnterCriticalSection( &PROCESS_Current()->crit_section );
264     ut = UTFind( hModule );
265     if ( !ut )
266     {
267         hModule16 = ut->hModule16;
268         UTFree( ut );
269     }
270     LeaveCriticalSection( &PROCESS_Current()->crit_section );
271
272     if ( hModule16 ) 
273         FreeLibrary16( hModule16 );
274 }
275
276 /****************************************************************************
277  *              UTInit16     (KERNEL.494)
278  */
279 WORD WINAPI UTInit16( DWORD x1, DWORD x2, DWORD x3, DWORD x4 )
280 {
281     FIXME( thunk, "(%08lx, %08lx, %08lx, %08lx): stub\n", x1, x2, x3, x4 );
282     return 0;
283 }
284