Moved SystemHeap allocations to the process heap.
[wine] / if1632 / thunk.c
1 /*
2  * Emulator thunks
3  *
4  * Copyright 1996, 1997 Alexandre Julliard
5  * Copyright 1998       Ulrich Weigand
6  */
7
8 #include <string.h>
9 #include "wine/winbase16.h"
10 #include "task.h"
11 #include "hook.h"
12 #include "callback.h"
13 #include "builtin16.h"
14 #include "user.h"
15 #include "heap.h"
16 #include "neexe.h"
17 #include "process.h"
18 #include "stackframe.h"
19 #include "win.h"
20 #include "flatthunk.h"
21 #include "mouse.h"
22 #include "keyboard.h"
23 #include "debugtools.h"
24
25 DEFAULT_DEBUG_CHANNEL(thunk)
26
27
28 /* List of the 16-bit callback functions. This list is used  */
29 /* by the build program to generate the file if1632/callto16.S */
30
31 /* ### start build ### */
32 extern WORD CALLBACK THUNK_CallTo16_word_     (FARPROC16);
33 extern WORD CALLBACK THUNK_CallTo16_word_w    (FARPROC16,WORD);
34 extern WORD CALLBACK THUNK_CallTo16_word_l    (FARPROC16,LONG);
35 extern LONG CALLBACK THUNK_CallTo16_long_l    (FARPROC16,LONG);
36 extern WORD CALLBACK THUNK_CallTo16_word_ww   (FARPROC16,WORD,WORD);
37 extern WORD CALLBACK THUNK_CallTo16_word_wl   (FARPROC16,WORD,LONG);
38 extern WORD CALLBACK THUNK_CallTo16_word_ll   (FARPROC16,LONG,LONG);
39 extern LONG CALLBACK THUNK_CallTo16_long_ll   (FARPROC16,LONG,LONG);
40 extern WORD CALLBACK THUNK_CallTo16_word_www  (FARPROC16,WORD,WORD,WORD);
41 extern WORD CALLBACK THUNK_CallTo16_word_wwl  (FARPROC16,WORD,WORD,LONG);
42 extern WORD CALLBACK THUNK_CallTo16_word_wlw  (FARPROC16,WORD,LONG,WORD);
43 extern WORD CALLBACK THUNK_CallTo16_word_lllw (FARPROC16,LONG,LONG,LONG,WORD);
44 extern WORD CALLBACK THUNK_CallTo16_word_llwl (FARPROC16,LONG,LONG,WORD,LONG);
45 extern WORD CALLBACK THUNK_CallTo16_word_lwww (FARPROC16,LONG,WORD,WORD,WORD);
46 extern WORD CALLBACK THUNK_CallTo16_word_wlww (FARPROC16,WORD,LONG,WORD,WORD);
47 extern WORD CALLBACK THUNK_CallTo16_word_wwwl (FARPROC16,WORD,WORD,WORD,LONG);
48 extern LONG CALLBACK THUNK_CallTo16_long_wwwl (FARPROC16,WORD,WORD,WORD,LONG);
49 extern WORD CALLBACK THUNK_CallTo16_word_wllwl(FARPROC16,WORD,LONG,LONG,WORD,LONG);
50 extern WORD CALLBACK THUNK_CallTo16_word_lwwww(FARPROC16,LONG,WORD,WORD,WORD,WORD);
51 /* ### stop build ### */
52
53
54
55 #include "pshpack1.h"
56
57 typedef struct tagTHUNK
58 {
59     BYTE             popl_eax;           /* 0x58  popl  %eax (return address)*/
60     BYTE             pushl_func;         /* 0x68  pushl $proc */
61     FARPROC16        proc WINE_PACKED;
62     BYTE             pushl_eax;          /* 0x50  pushl %eax */
63     BYTE             jmp;                /* 0xe9  jmp   relay (relative jump)*/
64     RELAY            relay WINE_PACKED;
65     struct tagTHUNK *next WINE_PACKED;
66     DWORD            magic;
67 } THUNK;
68
69 #define CALLTO16_THUNK_MAGIC 0x54484e4b   /* "THNK" */
70
71 #include "poppack.h"
72
73 #define DECL_THUNK(aname,aproc,arelay) \
74     THUNK aname; \
75     aname.popl_eax = 0x58; \
76     aname.pushl_func = 0x68; \
77     aname.proc = (FARPROC) (aproc); \
78     aname.pushl_eax = 0x50; \
79     aname.jmp = 0xe9; \
80     aname.relay = (RELAY)((char *)(arelay) - (char *)(&(aname).next)); \
81     aname.next = NULL; \
82     aname.magic = CALLTO16_THUNK_MAGIC;
83
84 static THUNK *firstThunk = NULL;
85
86 static BOOL THUNK_ThunkletInit( void );
87
88 /* Callbacks function table for the emulator */
89 static const CALLBACKS_TABLE CALLBACK_EmulatorTable =
90 {
91     (void *)CallTo16RegisterShort,               /* CallRegisterShortProc */
92     (void *)CallTo16RegisterLong,                /* CallRegisterLongProc */
93     (void *)THUNK_CallTo16_word_w,               /* CallWindowsExitProc */
94     (void *)THUNK_CallTo16_word_lwww,            /* CallWordBreakProc */
95     (void *)THUNK_CallTo16_word_ww,              /* CallBootAppProc */
96     (void *)THUNK_CallTo16_word_www,             /* CallLoadAppSegProc */
97     (void *)THUNK_CallTo16_word_www,             /* CallLocalNotifyFunc */
98     (void *)THUNK_CallTo16_word_www,             /* CallResourceHandlerProc */
99     (void *)THUNK_CallTo16_long_ll,              /* CallUTProc */
100     (void *)THUNK_CallTo16_long_l                /* CallASPIPostProc */
101 };
102
103 const CALLBACKS_TABLE *Callbacks = &CALLBACK_EmulatorTable;
104
105 CALLOUT_TABLE Callout = { 0 };
106
107
108 /***********************************************************************
109  *           THUNK_Init
110  */
111 BOOL THUNK_Init(void)
112 {
113     /* Initialize Thunklets */
114     return THUNK_ThunkletInit();
115 }
116
117 /***********************************************************************
118  *           THUNK_Alloc
119  */
120 FARPROC THUNK_Alloc( FARPROC16 func, RELAY relay )
121 {
122     HANDLE16 hSeg;
123     NE_MODULE *pModule;
124     THUNK *thunk;
125
126     /* NULL maps to NULL */
127     if ( !func ) return NULL;
128
129     /* 
130      * If we got an 16-bit built-in API entry point, retrieve the Wine
131      * 32-bit handler for that API routine.
132      *
133      * NOTE: For efficiency reasons, we only check whether the selector
134      *       of 'func' points to the code segment of a built-in module.
135      *       It might be theoretically possible that the offset is such
136      *       that 'func' does not point, in fact, to an API entry point.
137      *       In this case, however, the pointer is corrupt anyway.
138      */
139     hSeg = GlobalHandle16( SELECTOROF( func ) );
140     pModule = NE_GetPtr( FarGetOwner16( hSeg ) );
141
142     if ( pModule && (pModule->flags & NE_FFLAGS_BUILTIN) 
143                  && NE_SEG_TABLE(pModule)[0].hSeg == hSeg )
144     {
145         FARPROC proc = (FARPROC)((ENTRYPOINT16 *)PTR_SEG_TO_LIN( func ))->target;
146
147         TRACE( "(%04x:%04x, %p) -> built-in API %p\n",
148                SELECTOROF( func ), OFFSETOF( func ), relay, proc );
149         return proc;
150     }
151
152     /* Otherwise, we need to alloc a thunk */
153     thunk = HeapAlloc( GetProcessHeap(), 0, sizeof(*thunk) );
154     if (thunk)
155     {
156         thunk->popl_eax   = 0x58;
157         thunk->pushl_func = 0x68;
158         thunk->proc       = func;
159         thunk->pushl_eax  = 0x50;
160         thunk->jmp        = 0xe9;
161         thunk->relay      = (RELAY)((char *)relay - (char *)(&thunk->next));
162         thunk->magic      = CALLTO16_THUNK_MAGIC;
163         thunk->next       = firstThunk;
164         firstThunk = thunk;
165     }
166
167     TRACE( "(%04x:%04x, %p) -> allocated thunk %p\n",
168            SELECTOROF( func ), OFFSETOF( func ), relay, thunk );
169     return (FARPROC)thunk;
170 }
171
172 /***********************************************************************
173  *           THUNK_Free
174  */
175 void THUNK_Free( FARPROC thunk )
176 {
177     THUNK *t = (THUNK*)thunk;
178     if ( !t || IsBadReadPtr( t, sizeof(*t) ) 
179             || t->magic != CALLTO16_THUNK_MAGIC )
180          return;
181
182     if (HEAP_IsInsideHeap( GetProcessHeap(), 0, t ))
183     {
184         THUNK **prev = &firstThunk;
185         while (*prev && (*prev != t)) prev = &(*prev)->next;
186         if (*prev)
187         {
188             *prev = t->next;
189             HeapFree( GetProcessHeap(), 0, t );
190             return;
191         }
192     }
193     ERR("invalid thunk addr %p\n", thunk );
194     return;
195 }
196
197
198 /***********************************************************************
199  *           THUNK_EnumObjects16   (GDI.71)
200  */
201 INT16 WINAPI THUNK_EnumObjects16( HDC16 hdc, INT16 nObjType,
202                                   GOBJENUMPROC16 func, LPARAM lParam )
203 {
204     DECL_THUNK( thunk, func, THUNK_CallTo16_word_ll );
205     return EnumObjects16( hdc, nObjType, (GOBJENUMPROC16)&thunk, lParam );
206 }
207
208
209 /*************************************************************************
210  *           THUNK_EnumFonts16   (GDI.70)
211  */
212 INT16 WINAPI THUNK_EnumFonts16( HDC16 hdc, LPCSTR lpFaceName,
213                                 FONTENUMPROC16 func, LPARAM lParam )
214 {
215     DECL_THUNK( thunk, func, THUNK_CallTo16_word_llwl );
216     return EnumFonts16( hdc, lpFaceName, (FONTENUMPROC16)&thunk, lParam );
217 }
218
219 /******************************************************************
220  *           THUNK_EnumMetaFile16   (GDI.175)
221  */
222 BOOL16 WINAPI THUNK_EnumMetaFile16( HDC16 hdc, HMETAFILE16 hmf,
223                                     MFENUMPROC16 func, LPARAM lParam )
224 {
225     DECL_THUNK( thunk, func, THUNK_CallTo16_word_wllwl );
226     return EnumMetaFile16( hdc, hmf, (MFENUMPROC16)&thunk, lParam );
227 }
228
229
230 /*************************************************************************
231  *           THUNK_EnumFontFamilies16   (GDI.330)
232  */
233 INT16 WINAPI THUNK_EnumFontFamilies16( HDC16 hdc, LPCSTR lpszFamily,
234                                        FONTENUMPROC16 func, LPARAM lParam )
235 {
236     DECL_THUNK( thunk, func, THUNK_CallTo16_word_llwl );
237     return EnumFontFamilies16(hdc, lpszFamily, (FONTENUMPROC16)&thunk, lParam);
238 }
239
240
241 /*************************************************************************
242  *           THUNK_EnumFontFamiliesEx16   (GDI.613)
243  */
244 INT16 WINAPI THUNK_EnumFontFamiliesEx16( HDC16 hdc, LPLOGFONT16 lpLF,
245                                          FONTENUMPROCEX16 func, LPARAM lParam,
246                                          DWORD reserved )
247 {
248     DECL_THUNK( thunk, func, THUNK_CallTo16_word_llwl );
249     return EnumFontFamiliesEx16( hdc, lpLF, (FONTENUMPROCEX16)&thunk,
250                                  lParam, reserved );
251 }
252
253
254 /**********************************************************************
255  *           THUNK_LineDDA16   (GDI.100)
256  */
257 void WINAPI THUNK_LineDDA16( INT16 nXStart, INT16 nYStart, INT16 nXEnd,
258                              INT16 nYEnd, LINEDDAPROC16 func, LPARAM lParam )
259 {
260     DECL_THUNK( thunk, func, THUNK_CallTo16_word_wwl );
261     LineDDA16( nXStart, nYStart, nXEnd, nYEnd, (LINEDDAPROC16)&thunk, lParam );
262 }
263
264
265 /*******************************************************************
266  *           THUNK_EnumWindows16   (USER.54)
267  */
268 BOOL16 WINAPI THUNK_EnumWindows16( WNDENUMPROC16 func, LPARAM lParam )
269 {
270     DECL_THUNK( thunk, func, THUNK_CallTo16_word_wl );
271     return EnumWindows16( (WNDENUMPROC16)&thunk, lParam );
272 }
273
274
275 /**********************************************************************
276  *           THUNK_EnumChildWindows16   (USER.55)
277  */
278 BOOL16 WINAPI THUNK_EnumChildWindows16( HWND16 parent, WNDENUMPROC16 func,
279                                         LPARAM lParam )
280 {
281     DECL_THUNK( thunk, func, THUNK_CallTo16_word_wl );
282     return EnumChildWindows16( parent, (WNDENUMPROC16)&thunk, lParam );
283 }
284
285
286 /**********************************************************************
287  *           THUNK_EnumTaskWindows16   (USER.225)
288  */
289 BOOL16 WINAPI THUNK_EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
290                                        LPARAM lParam )
291 {
292     DECL_THUNK( thunk, func, THUNK_CallTo16_word_wl );
293     return EnumTaskWindows16( hTask, (WNDENUMPROC16)&thunk, lParam );
294 }
295
296
297 /***********************************************************************
298  *           THUNK_EnumProps16   (USER.27)
299  */
300 INT16 WINAPI THUNK_EnumProps16( HWND16 hwnd, PROPENUMPROC16 func )
301 {
302     DECL_THUNK( thunk, func, THUNK_CallTo16_word_wlw );
303     return EnumProps16( hwnd, (PROPENUMPROC16)&thunk );
304 }
305
306
307 /***********************************************************************
308  *           THUNK_GrayString16   (USER.185)
309  */
310 BOOL16 WINAPI THUNK_GrayString16( HDC16 hdc, HBRUSH16 hbr,
311                                   GRAYSTRINGPROC16 func, LPARAM lParam,
312                                   INT16 cch, INT16 x, INT16 y,
313                                   INT16 cx, INT16 cy )
314 {
315     DECL_THUNK( thunk, func, THUNK_CallTo16_word_wlw );
316     if (!func)
317         return GrayString16( hdc, hbr, NULL, lParam, cch, x, y, cx, cy );
318     else
319         return GrayString16( hdc, hbr, (GRAYSTRINGPROC16)&thunk, lParam, cch,
320                              x, y, cx, cy );
321 }
322
323
324 /***********************************************************************
325  *           THUNK_GetCalloutThunk
326  *
327  * Retrieve API entry point with given name from given module.
328  * If module is builtin, return the 32-bit entry point, otherwise
329  * create a 32->16 thunk to the 16-bit entry point, using the 
330  * given relay code.
331  *
332  */
333 static FARPROC THUNK_GetCalloutThunk( NE_MODULE *pModule, LPSTR name, RELAY relay )
334 {
335     FARPROC16 proc = WIN32_GetProcAddress16( pModule->self, name );
336     if ( !proc ) return 0;
337
338     if ( pModule->flags & NE_FFLAGS_BUILTIN )
339         return (FARPROC)((ENTRYPOINT16 *)PTR_SEG_TO_LIN( proc ))->target;
340     else
341         return (FARPROC)THUNK_Alloc( proc, relay );
342 }
343
344 /***********************************************************************
345  *           THUNK_InitCallout
346  */
347 void THUNK_InitCallout(void)
348 {
349     HMODULE hModule;
350     NE_MODULE *pModule;
351
352     hModule = GetModuleHandleA( "USER32" );
353     if ( hModule )
354     {
355 #define GETADDR( var, name )  \
356         *(FARPROC *)&Callout.##var = GetProcAddress( hModule, name )
357
358         GETADDR( PeekMessageA, "PeekMessageA" );
359         GETADDR( PeekMessageW, "PeekMessageW" );
360         GETADDR( GetMessageA, "GetMessageA" );
361         GETADDR( GetMessageW, "GetMessageW" );
362         GETADDR( SendMessageA, "SendMessageA" );
363         GETADDR( SendMessageW, "SendMessageW" );
364         GETADDR( PostMessageA, "PostMessageA" );
365         GETADDR( PostMessageW, "PostMessageW" );
366         GETADDR( PostThreadMessageA, "PostThreadMessageA" );
367         GETADDR( PostThreadMessageW, "PostThreadMessageW" );
368         GETADDR( TranslateMessage, "TranslateMessage" );
369         GETADDR( DispatchMessageW, "DispatchMessageW" );
370         GETADDR( DispatchMessageA, "DispatchMessageA" );
371         GETADDR( RedrawWindow, "RedrawWindow" );
372         GETADDR( WaitForInputIdle, "WaitForInputIdle" );
373
374 #undef GETADDR
375     }
376
377     pModule = NE_GetPtr( GetModuleHandle16( "USER" ) );
378     if ( pModule )
379     {
380 #define GETADDR( var, name, thk )  \
381         *(FARPROC *)&Callout.##var = THUNK_GetCalloutThunk( pModule, name, \
382                                                  (RELAY)THUNK_CallTo16_##thk )
383
384         GETADDR( PeekMessage16, "PeekMessage", word_lwwww );
385         GETADDR( GetMessage16, "GetMessage", word_lwww );
386         GETADDR( SendMessage16, "SendMessage", long_wwwl );
387         GETADDR( PostMessage16, "PostMessage", word_wwwl );
388         GETADDR( PostAppMessage16, "PostAppMessage", word_wwwl );
389         GETADDR( TranslateMessage16, "TranslateMessage", word_l );
390         GETADDR( DispatchMessage16, "DispatchMessage", long_l );
391         GETADDR( RedrawWindow16, "RedrawWindow", word_wlww );
392         GETADDR( FinalUserInit16, "FinalUserInit", word_ );
393         GETADDR( InitApp16, "InitApp", word_w );
394         GETADDR( InitThreadInput16, "InitThreadInput", word_ww );
395         GETADDR( UserYield16, "UserYield", word_ );
396         GETADDR( DestroyIcon32, "DestroyIcon32", word_ww );
397         GETADDR( UserSignalProc, "SignalProc32", word_lllw );
398
399 #undef GETADDR
400     }
401 }
402
403 /***********************************************************************
404  * 16->32 Flat Thunk routines:
405  */
406
407 /***********************************************************************
408  *              ThunkConnect16          (KERNEL.651)
409  * Connects a 32bit and a 16bit thunkbuffer.
410  */
411 UINT WINAPI ThunkConnect16(
412         LPSTR module16,              /* [in] name of win16 dll */
413         LPSTR module32,              /* [in] name of win32 dll */
414         HINSTANCE16 hInst16,         /* [in] hInst of win16 dll */
415         DWORD dwReason,              /* [in] initialisation argument */
416         struct ThunkDataCommon *TD,  /* [in/out] thunkbuffer */
417         LPSTR thunkfun32,            /* [in] win32 thunkfunction */
418         WORD cs                      /* [in] CS of win16 dll */
419 ) {
420     BOOL directionSL;
421
422     if (!strncmp(TD->magic, "SL01", 4))
423     {
424         directionSL = TRUE;
425
426         TRACE("SL01 thunk %s (%lx) -> %s (%s), Reason: %ld\n",
427               module16, (DWORD)TD, module32, thunkfun32, dwReason);
428     }
429     else if (!strncmp(TD->magic, "LS01", 4))
430     {
431         directionSL = FALSE;
432
433         TRACE("LS01 thunk %s (%lx) <- %s (%s), Reason: %ld\n",
434               module16, (DWORD)TD, module32, thunkfun32, dwReason);
435     }
436     else
437     {
438         ERR("Invalid magic %c%c%c%c\n",
439             TD->magic[0], TD->magic[1], TD->magic[2], TD->magic[3]);
440         return 0;
441     }
442
443     switch (dwReason)
444     {
445         case DLL_PROCESS_ATTACH:
446             if (directionSL)
447             {
448                 struct ThunkDataSL16 *SL16 = (struct ThunkDataSL16 *)TD;
449                 struct ThunkDataSL   *SL   = SL16->fpData;
450
451                 if (SL == NULL)
452                 {
453                     SL = HeapAlloc(GetProcessHeap(), 0, sizeof(*SL));
454
455                     SL->common   = SL16->common;
456                     SL->flags1   = SL16->flags1;
457                     SL->flags2   = SL16->flags2;
458
459                     SL->apiDB    = PTR_SEG_TO_LIN(SL16->apiDatabase);
460                     SL->targetDB = NULL;
461
462                     lstrcpynA(SL->pszDll16, module16, 255);
463                     lstrcpynA(SL->pszDll32, module32, 255);
464
465                     /* We should create a SEGPTR to the ThunkDataSL,
466                        but since the contents are not in the original format,
467                        any access to this by 16-bit code would crash anyway. */
468                     SL16->spData = 0;
469                     SL16->fpData = SL;
470                 }
471
472
473                 if (SL->flags2 & 0x80000000)
474                 {
475                     TRACE("Preloading 32-bit library\n");
476                     LoadLibraryA(module32);
477                 }
478             }
479             else
480             {
481                 /* nothing to do */
482             }
483             break;
484
485         case DLL_PROCESS_DETACH:
486             /* FIXME: cleanup */
487             break;
488     }
489
490     return 1;
491 }
492
493
494 /***********************************************************************
495  *           C16ThkSL                           (KERNEL.630)
496  */
497
498 void WINAPI C16ThkSL(CONTEXT86 *context)
499 {
500     LPBYTE stub = PTR_SEG_TO_LIN(EAX_reg(context)), x = stub;
501     WORD cs, ds;
502     GET_CS(cs);
503     GET_DS(ds);
504
505     /* We produce the following code:
506      *
507      *   mov ax, __FLATDS
508      *   mov es, ax
509      *   movzx ecx, cx
510      *   mov edx, es:[ecx + $EDX]
511      *   push bp
512      *   push edx
513      *   push dx
514      *   push edx
515      *   call __FLATCS:CallFrom16Thunk
516      */
517
518     *x++ = 0xB8; *((WORD *)x)++ = ds;
519     *x++ = 0x8E; *x++ = 0xC0;
520     *x++ = 0x66; *x++ = 0x0F; *x++ = 0xB7; *x++ = 0xC9;
521     *x++ = 0x67; *x++ = 0x66; *x++ = 0x26; *x++ = 0x8B;
522                  *x++ = 0x91; *((DWORD *)x)++ = EDX_reg(context);
523
524     *x++ = 0x55;
525     *x++ = 0x66; *x++ = 0x52;
526     *x++ = 0x52;
527     *x++ = 0x66; *x++ = 0x52;
528     *x++ = 0x66; *x++ = 0x9A; *((DWORD *)x)++ = (DWORD)CallFrom16Thunk;
529                               *((WORD *)x)++ = cs;
530
531     /* Jump to the stub code just created */
532     EIP_reg(context) = LOWORD(EAX_reg(context));
533     CS_reg(context)  = HIWORD(EAX_reg(context));
534
535     /* Since C16ThkSL got called by a jmp, we need to leave the
536        original return address on the stack */
537     ESP_reg(context) -= 4;
538 }
539
540 /***********************************************************************
541  *           C16ThkSL01                         (KERNEL.631)
542  */
543
544 void WINAPI C16ThkSL01(CONTEXT86 *context)
545 {
546     LPBYTE stub = PTR_SEG_TO_LIN(EAX_reg(context)), x = stub;
547
548     if (stub)
549     {
550         struct ThunkDataSL16 *SL16 = PTR_SEG_TO_LIN(EDX_reg(context));
551         struct ThunkDataSL *td = SL16->fpData;
552
553         DWORD procAddress = (DWORD)GetProcAddress16(GetModuleHandle16("KERNEL"), 631);
554         WORD cs;
555         GET_CS(cs);
556
557         if (!td)
558         {
559             ERR("ThunkConnect16 was not called!\n");
560             return;
561         }
562
563         TRACE("Creating stub for ThunkDataSL %08lx\n", (DWORD)td);
564
565
566         /* We produce the following code:
567          *
568          *   xor eax, eax
569          *   mov edx, $td
570          *   call C16ThkSL01
571          *   push bp
572          *   push edx
573          *   push dx
574          *   push edx
575          *   call __FLATCS:CallFrom16Thunk
576          */
577
578         *x++ = 0x66; *x++ = 0x33; *x++ = 0xC0;
579         *x++ = 0x66; *x++ = 0xBA; *((DWORD *)x)++ = (DWORD)td;
580         *x++ = 0x9A; *((DWORD *)x)++ = procAddress;
581
582         *x++ = 0x55;
583         *x++ = 0x66; *x++ = 0x52;
584         *x++ = 0x52;
585         *x++ = 0x66; *x++ = 0x52;
586         *x++ = 0x66; *x++ = 0x9A; *((DWORD *)x)++ = (DWORD)CallFrom16Thunk;
587                                   *((WORD *)x)++ = cs;
588
589         /* Jump to the stub code just created */
590         EIP_reg(context) = LOWORD(EAX_reg(context));
591         CS_reg(context)  = HIWORD(EAX_reg(context));
592
593         /* Since C16ThkSL01 got called by a jmp, we need to leave the
594            orginal return address on the stack */
595         ESP_reg(context) -= 4;
596     }
597     else
598     {
599         struct ThunkDataSL *td = (struct ThunkDataSL *)EDX_reg(context);
600         DWORD targetNr = CX_reg(context) / 4;
601         struct SLTargetDB *tdb;
602
603         TRACE("Process %08lx calling target %ld of ThunkDataSL %08lx\n",
604               (DWORD)PROCESS_Current(), targetNr, (DWORD)td);
605
606         for (tdb = td->targetDB; tdb; tdb = tdb->next)
607             if (tdb->process == PROCESS_Current())
608                 break;
609
610         if (!tdb)
611         {
612             TRACE("Loading 32-bit library %s\n", td->pszDll32);
613             LoadLibraryA(td->pszDll32);
614
615             for (tdb = td->targetDB; tdb; tdb = tdb->next)
616                 if (tdb->process == PROCESS_Current())
617                     break;
618         }
619
620         if (tdb)
621         {
622             EDX_reg(context) = tdb->targetTable[targetNr];
623
624             TRACE("Call target is %08lx\n", EDX_reg(context));
625         }
626         else
627         {
628             WORD *stack = PTR_SEG_OFF_TO_LIN(SS_reg(context), LOWORD(ESP_reg(context)));
629             DX_reg(context) = HIWORD(td->apiDB[targetNr].errorReturnValue);
630             AX_reg(context) = LOWORD(td->apiDB[targetNr].errorReturnValue);
631             EIP_reg(context) = stack[2];
632             CS_reg(context)  = stack[3];
633             ESP_reg(context) += td->apiDB[targetNr].nrArgBytes + 4;
634
635             ERR("Process %08lx did not ThunkConnect32 %s to %s\n",
636                 (DWORD)PROCESS_Current(), td->pszDll32, td->pszDll16);
637         }
638     }
639 }
640
641
642
643 /***********************************************************************
644  * 16<->32 Thunklet/Callback API:
645  */
646
647 #include "pshpack1.h"
648 typedef struct _THUNKLET
649 {
650     BYTE        prefix_target;
651     BYTE        pushl_target;
652     DWORD       target;
653
654     BYTE        prefix_relay;
655     BYTE        pushl_relay;
656     DWORD       relay;
657
658     BYTE        jmp_glue;
659     DWORD       glue;
660
661     BYTE        type;
662     HINSTANCE16 owner;
663     struct _THUNKLET *next;
664 } THUNKLET;
665 #include "poppack.h"
666
667 #define THUNKLET_TYPE_LS  1
668 #define THUNKLET_TYPE_SL  2
669
670 static HANDLE  ThunkletHeap = 0;
671 static THUNKLET *ThunkletAnchor = NULL;
672
673 static FARPROC ThunkletSysthunkGlueLS = 0;
674 static SEGPTR    ThunkletSysthunkGlueSL = 0;
675
676 static FARPROC ThunkletCallbackGlueLS = 0;
677 static SEGPTR    ThunkletCallbackGlueSL = 0;
678
679 /***********************************************************************
680  *     THUNK_ThunkletInit
681  */
682 static BOOL THUNK_ThunkletInit( void )
683 {
684     LPBYTE thunk;
685
686     ThunkletHeap = HeapCreate(HEAP_WINE_SEGPTR | HEAP_WINE_CODE16SEG, 0, 0);
687     if (!ThunkletHeap) return FALSE;
688
689     thunk = HeapAlloc( ThunkletHeap, 0, 5 );
690     if (!thunk) return FALSE;
691     
692     ThunkletSysthunkGlueLS = (FARPROC)thunk;
693     *thunk++ = 0x58;                             /* popl eax */
694     *thunk++ = 0xC3;                             /* ret      */
695
696     ThunkletSysthunkGlueSL = HEAP_GetSegptr( ThunkletHeap, 0, thunk );
697     *thunk++ = 0x66; *thunk++ = 0x58;            /* popl eax */
698     *thunk++ = 0xCB;                             /* lret     */
699
700     return TRUE;
701 }
702
703 /***********************************************************************
704  *     SetThunkletCallbackGlue             (KERNEL.560)
705  */
706 void WINAPI SetThunkletCallbackGlue16( FARPROC glueLS, SEGPTR glueSL )
707 {
708     ThunkletCallbackGlueLS = glueLS;
709     ThunkletCallbackGlueSL = glueSL;
710 }
711
712
713 /***********************************************************************
714  *     THUNK_FindThunklet
715  */
716 THUNKLET *THUNK_FindThunklet( DWORD target, DWORD relay, 
717                               DWORD glue, BYTE type ) 
718 {
719     THUNKLET *thunk; 
720
721     for (thunk = ThunkletAnchor; thunk; thunk = thunk->next)
722         if (    thunk->type   == type
723              && thunk->target == target
724              && thunk->relay  == relay 
725              && ( type == THUNKLET_TYPE_LS ?
726                     ( thunk->glue == glue - (DWORD)&thunk->type )
727                   : ( thunk->glue == glue ) ) )
728             return thunk;
729
730      return NULL;
731 }
732
733 /***********************************************************************
734  *     THUNK_AllocLSThunklet
735  */
736 FARPROC THUNK_AllocLSThunklet( SEGPTR target, DWORD relay, 
737                                  FARPROC glue, HTASK16 owner ) 
738 {
739     THUNKLET *thunk = THUNK_FindThunklet( (DWORD)target, relay, (DWORD)glue,
740                                           THUNKLET_TYPE_LS );
741     if (!thunk)
742     {
743         TDB *pTask = (TDB*)GlobalLock16( owner );
744
745         if ( !(thunk = HeapAlloc( ThunkletHeap, 0, sizeof(THUNKLET) )) )
746             return 0;
747
748         thunk->prefix_target = thunk->prefix_relay = 0x90;
749         thunk->pushl_target  = thunk->pushl_relay  = 0x68;
750         thunk->jmp_glue = 0xE9;
751
752         thunk->target  = (DWORD)target;
753         thunk->relay   = (DWORD)relay;
754         thunk->glue    = (DWORD)glue - (DWORD)&thunk->type;
755
756         thunk->type    = THUNKLET_TYPE_LS;
757         thunk->owner   = pTask? pTask->hInstance : 0;
758
759         thunk->next    = ThunkletAnchor;
760         ThunkletAnchor = thunk;
761     }
762
763     return (FARPROC)thunk;
764 }
765
766 /***********************************************************************
767  *     THUNK_AllocSLThunklet
768  */
769 SEGPTR THUNK_AllocSLThunklet( FARPROC target, DWORD relay,
770                               SEGPTR glue, HTASK16 owner )
771 {
772     THUNKLET *thunk = THUNK_FindThunklet( (DWORD)target, relay, (DWORD)glue,
773                                           THUNKLET_TYPE_SL );
774     if (!thunk)
775     {
776         TDB *pTask = (TDB*)GlobalLock16( owner );
777
778         if ( !(thunk = HeapAlloc( ThunkletHeap, 0, sizeof(THUNKLET) )) )
779             return 0;
780
781         thunk->prefix_target = thunk->prefix_relay = 0x66;
782         thunk->pushl_target  = thunk->pushl_relay  = 0x68;
783         thunk->jmp_glue = 0xEA;
784
785         thunk->target  = (DWORD)target;
786         thunk->relay   = (DWORD)relay;
787         thunk->glue    = (DWORD)glue;
788
789         thunk->type    = THUNKLET_TYPE_SL;
790         thunk->owner   = pTask? pTask->hInstance : 0;
791
792         thunk->next    = ThunkletAnchor;
793         ThunkletAnchor = thunk;
794     }
795
796     return HEAP_GetSegptr( ThunkletHeap, 0, thunk );
797 }
798
799 /**********************************************************************
800  *     IsLSThunklet
801  */
802 BOOL16 WINAPI IsLSThunklet( THUNKLET *thunk )
803 {
804     return    thunk->prefix_target == 0x90 && thunk->pushl_target == 0x68
805            && thunk->prefix_relay  == 0x90 && thunk->pushl_relay  == 0x68
806            && thunk->jmp_glue == 0xE9 && thunk->type == THUNKLET_TYPE_LS;
807 }
808
809 /**********************************************************************
810  *     IsSLThunklet                        (KERNEL.612)
811  */
812 BOOL16 WINAPI IsSLThunklet16( THUNKLET *thunk )
813 {
814     return    thunk->prefix_target == 0x66 && thunk->pushl_target == 0x68
815            && thunk->prefix_relay  == 0x66 && thunk->pushl_relay  == 0x68
816            && thunk->jmp_glue == 0xEA && thunk->type == THUNKLET_TYPE_SL;
817 }
818
819
820
821 /***********************************************************************
822  *     AllocLSThunkletSysthunk             (KERNEL.607)
823  */
824 FARPROC WINAPI AllocLSThunkletSysthunk16( SEGPTR target, 
825                                           FARPROC relay, DWORD dummy )
826 {
827     return THUNK_AllocLSThunklet( (SEGPTR)relay, (DWORD)target, 
828                                   ThunkletSysthunkGlueLS, GetCurrentTask() );
829 }
830
831 /***********************************************************************
832  *     AllocSLThunkletSysthunk             (KERNEL.608)
833  */
834 SEGPTR WINAPI AllocSLThunkletSysthunk16( FARPROC target, 
835                                        SEGPTR relay, DWORD dummy )
836 {
837     return THUNK_AllocSLThunklet( (FARPROC)relay, (DWORD)target, 
838                                   ThunkletSysthunkGlueSL, GetCurrentTask() );
839 }
840
841
842 /***********************************************************************
843  *     AllocLSThunkletCallbackEx           (KERNEL.567)
844  */
845 FARPROC WINAPI AllocLSThunkletCallbackEx16( SEGPTR target, 
846                                             DWORD relay, HTASK16 task )
847 {
848     THUNKLET *thunk = (THUNKLET *)PTR_SEG_TO_LIN( target );
849     if ( !thunk ) return NULL;
850
851     if (   IsSLThunklet16( thunk ) && thunk->relay == relay 
852         && thunk->glue == (DWORD)ThunkletCallbackGlueSL )
853         return (FARPROC)thunk->target;
854
855     return THUNK_AllocLSThunklet( target, relay, 
856                                   ThunkletCallbackGlueLS, task );
857 }
858
859 /***********************************************************************
860  *     AllocSLThunkletCallbackEx           (KERNEL.568)
861  */
862 SEGPTR WINAPI AllocSLThunkletCallbackEx16( FARPROC target, 
863                                          DWORD relay, HTASK16 task )
864 {
865     THUNKLET *thunk = (THUNKLET *)target;
866     if ( !thunk ) return 0;
867
868     if (   IsLSThunklet( thunk ) && thunk->relay == relay 
869         && thunk->glue == (DWORD)ThunkletCallbackGlueLS - (DWORD)&thunk->type )
870         return (SEGPTR)thunk->target;
871
872     return THUNK_AllocSLThunklet( target, relay, 
873                                   ThunkletCallbackGlueSL, task );
874 }
875
876 /***********************************************************************
877  *     AllocLSThunkletCallback             (KERNEL.561) (KERNEL.606)
878  */
879 FARPROC WINAPI AllocLSThunkletCallback16( SEGPTR target, DWORD relay )
880 {
881     return AllocLSThunkletCallbackEx16( target, relay, GetCurrentTask() );
882 }
883
884 /***********************************************************************
885  *     AllocSLThunkletCallback             (KERNEL.562) (KERNEL.605)
886  */
887 SEGPTR WINAPI AllocSLThunkletCallback16( FARPROC target, DWORD relay )
888 {
889     return AllocSLThunkletCallbackEx16( target, relay, GetCurrentTask() );
890 }
891
892 /***********************************************************************
893  *     FindLSThunkletCallback              (KERNEL.563) (KERNEL.609)
894  */
895 FARPROC WINAPI FindLSThunkletCallback( SEGPTR target, DWORD relay )
896 {
897     THUNKLET *thunk = (THUNKLET *)PTR_SEG_TO_LIN( target );
898     if (   thunk && IsSLThunklet16( thunk ) && thunk->relay == relay 
899         && thunk->glue == (DWORD)ThunkletCallbackGlueSL )
900         return (FARPROC)thunk->target;
901
902     thunk = THUNK_FindThunklet( (DWORD)target, relay, 
903                                 (DWORD)ThunkletCallbackGlueLS, 
904                                 THUNKLET_TYPE_LS );
905     return (FARPROC)thunk;
906 }
907
908 /***********************************************************************
909  *     FindSLThunkletCallback              (KERNEL.564) (KERNEL.610)
910  */
911 SEGPTR WINAPI FindSLThunkletCallback( FARPROC target, DWORD relay )
912 {
913     THUNKLET *thunk = (THUNKLET *)target;
914     if (   thunk && IsLSThunklet( thunk ) && thunk->relay == relay 
915         && thunk->glue == (DWORD)ThunkletCallbackGlueLS - (DWORD)&thunk->type )
916         return (SEGPTR)thunk->target;
917
918     thunk = THUNK_FindThunklet( (DWORD)target, relay, 
919                                 (DWORD)ThunkletCallbackGlueSL, 
920                                 THUNKLET_TYPE_SL );
921     return HEAP_GetSegptr( ThunkletHeap, 0, thunk );
922 }
923
924
925 /***********************************************************************
926  *     FreeThunklet16            (KERNEL.611)
927  */
928 BOOL16 WINAPI FreeThunklet16( DWORD unused1, DWORD unused2 )
929 {
930     return FALSE;
931 }
932
933 /***********************************************************************
934  * Callback Client API
935  */
936
937 #define N_CBC_FIXED    20
938 #define N_CBC_VARIABLE 10
939 #define N_CBC_TOTAL    (N_CBC_FIXED + N_CBC_VARIABLE)
940
941 static SEGPTR CBClientRelay16[ N_CBC_TOTAL ];
942 static FARPROC *CBClientRelay32[ N_CBC_TOTAL ];
943
944 /***********************************************************************
945  *     RegisterCBClient                    (KERNEL.619)
946  */
947 INT16 WINAPI RegisterCBClient16( INT16 wCBCId, 
948                                  SEGPTR relay16, FARPROC *relay32 )
949 {
950     /* Search for free Callback ID */
951     if ( wCBCId == -1 )
952         for ( wCBCId = N_CBC_FIXED; wCBCId < N_CBC_TOTAL; wCBCId++ )
953             if ( !CBClientRelay16[ wCBCId ] )
954                 break;
955
956     /* Register Callback ID */
957     if ( wCBCId > 0 && wCBCId < N_CBC_TOTAL )
958     {
959         CBClientRelay16[ wCBCId ] = relay16;
960         CBClientRelay32[ wCBCId ] = relay32;
961     }
962     else
963         wCBCId = 0;
964
965     return wCBCId;
966 }
967
968 /***********************************************************************
969  *     UnRegisterCBClient                  (KERNEL.622)
970  */
971 INT16 WINAPI UnRegisterCBClient16( INT16 wCBCId, 
972                                    SEGPTR relay16, FARPROC *relay32 )
973 {
974     if (    wCBCId >= N_CBC_FIXED && wCBCId < N_CBC_TOTAL 
975          && CBClientRelay16[ wCBCId ] == relay16 
976          && CBClientRelay32[ wCBCId ] == relay32 )
977     {
978         CBClientRelay16[ wCBCId ] = 0;
979         CBClientRelay32[ wCBCId ] = 0;
980     }
981     else
982         wCBCId = 0;
983
984     return wCBCId;
985 }
986
987
988 /***********************************************************************
989  *     InitCBClient                        (KERNEL.623)
990  */
991 void WINAPI InitCBClient16( FARPROC glueLS )
992 {
993     HMODULE16 kernel = GetModuleHandle16( "KERNEL" );
994     SEGPTR glueSL = (SEGPTR)WIN32_GetProcAddress16( kernel, (LPCSTR)604 );
995
996     SetThunkletCallbackGlue16( glueLS, glueSL );
997 }
998
999 /***********************************************************************
1000  *     CBClientGlueSL                      (KERNEL.604)
1001  */
1002 void WINAPI CBClientGlueSL( CONTEXT86 *context )
1003 {
1004     /* Create stack frame */
1005     SEGPTR stackSeg = stack16_push( 12 );
1006     LPWORD stackLin = PTR_SEG_TO_LIN( stackSeg );
1007     SEGPTR glue, *glueTab;
1008     
1009     stackLin[3] = BP_reg( context );
1010     stackLin[2] = SI_reg( context );
1011     stackLin[1] = DI_reg( context );
1012     stackLin[0] = DS_reg( context );
1013
1014     EBP_reg( context ) = OFFSETOF( stackSeg ) + 6;
1015     ESP_reg( context ) = OFFSETOF( stackSeg ) - 4;
1016     GS_reg( context ) = 0;
1017
1018     /* Jump to 16-bit relay code */
1019     glueTab = PTR_SEG_TO_LIN( CBClientRelay16[ stackLin[5] ] );
1020     glue = glueTab[ stackLin[4] ];
1021     CS_reg ( context ) = SELECTOROF( glue );
1022     EIP_reg( context ) = OFFSETOF  ( glue );
1023 }
1024
1025 /***********************************************************************
1026  *     CBClientThunkSL                      (KERNEL.620)
1027  */
1028 extern DWORD CALL32_CBClient( FARPROC proc, LPWORD args, DWORD *esi );
1029 void WINAPI CBClientThunkSL( CONTEXT86 *context )
1030 {
1031     /* Call 32-bit relay code */
1032
1033     LPWORD args = PTR_SEG_OFF_TO_LIN( SS_reg( context ), BP_reg( context ) );
1034     FARPROC proc = CBClientRelay32[ args[2] ][ args[1] ];
1035
1036     EAX_reg(context) = CALL32_CBClient( proc, args, &ESI_reg( context ) );
1037 }
1038
1039 /***********************************************************************
1040  *     CBClientThunkSLEx                    (KERNEL.621)
1041  */
1042 extern DWORD CALL32_CBClientEx( FARPROC proc, LPWORD args, DWORD *esi, INT *nArgs );
1043 void WINAPI CBClientThunkSLEx( CONTEXT86 *context )
1044 {
1045     /* Call 32-bit relay code */
1046
1047     LPWORD args = PTR_SEG_OFF_TO_LIN( SS_reg( context ), BP_reg( context ) );
1048     FARPROC proc = CBClientRelay32[ args[2] ][ args[1] ];
1049     INT nArgs;
1050     LPWORD stackLin;
1051
1052     EAX_reg(context) = CALL32_CBClientEx( proc, args, &ESI_reg( context ), &nArgs );
1053
1054     /* Restore registers saved by CBClientGlueSL */
1055     stackLin = (LPWORD)((LPBYTE)CURRENT_STACK16 + sizeof(STACK16FRAME) - 4);
1056     BP_reg( context ) = stackLin[3];
1057     SI_reg( context ) = stackLin[2];
1058     DI_reg( context ) = stackLin[1];
1059     DS_reg( context ) = stackLin[0];
1060     ESP_reg( context ) += 16+nArgs;
1061
1062     /* Return to caller of CBClient thunklet */
1063     CS_reg ( context ) = stackLin[9];
1064     EIP_reg( context ) = stackLin[8];
1065 }
1066