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