Fix GetTempPath32 if count=0.
[wine] / if1632 / thunk.c
1 /*
2  * Emulator thunks
3  *
4  * Copyright 1996, 1997 Alexandre Julliard
5  * Copyright 1998       Ulrich Weigand
6  */
7
8 #include "windows.h"
9 #include "callback.h"
10 #include "resource.h"
11 #include "task.h"
12 #include "user.h"
13 #include "heap.h"
14 #include "hook.h"
15 #include "module.h"
16 #include "process.h"
17 #include "stackframe.h"
18 #include "selectors.h"
19 #include "task.h"
20 #include "except.h"
21 #include "win.h"
22 #include "flatthunk.h"
23 #include "mouse.h"
24 #include "keyboard.h"
25 #include "debug.h"
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 LONG CALLBACK CallTo16_sreg_(const CONTEXT *context, INT32 offset);
33 extern LONG CALLBACK CallTo16_lreg_(const CONTEXT *context, INT32 offset);
34 extern WORD CALLBACK CallTo16_word_     (FARPROC16);
35 extern LONG CALLBACK CallTo16_long_     (FARPROC16);
36 extern WORD CALLBACK CallTo16_word_w    (FARPROC16,WORD);
37 extern LONG CALLBACK CallTo16_long_l    (FARPROC16,LONG);
38 extern WORD CALLBACK CallTo16_word_ww   (FARPROC16,WORD,WORD);
39 extern WORD CALLBACK CallTo16_word_wl   (FARPROC16,WORD,LONG);
40 extern WORD CALLBACK CallTo16_word_ll   (FARPROC16,LONG,LONG);
41 extern LONG CALLBACK CallTo16_long_ll   (FARPROC16,LONG,LONG);
42 extern WORD CALLBACK CallTo16_word_www  (FARPROC16,WORD,WORD,WORD);
43 extern WORD CALLBACK CallTo16_word_wwl  (FARPROC16,WORD,WORD,LONG);
44 extern WORD CALLBACK CallTo16_word_wlw  (FARPROC16,WORD,LONG,WORD);
45 extern LONG CALLBACK CallTo16_long_wwl  (FARPROC16,WORD,WORD,LONG);
46 extern LONG CALLBACK CallTo16_long_lll  (FARPROC16,LONG,LONG,LONG);
47 extern WORD CALLBACK CallTo16_word_llwl (FARPROC16,LONG,LONG,WORD,LONG);
48 extern WORD CALLBACK CallTo16_word_lwll (FARPROC16,LONG,WORD,LONG,LONG);
49 extern WORD CALLBACK CallTo16_word_lwww (FARPROC16,LONG,WORD,WORD,WORD);
50 extern WORD CALLBACK CallTo16_word_wwll (FARPROC16,WORD,WORD,LONG,LONG);
51 extern WORD CALLBACK CallTo16_word_wwwl (FARPROC16,WORD,WORD,WORD,LONG);
52 extern WORD CALLBACK CallTo16_word_llll (FARPROC16,LONG,LONG,LONG,LONG);
53 extern LONG CALLBACK CallTo16_long_llll (FARPROC16,LONG,LONG,LONG,LONG);
54 extern WORD CALLBACK CallTo16_word_wllwl(FARPROC16,WORD,LONG,LONG,WORD,LONG);
55 extern LONG CALLBACK CallTo16_long_lwwll(FARPROC16,LONG,WORD,WORD,LONG,LONG);
56 extern WORD CALLBACK CallTo16_word_wwlll(FARPROC16,WORD,WORD,LONG,LONG,LONG);
57 extern WORD CALLBACK CallTo16_word_wwwww(FARPROC16,WORD,WORD,WORD,WORD,WORD);
58 extern WORD CALLBACK CallTo16_word_lwlll(FARPROC16,LONG,WORD,LONG,LONG,LONG);
59 extern LONG CALLBACK CallTo16_long_lwlll(FARPROC16,LONG,WORD,LONG,LONG,LONG);
60 extern LONG CALLBACK CallTo16_long_lllll(FARPROC16,LONG,LONG,LONG,LONG,LONG);
61 extern LONG CALLBACK CallTo16_long_llllll(FARPROC16,LONG,LONG,LONG,LONG,LONG,
62                                           LONG);
63 extern LONG CALLBACK CallTo16_long_lllllll(FARPROC16,LONG,LONG,LONG,LONG,LONG,
64                                            LONG,LONG);
65 extern WORD CALLBACK CallTo16_word_llwwlll(FARPROC16,LONG,LONG,WORD,WORD,LONG,
66                                            LONG,LONG);
67 extern LONG CALLBACK CallTo16_word_lwwlllll(FARPROC16,LONG,WORD,WORD,LONG,LONG,
68                                             LONG,LONG,LONG);
69 extern LONG CALLBACK CallTo16_long_llllllll(FARPROC16,LONG,LONG,LONG,LONG,LONG,
70                                             LONG,LONG,LONG);
71 extern LONG CALLBACK CallTo16_long_lllllllll(FARPROC16,LONG,LONG,LONG,LONG,
72                                              LONG,LONG,LONG,LONG,LONG);
73 extern LONG CALLBACK CallTo16_long_llllllllll(FARPROC16,LONG,LONG,LONG,LONG,
74                                               LONG,LONG,LONG,LONG,LONG,LONG);
75 extern LONG CALLBACK CallTo16_long_lllllllllll(FARPROC16,LONG,LONG,LONG,LONG,
76                                                LONG,LONG,LONG,LONG,LONG,LONG,
77                                                LONG);
78 extern LONG CALLBACK CallTo16_long_llllllllllll(FARPROC16,LONG,LONG,LONG,LONG,
79                                                 LONG,LONG,LONG,LONG,LONG,LONG,
80                                                 LONG,LONG);
81 extern LONG CALLBACK CallTo16_long_lwwllwlllllw(FARPROC16,LONG,WORD,WORD,LONG,
82                                                 LONG,WORD,LONG,LONG,LONG,LONG,
83                                                 LONG,WORD);
84 extern LONG CALLBACK CallTo16_long_lllllllllllll(FARPROC16,LONG,LONG,LONG,LONG,
85                                                  LONG,LONG,LONG,LONG,LONG,LONG,
86                                                  LONG,LONG,LONG);
87 extern LONG CALLBACK CallTo16_long_llllllllllllll(FARPROC16,LONG,LONG,LONG,
88                                                   LONG,LONG,LONG,LONG,LONG,
89                                                   LONG,LONG,LONG,LONG,LONG,
90                                                   LONG);
91 extern LONG CALLBACK CallTo16_word_lwwwwlwwwwllll(FARPROC16,LONG,WORD,WORD,
92                                                   WORD,WORD,LONG,WORD,WORD,
93                                                   WORD,WORD,LONG,LONG,LONG,
94                                                   LONG);
95 extern LONG CALLBACK CallTo16_long_lllllllllllllll(FARPROC16,LONG,LONG,LONG,
96                                                    LONG,LONG,LONG,LONG,LONG,
97                                                    LONG,LONG,LONG,LONG,LONG,
98                                                    LONG,LONG);
99 extern LONG CALLBACK CallTo16_long_llllllllllllllll(FARPROC16,LONG,LONG,LONG,
100                                                     LONG,LONG,LONG,LONG,LONG,
101                                                     LONG,LONG,LONG,LONG,LONG,
102                                                     LONG,LONG,LONG);
103 /* ### stop build ### */
104
105
106 typedef void (*RELAY)();
107
108 #pragma pack(1)
109
110 typedef struct tagTHUNK
111 {
112     BYTE             popl_eax;           /* 0x58  popl  %eax (return address)*/
113     BYTE             pushl_func;         /* 0x68  pushl $proc */
114     FARPROC32        proc WINE_PACKED;
115     BYTE             pushl_eax;          /* 0x50  pushl %eax */
116     BYTE             jmp;                /* 0xe9  jmp   relay (relative jump)*/
117     RELAY            relay WINE_PACKED;
118     struct tagTHUNK *next WINE_PACKED;
119 } THUNK;
120
121 #pragma pack(4)
122
123 #define DECL_THUNK(name,proc,relay) \
124     THUNK name = { 0x58, 0x68, (FARPROC32)(proc), 0x50, 0xe9, \
125                    (RELAY)((char *)(relay) - (char *)(&(name).next)), NULL }
126
127
128 static THUNK *firstThunk = NULL;
129
130 static LRESULT WINAPI THUNK_CallWndProc16( WNDPROC16 proc, HWND16 hwnd,
131                                            UINT16 msg, WPARAM16 wParam,
132                                            LPARAM lParam );
133 static void WINAPI THUNK_CallTaskReschedule(void);
134 static BOOL32 WINAPI THUNK_WOWCallback16Ex( FARPROC16,DWORD,DWORD,
135                                             LPVOID,LPDWORD );
136
137 /* TASK_Reschedule() 16-bit entry point */
138 static FARPROC16 TASK_RescheduleProc;
139
140 static BOOL32 THUNK_ThunkletInit( void );
141
142 extern void CallFrom16_p_long_wwwll(void);
143
144 /* Callbacks function table for the emulator */
145 static const CALLBACKS_TABLE CALLBACK_EmulatorTable =
146 {
147     (void *)CallTo16_sreg_,                /* CallRegisterShortProc */
148     (void *)CallTo16_lreg_,                /* CallRegisterLongProc */
149     THUNK_CallTaskReschedule,              /* CallTaskRescheduleProc */
150     CallFrom16_p_long_wwwll,               /* CallFrom16WndProc */
151     THUNK_CallWndProc16,                   /* CallWndProc */
152     (void *)CallTo16_long_lwwll,           /* CallDriverProc */
153     (void *)CallTo16_word_wwlll,           /* CallDriverCallback */
154     (void *)CallTo16_word_wwlll,           /* CallTimeFuncProc */
155     (void *)CallTo16_word_w,               /* CallWindowsExitProc */
156     (void *)CallTo16_word_lwww,            /* CallWordBreakProc */
157     (void *)CallTo16_word_ww,              /* CallBootAppProc */
158     (void *)CallTo16_word_www,             /* CallLoadAppSegProc */
159     (void *)CallTo16_word_www,             /* CallLocalNotifyFunc */
160     (void *)CallTo16_word_www,             /* CallResourceHandlerProc */
161     (void *)CallTo16_word_wwwl,            /* CallPostAppMessageProc */
162     (void *)CallTo16_long_l,               /* CallWOWCallbackProc */
163     THUNK_WOWCallback16Ex,                 /* CallWOWCallback16Ex */
164     (void *)CallTo16_long_l,               /* CallASPIPostProc */
165     (void *)CallTo16_word_lwll,            /* CallDrvControlProc */
166     (void *)CallTo16_word_lwlll,           /* CallDrvEnableProc */
167     (void *)CallTo16_word_llll,            /* CallDrvEnumDFontsProc */
168     (void *)CallTo16_word_lwll,            /* CallDrvEnumObjProc */
169     (void *)CallTo16_word_lwwlllll,        /* CallDrvOutputProc */
170     (void *)CallTo16_long_lwlll,           /* CallDrvRealizeProc */
171     (void *)CallTo16_word_lwwwwlwwwwllll,  /* CallDrvStretchBltProc */
172     (void *)CallTo16_long_lwwllwlllllw,    /* CallDrvExtTextOutProc */
173     (void *)CallTo16_word_llwwlll,         /* CallDrvGetCharWidth */ 
174     (void *)CallTo16_word_ww               /* CallDrvAbortProc */
175 };
176
177
178 /***********************************************************************
179  *           THUNK_Init
180  */
181 BOOL32 THUNK_Init(void)
182 {
183     /* Set the window proc calling functions */
184     Callbacks = &CALLBACK_EmulatorTable;
185     /* Get the 16-bit reschedule function pointer */
186     TASK_RescheduleProc = MODULE_GetWndProcEntry16( "TASK_Reschedule" );
187     /* Initialize Thunklets */
188     return THUNK_ThunkletInit();
189 }
190
191 /***********************************************************************
192  *           THUNK_Alloc
193  */
194 static THUNK *THUNK_Alloc( FARPROC32 func, RELAY relay )
195 {
196     THUNK *thunk = HeapAlloc( GetProcessHeap(), 0, sizeof(*thunk) );
197     if (thunk)
198     {
199         thunk->popl_eax   = 0x58;
200         thunk->pushl_func = 0x68;
201         thunk->proc       = func;
202         thunk->pushl_eax  = 0x50;
203         thunk->jmp        = 0xe9;
204         thunk->relay      = (RELAY)((char *)relay - (char *)(&thunk->next));
205         thunk->next       = firstThunk;
206         firstThunk = thunk;
207     }
208     return thunk;
209 }
210
211
212 /***********************************************************************
213  *           THUNK_Find
214  */
215 static THUNK *THUNK_Find( FARPROC32 func )
216 {
217     THUNK *thunk = firstThunk;
218     while (thunk && (thunk->proc != func)) thunk = thunk->next;
219     return thunk;
220 }
221
222
223 /***********************************************************************
224  *           THUNK_Free
225  */
226 static void THUNK_Free( THUNK *thunk )
227 {
228     if (HEAP_IsInsideHeap( GetProcessHeap(), 0, thunk ))
229     {
230         THUNK **prev = &firstThunk;
231         while (*prev && (*prev != thunk)) prev = &(*prev)->next;
232         if (*prev)
233         {
234             *prev = thunk->next;
235             HeapFree( GetProcessHeap(), 0, thunk );
236             return;
237         }
238     }
239     ERR(thunk, "invalid thunk addr %p\n", thunk );
240 }
241
242
243 /***********************************************************************
244  *           THUNK_CallWndProc16
245  *
246  * Call a 16-bit window procedure
247  */
248 static LRESULT WINAPI THUNK_CallWndProc16( WNDPROC16 proc, HWND16 hwnd,
249                                            UINT16 msg, WPARAM16 wParam,
250                                            LPARAM lParam )
251 {
252     CONTEXT context;
253     LRESULT ret;
254     WORD *args;
255     WND *wndPtr = WIN_FindWndPtr( hwnd );
256     DWORD offset = 0;
257     THDB *thdb = THREAD_Current();
258
259     /* Window procedures want ax = hInstance, ds = es = ss */
260     
261     memset(&context, '\0', sizeof(context));
262     DS_reg(&context)  = SELECTOROF(thdb->cur_stack);
263     ES_reg(&context)  = DS_reg(&context);
264     EAX_reg(&context) = wndPtr ? wndPtr->hInstance : DS_reg(&context);
265     CS_reg(&context)  = SELECTOROF(proc);
266     EIP_reg(&context) = OFFSETOF(proc);
267     EBP_reg(&context) = OFFSETOF(thdb->cur_stack)
268                         + (WORD)&((STACK16FRAME*)0)->bp;
269
270     if (lParam)
271     {
272         /* Some programs (eg. the "Undocumented Windows" examples, JWP) only
273            work if structures passed in lParam are placed in the stack/data
274            segment. Programmers easily make the mistake of converting lParam
275            to a near rather than a far pointer, since Windows apparently
276            allows this. We copy the structures to the 16 bit stack; this is
277            ugly but makes these programs work. */
278         switch (msg)
279         {
280           case WM_CREATE:
281           case WM_NCCREATE:
282             offset = sizeof(CREATESTRUCT16); break;
283           case WM_DRAWITEM:
284             offset = sizeof(DRAWITEMSTRUCT16); break;
285           case WM_COMPAREITEM:
286             offset = sizeof(COMPAREITEMSTRUCT16); break;
287         }
288         if (offset)
289         {
290             void *s = PTR_SEG_TO_LIN(lParam);
291             lParam = STACK16_PUSH( thdb, offset );
292             memcpy( PTR_SEG_TO_LIN(lParam), s, offset );
293         }
294     }
295
296     args = (WORD *)THREAD_STACK16(thdb) - 5;
297     args[0] = LOWORD(lParam);
298     args[1] = HIWORD(lParam);
299     args[2] = wParam;
300     args[3] = msg;
301     args[4] = hwnd;
302
303     ret = CallTo16_sreg_( &context, 5 * sizeof(WORD) );
304     if (offset) STACK16_POP( thdb, offset );
305     return ret;
306 }
307
308
309 /***********************************************************************
310  *           THUNK_CallTaskReschedule
311  */
312 static void WINAPI THUNK_CallTaskReschedule(void)
313 {
314     CallTo16_word_(TASK_RescheduleProc);
315 }
316
317
318 /***********************************************************************
319  *           THUNK_EnumObjects16   (GDI.71)
320  */
321 INT16 WINAPI THUNK_EnumObjects16( HDC16 hdc, INT16 nObjType,
322                                   GOBJENUMPROC16 func, LPARAM lParam )
323 {
324     DECL_THUNK( thunk, func, CallTo16_word_ll );
325     return EnumObjects16( hdc, nObjType, (GOBJENUMPROC16)&thunk, lParam );
326 }
327
328
329 /*************************************************************************
330  *           THUNK_EnumFonts16   (GDI.70)
331  */
332 INT16 WINAPI THUNK_EnumFonts16( HDC16 hdc, LPCSTR lpFaceName,
333                                 FONTENUMPROC16 func, LPARAM lParam )
334 {
335     DECL_THUNK( thunk, func, CallTo16_word_llwl );
336     return EnumFonts16( hdc, lpFaceName, (FONTENUMPROC16)&thunk, lParam );
337 }
338
339 /******************************************************************
340  *           THUNK_EnumMetaFile16   (GDI.175)
341  */
342 BOOL16 WINAPI THUNK_EnumMetaFile16( HDC16 hdc, HMETAFILE16 hmf,
343                                     MFENUMPROC16 func, LPARAM lParam )
344 {
345     DECL_THUNK( thunk, func, CallTo16_word_wllwl );
346     return EnumMetaFile16( hdc, hmf, (MFENUMPROC16)&thunk, lParam );
347 }
348
349
350 /*************************************************************************
351  *           THUNK_EnumFontFamilies16   (GDI.330)
352  */
353 INT16 WINAPI THUNK_EnumFontFamilies16( HDC16 hdc, LPCSTR lpszFamily,
354                                        FONTENUMPROC16 func, LPARAM lParam )
355 {
356     DECL_THUNK( thunk, func, CallTo16_word_llwl );
357     return EnumFontFamilies16(hdc, lpszFamily, (FONTENUMPROC16)&thunk, lParam);
358 }
359
360
361 /*************************************************************************
362  *           THUNK_EnumFontFamiliesEx16   (GDI.613)
363  */
364 INT16 WINAPI THUNK_EnumFontFamiliesEx16( HDC16 hdc, LPLOGFONT16 lpLF,
365                                          FONTENUMPROCEX16 func, LPARAM lParam,
366                                          DWORD reserved )
367 {
368     DECL_THUNK( thunk, func, CallTo16_word_llwl );
369     return EnumFontFamiliesEx16( hdc, lpLF, (FONTENUMPROCEX16)&thunk,
370                                  lParam, reserved );
371 }
372
373
374 /**********************************************************************
375  *           THUNK_LineDDA16   (GDI.100)
376  */
377 void WINAPI THUNK_LineDDA16( INT16 nXStart, INT16 nYStart, INT16 nXEnd,
378                              INT16 nYEnd, LINEDDAPROC16 func, LPARAM lParam )
379 {
380     DECL_THUNK( thunk, func, CallTo16_word_wwl );
381     LineDDA16( nXStart, nYStart, nXEnd, nYEnd, (LINEDDAPROC16)&thunk, lParam );
382 }
383
384
385 /*******************************************************************
386  *           THUNK_EnumWindows16   (USER.54)
387  */
388 BOOL16 WINAPI THUNK_EnumWindows16( WNDENUMPROC16 func, LPARAM lParam )
389 {
390     DECL_THUNK( thunk, func, CallTo16_word_wl );
391     return EnumWindows16( (WNDENUMPROC16)&thunk, lParam );
392 }
393
394
395 /**********************************************************************
396  *           THUNK_EnumChildWindows16   (USER.55)
397  */
398 BOOL16 WINAPI THUNK_EnumChildWindows16( HWND16 parent, WNDENUMPROC16 func,
399                                         LPARAM lParam )
400 {
401     DECL_THUNK( thunk, func, CallTo16_word_wl );
402     return EnumChildWindows16( parent, (WNDENUMPROC16)&thunk, lParam );
403 }
404
405
406 /**********************************************************************
407  *           THUNK_EnumTaskWindows16   (USER.225)
408  */
409 BOOL16 WINAPI THUNK_EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
410                                        LPARAM lParam )
411 {
412     DECL_THUNK( thunk, func, CallTo16_word_wl );
413     return EnumTaskWindows16( hTask, (WNDENUMPROC16)&thunk, lParam );
414 }
415
416
417 /***********************************************************************
418  *           THUNK_EnumProps16   (USER.27)
419  */
420 INT16 WINAPI THUNK_EnumProps16( HWND16 hwnd, PROPENUMPROC16 func )
421 {
422     DECL_THUNK( thunk, func, CallTo16_word_wlw );
423     return EnumProps16( hwnd, (PROPENUMPROC16)&thunk );
424 }
425
426
427 /***********************************************************************
428  *           THUNK_GrayString16   (USER.185)
429  */
430 BOOL16 WINAPI THUNK_GrayString16( HDC16 hdc, HBRUSH16 hbr,
431                                   GRAYSTRINGPROC16 func, LPARAM lParam,
432                                   INT16 cch, INT16 x, INT16 y,
433                                   INT16 cx, INT16 cy )
434 {
435     DECL_THUNK( thunk, func, CallTo16_word_wlw );
436     if (!func)
437         return GrayString16( hdc, hbr, NULL, lParam, cch, x, y, cx, cy );
438     else
439         return GrayString16( hdc, hbr, (GRAYSTRINGPROC16)&thunk, lParam, cch,
440                              x, y, cx, cy );
441 }
442
443
444 /***********************************************************************
445  *           THUNK_SetWindowsHook16   (USER.121)
446  */
447 FARPROC16 WINAPI THUNK_SetWindowsHook16( INT16 id, HOOKPROC16 proc )
448 {
449     HINSTANCE16 hInst = FarGetOwner( HIWORD(proc) );
450     HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
451     THUNK *thunk = THUNK_Alloc( (FARPROC16)proc, (RELAY)CallTo16_long_wwl );
452     if (!thunk) return 0;
453     return (FARPROC16)SetWindowsHookEx16( id, (HOOKPROC16)thunk, hInst, hTask);
454 }
455
456
457 /***********************************************************************
458  *           THUNK_UnhookWindowsHook16   (USER.234)
459  */
460 BOOL16 WINAPI THUNK_UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
461 {
462     BOOL16 ret;
463     THUNK *thunk = THUNK_Find( (FARPROC16)proc );
464     if (!thunk) return FALSE;
465     ret = UnhookWindowsHook16( id, (HOOKPROC16)thunk );
466     THUNK_Free( thunk );
467     return ret;
468 }
469
470
471 /***********************************************************************
472  *           THUNK_SetWindowsHookEx16   (USER.291)
473  */
474 HHOOK WINAPI THUNK_SetWindowsHookEx16( INT16 id, HOOKPROC16 proc,
475                                        HINSTANCE16 hInst, HTASK16 hTask )
476 {
477     THUNK *thunk = THUNK_Alloc( (FARPROC16)proc, (RELAY)CallTo16_long_wwl );
478     if (!thunk) return 0;
479     return SetWindowsHookEx16( id, (HOOKPROC16)thunk, hInst, hTask );
480 }
481
482
483 /***********************************************************************
484  *           THUNK_UnhookWindowHookEx16   (USER.292)
485  */
486 BOOL16 WINAPI THUNK_UnhookWindowsHookEx16( HHOOK hhook )
487 {
488     THUNK *thunk = (THUNK *)HOOK_GetProc16( hhook );
489     BOOL16 ret = UnhookWindowsHookEx16( hhook );
490     if (thunk) THUNK_Free( thunk );
491     return ret;
492 }
493
494
495
496 static FARPROC16 defDCHookProc = NULL;
497
498 /***********************************************************************
499  *           THUNK_SetDCHook   (GDI.190)
500  */
501 BOOL16 WINAPI THUNK_SetDCHook( HDC16 hdc, FARPROC16 proc, DWORD dwHookData )
502 {
503     THUNK *thunk, *oldThunk;
504
505     if (!defDCHookProc)  /* Get DCHook Win16 entry point */
506         defDCHookProc = NE_GetEntryPoint( GetModuleHandle16("USER"), 362 );
507
508     if (proc != defDCHookProc)
509     {
510         thunk = THUNK_Alloc( proc, (RELAY)CallTo16_word_wwll );
511         if (!thunk) return FALSE;
512     }
513     else thunk = (THUNK *)DCHook;
514
515     /* Free the previous thunk */
516     GetDCHook( hdc, (FARPROC16 *)&oldThunk );
517     if (oldThunk && (oldThunk != (THUNK *)DCHook)) THUNK_Free( oldThunk );
518
519     return SetDCHook( hdc, (FARPROC16)thunk, dwHookData );
520 }
521
522
523 /***********************************************************************
524  *           THUNK_GetDCHook   (GDI.191)
525  */
526 DWORD WINAPI THUNK_GetDCHook( HDC16 hdc, FARPROC16 *phookProc )
527 {
528     THUNK *thunk = NULL;
529     DWORD ret = GetDCHook( hdc, (FARPROC16 *)&thunk );
530     if (thunk)
531     {
532         if (thunk == (THUNK *)DCHook)
533         {
534             if (!defDCHookProc)  /* Get DCHook Win16 entry point */
535                 defDCHookProc = NE_GetEntryPoint(GetModuleHandle16("USER"),362);
536             *phookProc = defDCHookProc;
537         }
538         else *phookProc = thunk->proc;
539     }
540     return ret;
541 }
542
543
544 /***********************************************************************
545  *           THUNK_SetTaskSignalProc (KERNEL.38)
546  */
547 FARPROC16 WINAPI THUNK_SetTaskSignalProc( HTASK16 hTask, FARPROC16 proc )
548 {
549     static FARPROC16 defSignalProc16 = NULL;
550
551     THUNK *thunk = NULL;
552
553     if( !defSignalProc16 )
554         defSignalProc16 = NE_GetEntryPoint(GetModuleHandle16("USER"), 314 );
555
556     if( proc == defSignalProc16 )
557         thunk = (THUNK*)SetTaskSignalProc( hTask, (FARPROC16)&USER_SignalProc );
558     else 
559     {
560         thunk = THUNK_Alloc( proc, (RELAY)CallTo16_word_wwwww );
561         if( !thunk ) return FALSE;
562         thunk = (THUNK*)SetTaskSignalProc( hTask, (FARPROC16)thunk );
563     }
564
565     if( thunk != (THUNK*)USER_SignalProc )
566     {
567         if( !thunk ) return NULL;
568
569         proc = thunk->proc;
570         THUNK_Free( thunk );
571         return proc;
572     }
573     return defSignalProc16;
574 }
575
576 /***********************************************************************
577  *           THUNK_CreateThread16   (KERNEL.441)
578  */
579 static DWORD CALLBACK THUNK_StartThread16( LPVOID threadArgs )
580 {
581     FARPROC16 start = ((FARPROC16 *)threadArgs)[0];
582     DWORD     param = ((DWORD *)threadArgs)[1];
583     HeapFree( GetProcessHeap(), 0, threadArgs );
584
585     return CallTo16_long_l( start, param );
586 }
587 HANDLE32 WINAPI THUNK_CreateThread16( SECURITY_ATTRIBUTES *sa, DWORD stack,
588                                       FARPROC16 start, SEGPTR param,
589                                       DWORD flags, LPDWORD id )
590 {
591     DWORD *threadArgs = HeapAlloc( GetProcessHeap(), 0, 2*sizeof(DWORD) );
592     if (!threadArgs) return INVALID_HANDLE_VALUE32;
593     threadArgs[0] = (DWORD)start;
594     threadArgs[1] = (DWORD)param;
595
596     return CreateThread( sa, stack, THUNK_StartThread16, threadArgs, flags, id );
597 }
598
599 /***********************************************************************
600  *           THUNK_WOWCallback16Ex      (WOW32.3)(KERNEL32.55)
601  * Generic thunking routine to call 16 bit functions from 32bit code.
602  * 
603  * RETURNS
604  *      TRUE if the call was done
605  */
606 static BOOL32 WINAPI THUNK_WOWCallback16Ex(
607         FARPROC16 proc,         /* [in] 16bit function to call */
608         DWORD dwFlags,          /* [in] flags (WCB_*) */
609         DWORD cbArgs,           /* [in] number of arguments */
610         LPVOID xargs,           /* [in/out] arguments */
611         LPDWORD pdwret          /* [out] return value of the 16bit call */
612 ) {
613     LPDWORD     args = (LPDWORD)xargs;
614     DWORD       ret,i;
615
616     TRACE(relay,"(%p,0x%08lx,%ld,%p,%p)\n",
617         proc,dwFlags,cbArgs,xargs,pdwret
618     );
619     if (dwFlags == WCB16_CDECL) {
620         /* swap the arguments */
621         args = HeapAlloc(GetProcessHeap(),0,cbArgs*sizeof(DWORD));
622         for (i=0;i<cbArgs;i++)
623             args[i] = ((DWORD*)xargs)[cbArgs-i-1];
624     }
625     switch (cbArgs) {
626     case 0: ret = CallTo16_long_(proc);break;
627     case 1: ret = CallTo16_long_l(proc,args[0]);break;
628     case 2: ret = CallTo16_long_ll(proc,args[0],args[1]);break;
629     case 3: ret = CallTo16_long_lll(proc,args[0],args[1],args[2]);break;
630     case 4: ret = CallTo16_long_llll(proc,args[0],args[1],args[2],args[3]);
631             break;
632     case 5: ret = CallTo16_long_lllll(proc,args[0],args[1],args[2],args[3],
633                 args[4]
634             );
635             break;
636     case 6: ret = CallTo16_long_llllll(proc,args[0],args[1],args[2],args[3],
637                 args[4],args[5]
638             );
639             break;
640     case 7: ret = CallTo16_long_lllllll(proc,args[0],args[1],args[2],args[3],
641                 args[4],args[5],args[6]
642             );
643             break;
644     case 8: ret = CallTo16_long_llllllll(proc,args[0],args[1],args[2],args[3],
645                 args[4],args[5],args[6],args[7]
646             );
647             break;
648     case 9: ret = CallTo16_long_lllllllll(proc,args[0],args[1],args[2],args[3],
649                 args[4],args[5],args[6],args[7],args[8]
650             );
651             break;
652     case 10:ret = CallTo16_long_llllllllll(proc,args[0],args[1],args[2],args[3],
653                 args[4],args[5],args[6],args[7],args[8],args[9]
654             );
655             break;
656     case 11:ret = CallTo16_long_lllllllllll(proc,args[0],args[1],args[2],
657                 args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]
658             );
659             break;
660     case 12:ret = CallTo16_long_llllllllllll(proc,args[0],args[1],args[2],
661                 args[3],args[4],args[5],args[6],args[7],args[8],args[9],
662                 args[10],args[11]
663             );
664             break;
665     case 13:ret = CallTo16_long_lllllllllllll(proc,args[0],args[1],args[2],
666                 args[3],args[4],args[5],args[6],args[7],args[8],args[9],
667                 args[10],args[11],args[12]
668             );
669             break;
670     case 14:ret = CallTo16_long_llllllllllllll(proc,args[0],args[1],args[2],
671                 args[3],args[4],args[5],args[6],args[7],args[8],args[9],
672                 args[10],args[11],args[12],args[13]
673             );
674             break;
675     case 15:ret = CallTo16_long_lllllllllllllll(proc,args[0],args[1],args[2],
676                 args[3],args[4],args[5],args[6],args[7],args[8],args[9],
677                 args[10],args[11],args[12],args[13],args[14]
678             );
679             break;
680     case 16:ret = CallTo16_long_llllllllllllllll(proc,args[0],args[1],args[2],
681                 args[3],args[4],args[5],args[6],args[7],args[8],args[9],
682                 args[10],args[11],args[12],args[13],args[14],args[15]
683             );
684             break;
685     default:
686             ERR(thunk,"%ld arguments not supported.\n",cbArgs);
687             if (dwFlags == WCB16_CDECL)
688                 HeapFree(GetProcessHeap(),0,args);
689             return FALSE;
690     }
691     if (dwFlags == WCB16_CDECL)
692         HeapFree(GetProcessHeap(),0,args);
693     if (pdwret) 
694         *pdwret = ret;
695     return TRUE;
696 }
697
698 /***********************************************************************
699  *           THUNK_MOUSE_Enable   (MOUSE.2)
700  */
701 static VOID WINAPI THUNK_CallMouseEventProc( FARPROC16 proc, 
702                                              DWORD dwFlags, DWORD dx, DWORD dy,
703                                              DWORD cButtons, DWORD dwExtraInfo )
704 {
705     CONTEXT context;
706
707     memset( &context, 0, sizeof(context) );
708     CS_reg(&context)  = SELECTOROF( proc );
709     EIP_reg(&context) = OFFSETOF( proc );
710     AX_reg(&context)  = (WORD)dwFlags;
711     BX_reg(&context)  = (WORD)dx;
712     CX_reg(&context)  = (WORD)dy;
713     DX_reg(&context)  = (WORD)cButtons;
714     SI_reg(&context)  = LOWORD( dwExtraInfo );
715     DI_reg(&context)  = HIWORD( dwExtraInfo );
716
717     CallTo16_sreg_( &context, 0 );
718 }
719 VOID WINAPI THUNK_MOUSE_Enable( FARPROC16 proc )
720 {
721     static THUNK *lastThunk = NULL;
722     static FARPROC16 lastProc = NULL;
723
724     if ( lastProc != proc )
725     {
726         if ( lastThunk ) 
727             THUNK_Free( lastThunk );
728
729         if ( !proc )
730             lastThunk = NULL;
731         else
732             lastThunk = THUNK_Alloc( proc, (RELAY)THUNK_CallMouseEventProc );
733
734         lastProc = proc;
735     }
736
737     return MOUSE_Enable( (LPMOUSE_EVENT_PROC)lastThunk );
738 }
739
740 /***********************************************************************
741  *           GetMouseEventProc   (USER.337)
742  */
743 FARPROC16 WINAPI GetMouseEventProc(void)
744 {
745     HMODULE16 hmodule = GetModuleHandle16("USER");
746     return NE_GetEntryPoint( hmodule, NE_GetOrdinal( hmodule, "mouse_event" ));
747 }
748
749
750 /***********************************************************************
751  *           WIN16_mouse_event   (USER.299)
752  */
753 void WINAPI WIN16_mouse_event( CONTEXT *context )
754 {
755     mouse_event( AX_reg(context), BX_reg(context), CX_reg(context),
756                  DX_reg(context), MAKELONG(SI_reg(context), DI_reg(context)) );
757 }
758
759
760 /***********************************************************************
761  *           THUNK_KEYBD_Enable   (KEYBOARD.2)
762  */
763 static VOID WINAPI THUNK_CallKeybdEventProc( FARPROC16 proc, 
764                                              BYTE bVk, BYTE bScan,
765                                              DWORD dwFlags, DWORD dwExtraInfo )
766 {
767     CONTEXT context;
768
769     memset( &context, 0, sizeof(context) );
770     CS_reg(&context)  = SELECTOROF( proc );
771     EIP_reg(&context) = OFFSETOF( proc );
772     AH_reg(&context)  = (dwFlags & KEYEVENTF_KEYUP)? 0x80 : 0;
773     AL_reg(&context)  = bVk;
774     BH_reg(&context)  = (dwFlags & KEYEVENTF_EXTENDEDKEY)? 1 : 0;
775     BL_reg(&context)  = bScan;
776     SI_reg(&context)  = LOWORD( dwExtraInfo );
777     DI_reg(&context)  = HIWORD( dwExtraInfo );
778
779     CallTo16_sreg_( &context, 0 );
780 }
781 VOID WINAPI THUNK_KEYBOARD_Enable( FARPROC16 proc, LPBYTE lpKeyState )
782 {
783     static THUNK *lastThunk = NULL;
784     static FARPROC16 lastProc = NULL;
785
786     if ( lastProc != proc )
787     {
788         if ( lastThunk ) 
789             THUNK_Free( lastThunk );
790
791         if ( !proc )
792             lastThunk = NULL;
793         else
794             lastThunk = THUNK_Alloc( proc, (RELAY)THUNK_CallKeybdEventProc );
795
796         lastProc = proc;
797     }
798
799     return KEYBOARD_Enable( (LPKEYBD_EVENT_PROC)lastThunk, lpKeyState );
800 }
801
802 /***********************************************************************
803  *           WIN16_keybd_event   (USER.289)
804  */
805 void WINAPI WIN16_keybd_event( CONTEXT *context )
806 {
807     DWORD dwFlags = 0;
808     
809     if (AH_reg(context) & 0x80) dwFlags |= KEYEVENTF_KEYUP;
810     if (BH_reg(context) & 1   ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
811
812     keybd_event( AL_reg(context), BL_reg(context), 
813                  dwFlags, MAKELONG(SI_reg(context), DI_reg(context)) );
814 }
815
816
817 /***********************************************************************
818  *           WIN16_CreateSystemTimer   (SYSTEM.2)
819  */
820 static void CALLBACK THUNK_CallSystemTimerProc( FARPROC16 proc, WORD timer )
821 {
822     CONTEXT context;
823     memset( &context, '\0', sizeof(context) );
824
825     CS_reg( &context ) = SELECTOROF( proc );
826     IP_reg( &context ) = OFFSETOF( proc );
827     BP_reg( &context ) = OFFSETOF( THREAD_Current()->cur_stack )
828                          + (WORD)&((STACK16FRAME*)0)->bp;
829
830     AX_reg( &context ) = timer;
831
832     CallTo16_sreg_( &context, 0 ); 
833
834     /* FIXME: This does not work if the signal occurs while some thread
835               is currently in 16-bit code. With the current structure
836               of the Wine thunking code, this seems to be hard to fix ... */
837 }
838 WORD WINAPI WIN16_CreateSystemTimer( WORD rate, FARPROC16 proc )
839 {
840     THUNK *thunk = THUNK_Alloc( proc, (RELAY)THUNK_CallSystemTimerProc );
841     WORD timer = 0;
842
843 #if 1
844     FIXME(system,"are currently broken, returning 0.\n");
845 #else
846     timer = CreateSystemTimer( rate, (SYSTEMTIMERPROC)thunk );
847 #endif
848
849     if (!timer) THUNK_Free( thunk );
850     return timer;
851 }
852
853
854 /***********************************************************************
855  * 16->32 Flat Thunk routines:
856  */
857
858 /***********************************************************************
859  *              ThunkConnect16          (KERNEL.651)
860  * Connects a 32bit and a 16bit thunkbuffer.
861  */
862 UINT32 WINAPI ThunkConnect16(
863         LPSTR module16,              /* [in] name of win16 dll */
864         LPSTR module32,              /* [in] name of win32 dll */
865         HINSTANCE16 hInst16,         /* [in] hInst of win16 dll */
866         DWORD dwReason,              /* [in] initialisation argument */
867         struct ThunkDataCommon *TD,  /* [in/out] thunkbuffer */
868         LPSTR thunkfun32,            /* [in] win32 thunkfunction */
869         WORD cs                      /* [in] CS of win16 dll */
870 ) {
871     BOOL32 directionSL;
872
873     if (!lstrncmp32A(TD->magic, "SL01", 4))
874     {
875         directionSL = TRUE;
876
877         TRACE(thunk, "SL01 thunk %s (%lx) -> %s (%s), Reason: %ld\n",
878                      module16, (DWORD)TD, module32, thunkfun32, dwReason);
879     }
880     else if (!lstrncmp32A(TD->magic, "LS01", 4))
881     {
882         directionSL = FALSE;
883
884         TRACE(thunk, "LS01 thunk %s (%lx) <- %s (%s), Reason: %ld\n",
885                      module16, (DWORD)TD, module32, thunkfun32, dwReason);
886     }
887     else
888     {
889         ERR(thunk, "Invalid magic %c%c%c%c\n",
890                    TD->magic[0], TD->magic[1], TD->magic[2], TD->magic[3]);
891         return 0;
892     }
893
894     switch (dwReason)
895     {
896         case DLL_PROCESS_ATTACH:
897             if (directionSL)
898             {
899                 struct ThunkDataSL16 *SL16 = (struct ThunkDataSL16 *)TD;
900                 struct ThunkDataSL   *SL   = SL16->fpData;
901
902                 if (SL == NULL)
903                 {
904                     SL = HeapAlloc(GetProcessHeap(), 0, sizeof(*SL));
905
906                     SL->common   = SL16->common;
907                     SL->flags1   = SL16->flags1;
908                     SL->flags2   = SL16->flags2;
909
910                     SL->apiDB    = PTR_SEG_TO_LIN(SL16->apiDatabase);
911                     SL->targetDB = NULL;
912
913                     lstrcpyn32A(SL->pszDll16, module16, 255);
914                     lstrcpyn32A(SL->pszDll32, module32, 255);
915
916                     /* We should create a SEGPTR to the ThunkDataSL,
917                        but since the contents are not in the original format,
918                        any access to this by 16-bit code would crash anyway. */
919                     SL16->spData = 0;
920                     SL16->fpData = SL;
921                 }
922
923
924                 if (SL->flags2 & 0x80000000)
925                 {
926                     TRACE(thunk, "Preloading 32-bit library\n");
927                     LoadLibrary32A(module32);
928                 }
929             }
930             else
931             {
932                 /* nothing to do */
933             }
934             break;
935
936         case DLL_PROCESS_DETACH:
937             /* FIXME: cleanup */
938             break;
939     }
940
941     return 1;
942 }
943
944
945 /***********************************************************************
946  *           C16ThkSL                           (KERNEL.630)
947  */
948
949 void WINAPI C16ThkSL(CONTEXT *context)
950 {
951     extern void CallFrom16_t_long_(void);
952     LPBYTE stub = PTR_SEG_TO_LIN(EAX_reg(context)), x = stub;
953     WORD cs, ds;
954     GET_CS(cs);
955     GET_DS(ds);
956
957     /* We produce the following code:
958      *
959      *   mov ax, __FLATDS
960      *   mov es, ax
961      *   movzx ecx, cx
962      *   mov edx, es:[ecx + $EDX]
963      *   push bp
964      *   push edx
965      *   call __FLATCS:CallFrom16_t_long_
966      */
967
968     *x++ = 0xB8; *((WORD *)x)++ = ds;
969     *x++ = 0x8E; *x++ = 0xC0;
970     *x++ = 0x66; *x++ = 0x0F; *x++ = 0xB7; *x++ = 0xC9;
971     *x++ = 0x67; *x++ = 0x66; *x++ = 0x26; *x++ = 0x8B;
972                  *x++ = 0x91; *((DWORD *)x)++ = EDX_reg(context);
973
974     *x++ = 0x55;
975     *x++ = 0x66; *x++ = 0x52;
976     *x++ = 0x66; *x++ = 0x9A; *((DWORD *)x)++ = (DWORD)CallFrom16_t_long_;
977                               *((WORD *)x)++ = cs;
978
979     /* Jump to the stub code just created */
980     IP_reg(context) = LOWORD(EAX_reg(context));
981     CS_reg(context) = HIWORD(EAX_reg(context));
982
983     /* Since C16ThkSL got called by a jmp, we need to leave the
984        orginal return address on the stack */
985     SP_reg(context) -= 4;
986 }
987
988 /***********************************************************************
989  *           C16ThkSL01                         (KERNEL.631)
990  */
991
992 void WINAPI C16ThkSL01(CONTEXT *context)
993 {
994     LPBYTE stub = PTR_SEG_TO_LIN(EAX_reg(context)), x = stub;
995
996     if (stub)
997     {
998         struct ThunkDataSL16 *SL16 = PTR_SEG_TO_LIN(EDX_reg(context));
999         struct ThunkDataSL *td = SL16->fpData;
1000
1001         extern void CallFrom16_t_long_(void);
1002         DWORD procAddress = (DWORD)GetProcAddress16(GetModuleHandle16("KERNEL"), 631);
1003         WORD cs;
1004         GET_CS(cs);
1005
1006         if (!td)
1007         {
1008             ERR(thunk, "ThunkConnect16 was not called!\n");
1009             return;
1010         }
1011
1012         TRACE(thunk, "Creating stub for ThunkDataSL %08lx\n", (DWORD)td);
1013
1014
1015         /* We produce the following code:
1016          *
1017          *   xor eax, eax
1018          *   mov edx, $td
1019          *   call C16ThkSL01
1020          *   push bp
1021          *   push edx
1022          *   call __FLATCS:CallFrom16_t_long_
1023          */
1024
1025         *x++ = 0x66; *x++ = 0x33; *x++ = 0xC0;
1026         *x++ = 0x66; *x++ = 0xBA; *((DWORD *)x)++ = (DWORD)td;
1027         *x++ = 0x9A; *((DWORD *)x)++ = procAddress;
1028
1029         *x++ = 0x55;
1030         *x++ = 0x66; *x++ = 0x52;
1031         *x++ = 0x66; *x++ = 0x9A; *((DWORD *)x)++ = (DWORD)CallFrom16_t_long_;
1032                                   *((WORD *)x)++ = cs;
1033
1034         /* Jump to the stub code just created */
1035         IP_reg(context) = LOWORD(EAX_reg(context));
1036         CS_reg(context) = HIWORD(EAX_reg(context));
1037
1038         /* Since C16ThkSL01 got called by a jmp, we need to leave the
1039            orginal return address on the stack */
1040         SP_reg(context) -= 4;
1041     }
1042     else
1043     {
1044         struct ThunkDataSL *td = (struct ThunkDataSL *)EDX_reg(context);
1045         DWORD targetNr = CX_reg(context) / 4;
1046         struct SLTargetDB *tdb;
1047
1048         TRACE(thunk, "Process %08lx calling target %ld of ThunkDataSL %08lx\n",
1049                      (DWORD)PROCESS_Current(), targetNr, (DWORD)td);
1050
1051         for (tdb = td->targetDB; tdb; tdb = tdb->next)
1052             if (tdb->process == PROCESS_Current())
1053                 break;
1054
1055         if (!tdb)
1056         {
1057             TRACE(thunk, "Loading 32-bit library %s\n", td->pszDll32);
1058             LoadLibrary32A(td->pszDll32);
1059
1060             for (tdb = td->targetDB; tdb; tdb = tdb->next)
1061                 if (tdb->process == PROCESS_Current())
1062                     break;
1063         }
1064
1065         if (tdb)
1066         {
1067             EDX_reg(context) = tdb->targetTable[targetNr];
1068
1069             TRACE(thunk, "Call target is %08lx\n", EDX_reg(context));
1070         }
1071         else
1072         {
1073             WORD *stack = PTR_SEG_OFF_TO_LIN(SS_reg(context), SP_reg(context));
1074             DX_reg(context) = HIWORD(td->apiDB[targetNr].errorReturnValue);
1075             AX_reg(context) = LOWORD(td->apiDB[targetNr].errorReturnValue);
1076             IP_reg(context) = stack[2];
1077             CS_reg(context) = stack[3];
1078             SP_reg(context) += td->apiDB[targetNr].nrArgBytes + 4;
1079
1080             ERR(thunk, "Process %08lx did not ThunkConnect32 %s to %s\n",
1081                        (DWORD)PROCESS_Current(), td->pszDll32, td->pszDll16);
1082         }
1083     }
1084 }
1085
1086 DWORD WINAPI 
1087 WOW16Call(WORD x,WORD y,WORD z) {
1088         int     i;
1089         DWORD   calladdr;
1090         FIXME(thunk,"(0x%04x,0x%04x,%d),calling (",x,y,z);
1091
1092         for (i=0;i<x/2;i++) {
1093                 WORD    a = STACK16_POP(THREAD_Current(),2);
1094                 DPRINTF("%04x ",a);
1095         }
1096         calladdr = STACK16_POP(THREAD_Current(),4);
1097         DPRINTF(") calling address was 0x%08lx\n",calladdr);
1098         return 0;
1099 }
1100
1101
1102 /***********************************************************************
1103  * 16<->32 Thunklet/Callback API:
1104  */
1105
1106 #pragma pack(1)
1107 typedef struct _THUNKLET
1108 {
1109     BYTE        prefix_target;
1110     BYTE        pushl_target;
1111     DWORD       target;
1112
1113     BYTE        prefix_relay;
1114     BYTE        pushl_relay;
1115     DWORD       relay;
1116
1117     BYTE        jmp_glue;
1118     DWORD       glue;
1119
1120     BYTE        type;
1121     HINSTANCE16 owner;
1122     struct _THUNKLET *next;
1123 } THUNKLET;
1124 #pragma pack(4)
1125
1126 #define THUNKLET_TYPE_LS  1
1127 #define THUNKLET_TYPE_SL  2
1128
1129 static HANDLE32  ThunkletHeap = 0;
1130 static THUNKLET *ThunkletAnchor = NULL;
1131
1132 static FARPROC32 ThunkletSysthunkGlueLS = 0;
1133 static SEGPTR    ThunkletSysthunkGlueSL = 0;
1134
1135 static FARPROC32 ThunkletCallbackGlueLS = 0;
1136 static SEGPTR    ThunkletCallbackGlueSL = 0;
1137
1138 /***********************************************************************
1139  *     THUNK_ThunkletInit
1140  */
1141 static BOOL32 THUNK_ThunkletInit( void )
1142 {
1143     LPBYTE thunk;
1144
1145     ThunkletHeap = HeapCreate(HEAP_WINE_SEGPTR | HEAP_WINE_CODE16SEG, 0, 0);
1146     if (!ThunkletHeap) return FALSE;
1147
1148     thunk = HeapAlloc( ThunkletHeap, 0, 5 );
1149     if (!thunk) return FALSE;
1150     
1151     ThunkletSysthunkGlueLS = (FARPROC32)thunk;
1152     *thunk++ = 0x58;                             /* popl eax */
1153     *thunk++ = 0xC3;                             /* ret      */
1154
1155     ThunkletSysthunkGlueSL = HEAP_GetSegptr( ThunkletHeap, 0, thunk );
1156     *thunk++ = 0x66; *thunk++ = 0x58;            /* popl eax */
1157     *thunk++ = 0xCB;                             /* lret     */
1158
1159     return TRUE;
1160 }
1161
1162 /***********************************************************************
1163  *     SetThunkletCallbackGlue             (KERNEL.560)
1164  */
1165 void WINAPI SetThunkletCallbackGlue( FARPROC32 glueLS, SEGPTR glueSL )
1166 {
1167     ThunkletCallbackGlueLS = glueLS;
1168     ThunkletCallbackGlueSL = glueSL;
1169 }
1170
1171
1172 /***********************************************************************
1173  *     THUNK_FindThunklet
1174  */
1175 THUNKLET *THUNK_FindThunklet( DWORD target, DWORD relay, 
1176                               DWORD glue, BYTE type ) 
1177 {
1178     THUNKLET *thunk; 
1179
1180     for (thunk = ThunkletAnchor; thunk; thunk = thunk->next)
1181         if (    thunk->type   == type
1182              && thunk->target == target
1183              && thunk->relay  == relay 
1184              && thunk->glue   == glue )
1185             return thunk;
1186
1187      return NULL;
1188 }
1189
1190 /***********************************************************************
1191  *     THUNK_AllocLSThunklet
1192  */
1193 FARPROC32 THUNK_AllocLSThunklet( SEGPTR target, DWORD relay, 
1194                                  FARPROC32 glue, HTASK16 owner ) 
1195 {
1196     THUNKLET *thunk = THUNK_FindThunklet( (DWORD)target, relay, (DWORD)glue,
1197                                           THUNKLET_TYPE_LS );
1198     if (!thunk)
1199     {
1200         TDB *pTask = (TDB*)GlobalLock16( owner );
1201
1202         if ( !(thunk = HeapAlloc( ThunkletHeap, 0, sizeof(THUNKLET) )) )
1203             return 0;
1204
1205         thunk->prefix_target = thunk->prefix_relay = 0x90;
1206         thunk->pushl_target  = thunk->pushl_relay  = 0x68;
1207         thunk->jmp_glue = 0xE9;
1208
1209         thunk->target  = (DWORD)target;
1210         thunk->relay   = (DWORD)relay;
1211         thunk->glue    = (DWORD)glue - (DWORD)&thunk->type;
1212
1213         thunk->type    = THUNKLET_TYPE_LS;
1214         thunk->owner   = pTask? pTask->hInstance : 0;
1215
1216         thunk->next    = ThunkletAnchor;
1217         ThunkletAnchor = thunk;
1218     }
1219
1220     return (FARPROC32)thunk;
1221 }
1222
1223 /***********************************************************************
1224  *     THUNK_AllocSLThunklet
1225  */
1226 SEGPTR THUNK_AllocSLThunklet( FARPROC32 target, DWORD relay,
1227                               SEGPTR glue, HTASK16 owner )
1228 {
1229     THUNKLET *thunk = THUNK_FindThunklet( (DWORD)target, relay, (DWORD)glue,
1230                                           THUNKLET_TYPE_SL );
1231     if (!thunk)
1232     {
1233         TDB *pTask = (TDB*)GlobalLock16( owner );
1234
1235         if ( !(thunk = HeapAlloc( ThunkletHeap, 0, sizeof(THUNKLET) )) )
1236             return 0;
1237
1238         thunk->prefix_target = thunk->prefix_relay = 0x66;
1239         thunk->pushl_target  = thunk->pushl_relay  = 0x68;
1240         thunk->jmp_glue = 0xEA;
1241
1242         thunk->target  = (DWORD)target;
1243         thunk->relay   = (DWORD)relay;
1244         thunk->glue    = (DWORD)glue;
1245
1246         thunk->type    = THUNKLET_TYPE_SL;
1247         thunk->owner   = pTask? pTask->hInstance : 0;
1248
1249         thunk->next    = ThunkletAnchor;
1250         ThunkletAnchor = thunk;
1251     }
1252
1253     return HEAP_GetSegptr( ThunkletHeap, 0, thunk );
1254 }
1255
1256 /**********************************************************************
1257  *     IsLSThunklet
1258  */
1259 BOOL16 WINAPI IsLSThunklet( THUNKLET *thunk )
1260 {
1261     return    thunk->prefix_target == 0x90 && thunk->pushl_target == 0x68
1262            && thunk->prefix_relay  == 0x90 && thunk->pushl_relay  == 0x68
1263            && thunk->jmp_glue == 0xE9 && thunk->type == THUNKLET_TYPE_LS;
1264 }
1265
1266 /**********************************************************************
1267  *     IsSLThunklet                        (KERNEL.612)
1268  */
1269 BOOL16 WINAPI IsSLThunklet( THUNKLET *thunk )
1270 {
1271     return    thunk->prefix_target == 0x66 && thunk->pushl_target == 0x68
1272            && thunk->prefix_relay  == 0x66 && thunk->pushl_relay  == 0x68
1273            && thunk->jmp_glue == 0xEA && thunk->type == THUNKLET_TYPE_SL;
1274 }
1275
1276
1277
1278 /***********************************************************************
1279  *     AllocLSThunkletSysthunk             (KERNEL.607)
1280  */
1281 FARPROC32 WINAPI AllocLSThunkletSysthunk( SEGPTR target, 
1282                                           FARPROC32 relay, DWORD dummy )
1283 {
1284     return THUNK_AllocLSThunklet( (SEGPTR)relay, (DWORD)target, 
1285                                   ThunkletSysthunkGlueLS, GetCurrentTask() );
1286 }
1287
1288 /***********************************************************************
1289  *     AllocSLThunkletSysthunk             (KERNEL.608)
1290  */
1291 SEGPTR WINAPI AllocSLThunkletSysthunk( FARPROC32 target, 
1292                                        SEGPTR relay, DWORD dummy )
1293 {
1294     return THUNK_AllocSLThunklet( (FARPROC32)relay, (DWORD)target, 
1295                                   ThunkletSysthunkGlueSL, GetCurrentTask() );
1296 }
1297
1298
1299 /***********************************************************************
1300  *     AllocLSThunkletCallbackEx           (KERNEL.567)
1301  */
1302 FARPROC32 WINAPI AllocLSThunkletCallbackEx( SEGPTR target, 
1303                                             DWORD relay, HTASK16 task )
1304 {
1305     THUNKLET *thunk = (THUNKLET *)PTR_SEG_TO_LIN( target );
1306     if (   IsSLThunklet( thunk ) && thunk->relay == relay 
1307         && thunk->glue == (DWORD)ThunkletCallbackGlueSL )
1308         return (FARPROC32)thunk->target;
1309
1310     return THUNK_AllocLSThunklet( target, relay, 
1311                                   ThunkletCallbackGlueLS, task );
1312 }
1313
1314 /***********************************************************************
1315  *     AllocSLThunkletCallbackEx           (KERNEL.568)
1316  */
1317 SEGPTR WINAPI AllocSLThunkletCallbackEx( FARPROC32 target, 
1318                                          DWORD relay, HTASK16 task )
1319 {
1320     THUNKLET *thunk = (THUNKLET *)target;
1321     if (   IsLSThunklet( thunk ) && thunk->relay == relay 
1322         && thunk->glue == (DWORD)ThunkletCallbackGlueLS )
1323         return (SEGPTR)thunk->target;
1324
1325     return THUNK_AllocSLThunklet( target, relay, 
1326                                   ThunkletCallbackGlueSL, task );
1327 }
1328
1329 /***********************************************************************
1330  *     AllocLSThunkletCallback             (KERNEL.561) (KERNEL.606)
1331  */
1332 FARPROC32 WINAPI AllocLSThunkletCallback( SEGPTR target, DWORD relay )
1333 {
1334     return AllocLSThunkletCallbackEx( target, relay, GetCurrentTask() );
1335 }
1336
1337 /***********************************************************************
1338  *     AllocSLThunkletCallback             (KERNEL.562) (KERNEL.605)
1339  */
1340 SEGPTR WINAPI AllocSLThunkletCallback( FARPROC32 target, DWORD relay )
1341 {
1342     return AllocSLThunkletCallbackEx( target, relay, GetCurrentTask() );
1343 }
1344
1345 /***********************************************************************
1346  *     FindLSThunkletCallback              (KERNEL.563) (KERNEL.609)
1347  */
1348 FARPROC32 WINAPI FindLSThunkletCallback( SEGPTR target, DWORD relay )
1349 {
1350     THUNKLET *thunk = (THUNKLET *)PTR_SEG_TO_LIN( target );
1351     if (   thunk && IsSLThunklet( thunk ) && thunk->relay == relay 
1352         && thunk->glue == (DWORD)ThunkletCallbackGlueSL )
1353         return (FARPROC32)thunk->target;
1354
1355     thunk = THUNK_FindThunklet( (DWORD)target, relay, 
1356                                 (DWORD)ThunkletCallbackGlueLS, 
1357                                 THUNKLET_TYPE_LS );
1358     return (FARPROC32)thunk;
1359 }
1360
1361 /***********************************************************************
1362  *     FindSLThunkletCallback              (KERNEL.564) (KERNEL.610)
1363  */
1364 SEGPTR WINAPI FindSLThunkletCallback( FARPROC32 target, DWORD relay )
1365 {
1366     THUNKLET *thunk = (THUNKLET *)target;
1367     if (   thunk && IsLSThunklet( thunk ) && thunk->relay == relay 
1368         && thunk->glue == (DWORD)ThunkletCallbackGlueLS )
1369         return (SEGPTR)thunk->target;
1370
1371     thunk = THUNK_FindThunklet( (DWORD)target, relay, 
1372                                 (DWORD)ThunkletCallbackGlueSL, 
1373                                 THUNKLET_TYPE_SL );
1374     return HEAP_GetSegptr( ThunkletHeap, 0, thunk );
1375 }
1376
1377
1378 /***********************************************************************
1379  * Callback Client API
1380  */
1381
1382 #define N_CBC_FIXED    20
1383 #define N_CBC_VARIABLE 10
1384 #define N_CBC_TOTAL    (N_CBC_FIXED + N_CBC_VARIABLE)
1385
1386 static SEGPTR    *CBClientRelay16[ N_CBC_TOTAL ];
1387 static FARPROC32 *CBClientRelay32[ N_CBC_TOTAL ];
1388
1389 /***********************************************************************
1390  *     RegisterCBClient                    (KERNEL.619)
1391  */
1392 INT16 WINAPI RegisterCBClient( INT16 wCBCId, 
1393                                SEGPTR *relay16, FARPROC32 *relay32 )
1394 {
1395     /* Search for free Callback ID */
1396     if ( wCBCId == -1 )
1397         for ( wCBCId = N_CBC_FIXED; wCBCId < N_CBC_TOTAL; wCBCId++ )
1398             if ( !CBClientRelay16[ wCBCId ] )
1399                 break;
1400
1401     /* Register Callback ID */
1402     if ( wCBCId > 0 && wCBCId < N_CBC_TOTAL )
1403     {
1404         CBClientRelay16[ wCBCId ] = relay16;
1405         CBClientRelay32[ wCBCId ] = relay32;
1406     }
1407     else
1408         wCBCId = 0;
1409
1410     return wCBCId;
1411 }
1412
1413 /***********************************************************************
1414  *     UnRegisterCBClient                  (KERNEL.622)
1415  */
1416 INT16 WINAPI UnRegisterCBClient( INT16 wCBCId, 
1417                                  SEGPTR *relay16, FARPROC32 *relay32 )
1418 {
1419     if (    wCBCId >= N_CBC_FIXED && wCBCId < N_CBC_TOTAL 
1420          && CBClientRelay16[ wCBCId ] == relay16 
1421          && CBClientRelay32[ wCBCId ] == relay32 )
1422     {
1423         CBClientRelay16[ wCBCId ] = 0;
1424         CBClientRelay32[ wCBCId ] = 0;
1425     }
1426     else
1427         wCBCId = 0;
1428
1429     return wCBCId;
1430 }
1431
1432
1433 /***********************************************************************
1434  *     InitCBClient                        (KERNEL.623)
1435  */
1436 void WINAPI InitCBClient( FARPROC32 glueLS )
1437 {
1438     HMODULE16 kernel = GetModuleHandle16( "KERNEL" );
1439     SEGPTR glueSL = (SEGPTR)WIN32_GetProcAddress16( kernel, (LPCSTR)604 );
1440
1441     SetThunkletCallbackGlue( glueLS, glueSL );
1442 }
1443
1444 /***********************************************************************
1445  *     CBClientGlueSL                      (KERNEL.604)
1446  */
1447 void WINAPI CBClientGlueSL( CONTEXT *context )
1448 {
1449     /* Create stack frame */
1450     SEGPTR stackSeg = STACK16_PUSH( THREAD_Current(), 12 );
1451     LPWORD stackLin = PTR_SEG_TO_LIN( stackSeg );
1452     SEGPTR glue;
1453     
1454     stackLin[3] = BP_reg( context );
1455     stackLin[2] = SI_reg( context );
1456     stackLin[1] = DI_reg( context );
1457     stackLin[0] = DS_reg( context );
1458
1459     BP_reg( context ) = OFFSETOF( stackSeg ) + 6;
1460     SP_reg( context ) = OFFSETOF( stackSeg ) - 4;
1461     GS_reg( context ) = 0;
1462
1463     /* Jump to 16-bit relay code */
1464     glue = CBClientRelay16[ stackLin[5] ][ stackLin[4] ];
1465     CS_reg ( context ) = SELECTOROF( glue );
1466     EIP_reg( context ) = OFFSETOF  ( glue );
1467 }
1468
1469 /***********************************************************************
1470  *     CBClientThunkSL                      (KERNEL.620)
1471  */
1472 void WINAPI CBClientThunkSL( CONTEXT *context )
1473 {
1474     /* Call 32-bit relay code */
1475     extern DWORD WINAPI CALL32_CBClient( FARPROC32 proc, LPWORD args );
1476
1477     LPWORD args = PTR_SEG_OFF_TO_LIN( SS_reg( context ), BP_reg( context ) );
1478     FARPROC32 proc = CBClientRelay32[ args[2] ][ args[1] ];
1479
1480     EAX_reg(context) = CALL32_CBClient( proc, args );
1481 }
1482