Release 970928
[wine.git] / if1632 / thunk.c
blob2da1a3d03f96ecc09162697f76b993f3926c2fcb
1 /*
2 * Emulator and Win95 thunks
4 * Copyright 1996 Alexandre Julliard
5 * Copyright 1997 Marcus Meissner
6 */
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 "winproc.h"
17 #include "stackframe.h"
18 #include "selectors.h"
19 #include "task.h"
20 #include "except.h"
21 #include "win.h"
22 #include "stddebug.h"
23 #include "debug.h"
25 typedef void (*RELAY)();
27 #pragma pack(1)
29 typedef struct tagTHUNK
31 BYTE popl_eax; /* 0x58 popl %eax (return address)*/
32 BYTE pushl_func; /* 0x68 pushl $proc */
33 FARPROC32 proc WINE_PACKED;
34 BYTE pushl_eax; /* 0x50 pushl %eax */
35 BYTE jmp; /* 0xe9 jmp relay (relative jump)*/
36 RELAY relay WINE_PACKED;
37 struct tagTHUNK *next WINE_PACKED;
38 } THUNK;
40 #pragma pack(4)
42 #define DECL_THUNK(name,proc,relay) \
43 THUNK name = { 0x58, 0x68, (FARPROC32)(proc), 0x50, 0xe9, \
44 (RELAY)((char *)(relay) - (char *)(&(name).next)), NULL }
47 static THUNK *firstThunk = NULL;
49 static LRESULT THUNK_CallWndProc16( WNDPROC16 proc, HWND16 hwnd, UINT16 msg,
50 WPARAM16 wParam, LPARAM lParam );
52 /***********************************************************************
53 * THUNK_Init
55 BOOL32 THUNK_Init(void)
57 /* Set the window proc calling functions */
58 WINPROC_SetCallWndProc16( THUNK_CallWndProc16 );
59 return TRUE;
63 /***********************************************************************
64 * THUNK_Alloc
66 static THUNK *THUNK_Alloc( FARPROC32 func, RELAY relay )
68 THUNK *thunk = HeapAlloc( GetProcessHeap(), 0, sizeof(*thunk) );
69 if (thunk)
71 thunk->popl_eax = 0x58;
72 thunk->pushl_func = 0x68;
73 thunk->proc = func;
74 thunk->pushl_eax = 0x50;
75 thunk->jmp = 0xe9;
76 thunk->relay = (RELAY)((char *)relay - (char *)(&thunk->next));
77 thunk->next = firstThunk;
78 firstThunk = thunk;
80 return thunk;
84 /***********************************************************************
85 * THUNK_Find
87 static THUNK *THUNK_Find( FARPROC32 func )
89 THUNK *thunk = firstThunk;
90 while (thunk && (thunk->proc != func)) thunk = thunk->next;
91 return thunk;
95 /***********************************************************************
96 * THUNK_Free
98 static void THUNK_Free( THUNK *thunk )
100 if (HEAP_IsInsideHeap( GetProcessHeap(), 0, thunk ))
102 THUNK **prev = &firstThunk;
103 while (*prev && (*prev != thunk)) prev = &(*prev)->next;
104 if (*prev)
106 *prev = thunk->next;
107 HeapFree( GetProcessHeap(), 0, thunk );
108 return;
111 fprintf( stderr, "THUNK_Free: invalid thunk addr %p\n", thunk );
115 /***********************************************************************
116 * THUNK_CallWndProc16
118 * Call a 16-bit window procedure
120 static LRESULT THUNK_CallWndProc16( WNDPROC16 proc, HWND16 hwnd, UINT16 msg,
121 WPARAM16 wParam, LPARAM lParam )
123 CONTEXT context;
124 LRESULT ret;
125 WORD *args;
126 WND *wndPtr = WIN_FindWndPtr( hwnd );
127 DWORD offset = 0;
129 /* Window procedures want ax = hInstance, ds = es = ss */
131 DS_reg(&context) = SELECTOROF(IF1632_Saved16_ss_sp);
132 ES_reg(&context) = DS_reg(&context);
133 EAX_reg(&context) = wndPtr ? wndPtr->hInstance : DS_reg(&context);
134 CS_reg(&context) = SELECTOROF(proc);
135 EIP_reg(&context) = OFFSETOF(proc);
136 EBP_reg(&context) = OFFSETOF(IF1632_Saved16_ss_sp)
137 + (WORD)&((STACK16FRAME*)0)->bp;
139 if (((msg == WM_CREATE) || (msg == WM_NCCREATE)) && lParam)
141 /* Build the CREATESTRUCT on the 16-bit stack. */
142 /* This is really ugly, but some programs (notably the */
143 /* "Undocumented Windows" examples) want it that way. */
144 CREATESTRUCT16 *cs = (CREATESTRUCT16 *)PTR_SEG_TO_LIN(lParam);
145 offset = sizeof(*cs);
146 memcpy( (char *)CURRENT_STACK16 - offset, cs, offset );
147 IF1632_Saved16_ss_sp -= offset;
148 lParam = IF1632_Saved16_ss_sp;
150 args = (WORD *)CURRENT_STACK16 - 7;
151 args[0] = LOWORD(lParam);
152 args[1] = HIWORD(lParam);
153 args[2] = wParam;
154 args[3] = msg;
155 args[4] = hwnd;
156 /* args[5] and args[6] are used by relay code to store the stack pointer */
158 ret = CallTo16_regs_( &context, -(5 * sizeof(WORD)) );
159 IF1632_Saved16_ss_sp += offset;
160 return ret;
164 /***********************************************************************
165 * THUNK_EnumObjects16 (GDI.71)
167 INT16 WINAPI THUNK_EnumObjects16( HDC16 hdc, INT16 nObjType,
168 GOBJENUMPROC16 func, LPARAM lParam )
170 DECL_THUNK( thunk, func, CallTo16_word_ll );
171 return EnumObjects16( hdc, nObjType, (GOBJENUMPROC16)&thunk, lParam );
175 /*************************************************************************
176 * THUNK_EnumFonts16 (GDI.70)
178 INT16 WINAPI THUNK_EnumFonts16( HDC16 hdc, LPCSTR lpFaceName,
179 FONTENUMPROC16 func, LPARAM lParam )
181 DECL_THUNK( thunk, func, CallTo16_word_llwl );
182 return EnumFonts16( hdc, lpFaceName, (FONTENUMPROC16)&thunk, lParam );
185 /******************************************************************
186 * THUNK_EnumMetaFile16 (GDI.175)
188 BOOL16 WINAPI THUNK_EnumMetaFile16( HDC16 hdc, HMETAFILE16 hmf,
189 MFENUMPROC16 func, LPARAM lParam )
191 DECL_THUNK( thunk, func, CallTo16_word_wllwl );
192 return EnumMetaFile16( hdc, hmf, (MFENUMPROC16)&thunk, lParam );
196 /*************************************************************************
197 * THUNK_EnumFontFamilies16 (GDI.330)
199 INT16 WINAPI THUNK_EnumFontFamilies16( HDC16 hdc, LPCSTR lpszFamily,
200 FONTENUMPROC16 func, LPARAM lParam )
202 DECL_THUNK( thunk, func, CallTo16_word_llwl );
203 return EnumFontFamilies16(hdc, lpszFamily, (FONTENUMPROC16)&thunk, lParam);
207 /*************************************************************************
208 * THUNK_EnumFontFamiliesEx16 (GDI.613)
210 INT16 WINAPI THUNK_EnumFontFamiliesEx16( HDC16 hdc, LPLOGFONT16 lpLF,
211 FONTENUMPROCEX16 func, LPARAM lParam,
212 DWORD reserved )
214 DECL_THUNK( thunk, func, CallTo16_word_llwl );
215 return EnumFontFamiliesEx16( hdc, lpLF, (FONTENUMPROCEX16)&thunk,
216 lParam, reserved );
220 /**********************************************************************
221 * THUNK_LineDDA16 (GDI.100)
223 void WINAPI THUNK_LineDDA16( INT16 nXStart, INT16 nYStart, INT16 nXEnd,
224 INT16 nYEnd, LINEDDAPROC16 func, LPARAM lParam )
226 DECL_THUNK( thunk, func, CallTo16_word_wwl );
227 LineDDA16( nXStart, nYStart, nXEnd, nYEnd, (LINEDDAPROC16)&thunk, lParam );
231 /*******************************************************************
232 * THUNK_EnumWindows16 (USER.54)
234 BOOL16 WINAPI THUNK_EnumWindows16( WNDENUMPROC16 func, LPARAM lParam )
236 DECL_THUNK( thunk, func, CallTo16_word_wl );
237 return EnumWindows16( (WNDENUMPROC16)&thunk, lParam );
241 /**********************************************************************
242 * THUNK_EnumChildWindows16 (USER.55)
244 BOOL16 WINAPI THUNK_EnumChildWindows16( HWND16 parent, WNDENUMPROC16 func,
245 LPARAM lParam )
247 DECL_THUNK( thunk, func, CallTo16_word_wl );
248 return EnumChildWindows16( parent, (WNDENUMPROC16)&thunk, lParam );
252 /**********************************************************************
253 * THUNK_EnumTaskWindows16 (USER.225)
255 BOOL16 WINAPI THUNK_EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
256 LPARAM lParam )
258 DECL_THUNK( thunk, func, CallTo16_word_wl );
259 return EnumTaskWindows16( hTask, (WNDENUMPROC16)&thunk, lParam );
263 /***********************************************************************
264 * THUNK_EnumProps16 (USER.27)
266 INT16 WINAPI THUNK_EnumProps16( HWND16 hwnd, PROPENUMPROC16 func )
268 DECL_THUNK( thunk, func, CallTo16_word_wlw );
269 return EnumProps16( hwnd, (PROPENUMPROC16)&thunk );
273 /***********************************************************************
274 * THUNK_GrayString16 (USER.185)
276 BOOL16 WINAPI THUNK_GrayString16( HDC16 hdc, HBRUSH16 hbr,
277 GRAYSTRINGPROC16 func, LPARAM lParam,
278 INT16 cch, INT16 x, INT16 y,
279 INT16 cx, INT16 cy )
281 DECL_THUNK( thunk, func, CallTo16_word_wlw );
282 if (!func)
283 return GrayString16( hdc, hbr, NULL, lParam, cch, x, y, cx, cy );
284 else
285 return GrayString16( hdc, hbr, (GRAYSTRINGPROC16)&thunk, lParam, cch,
286 x, y, cx, cy );
290 /***********************************************************************
291 * THUNK_SetWindowsHook16 (USER.121)
293 FARPROC16 WINAPI THUNK_SetWindowsHook16( INT16 id, HOOKPROC16 proc )
295 HINSTANCE16 hInst = FarGetOwner( HIWORD(proc) );
296 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
297 THUNK *thunk = THUNK_Alloc( (FARPROC16)proc, (RELAY)CallTo16_long_wwl );
298 if (!thunk) return 0;
299 return (FARPROC16)SetWindowsHookEx16( id, (HOOKPROC16)thunk, hInst, hTask);
303 /***********************************************************************
304 * THUNK_UnhookWindowsHook16 (USER.234)
306 BOOL16 WINAPI THUNK_UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
308 BOOL16 ret;
309 THUNK *thunk = THUNK_Find( (FARPROC16)proc );
310 if (!thunk) return FALSE;
311 ret = UnhookWindowsHook16( id, (HOOKPROC16)thunk );
312 THUNK_Free( thunk );
313 return ret;
317 /***********************************************************************
318 * THUNK_SetWindowsHookEx16 (USER.291)
320 HHOOK WINAPI THUNK_SetWindowsHookEx16( INT16 id, HOOKPROC16 proc,
321 HINSTANCE16 hInst, HTASK16 hTask )
323 THUNK *thunk = THUNK_Alloc( (FARPROC16)proc, (RELAY)CallTo16_long_wwl );
324 if (!thunk) return 0;
325 return SetWindowsHookEx16( id, (HOOKPROC16)thunk, hInst, hTask );
329 /***********************************************************************
330 * THUNK_UnhookWindowHookEx16 (USER.292)
332 BOOL16 WINAPI THUNK_UnhookWindowsHookEx16( HHOOK hhook )
334 THUNK *thunk = (THUNK *)HOOK_GetProc16( hhook );
335 BOOL16 ret = UnhookWindowsHookEx16( hhook );
336 if (thunk) THUNK_Free( thunk );
337 return ret;
341 /***********************************************************************
342 * THUNK_CreateSystemTimer (SYSTEM.2)
344 WORD WINAPI THUNK_CreateSystemTimer( WORD rate, FARPROC16 callback )
346 THUNK *thunk = THUNK_Alloc( callback, (RELAY)CallTo16_word_ );
347 if (!thunk) return 0;
348 return CreateSystemTimer( rate, (FARPROC16)thunk );
352 /***********************************************************************
353 * THUNK_KillSystemTimer (SYSTEM.3)
355 WORD WINAPI THUNK_KillSystemTimer( WORD timer )
357 extern WORD SYSTEM_KillSystemTimer( WORD timer ); /* misc/system.c */
358 extern FARPROC16 SYSTEM_GetTimerProc( WORD timer ); /* misc/system.c */
360 THUNK *thunk = (THUNK *)SYSTEM_GetTimerProc( timer );
361 WORD ret = SYSTEM_KillSystemTimer( timer );
362 if (thunk) THUNK_Free( thunk );
363 return ret;
367 static FARPROC16 defDCHookProc = NULL;
369 /***********************************************************************
370 * THUNK_SetDCHook (GDI.190)
372 BOOL16 WINAPI THUNK_SetDCHook( HDC16 hdc, FARPROC16 proc, DWORD dwHookData )
374 THUNK *thunk, *oldThunk;
376 if (!defDCHookProc) /* Get DCHook Win16 entry point */
377 defDCHookProc = MODULE_GetEntryPoint( GetModuleHandle16("USER"), 362 );
379 if (proc != defDCHookProc)
381 thunk = THUNK_Alloc( proc, (RELAY)CallTo16_word_wwll );
382 if (!thunk) return FALSE;
384 else thunk = (THUNK *)DCHook;
386 /* Free the previous thunk */
387 GetDCHook( hdc, (FARPROC16 *)&oldThunk );
388 if (oldThunk && (oldThunk != (THUNK *)DCHook)) THUNK_Free( oldThunk );
390 return SetDCHook( hdc, (FARPROC16)thunk, dwHookData );
394 /***********************************************************************
395 * THUNK_GetDCHook (GDI.191)
397 DWORD WINAPI THUNK_GetDCHook( HDC16 hdc, FARPROC16 *phookProc )
399 THUNK *thunk = NULL;
400 DWORD ret = GetDCHook( hdc, (FARPROC16 *)&thunk );
401 if (thunk)
403 if (thunk == (THUNK *)DCHook)
405 if (!defDCHookProc) /* Get DCHook Win16 entry point */
406 defDCHookProc = MODULE_GetEntryPoint(GetModuleHandle16("USER"),
407 362 );
408 *phookProc = defDCHookProc;
410 else *phookProc = thunk->proc;
412 return ret;
416 /***********************************************************************
417 * THUNK_SetTaskSignalProc (KERNEL.38)
419 FARPROC16 WINAPI THUNK_SetTaskSignalProc( HTASK16 hTask, FARPROC16 proc )
421 static FARPROC16 defSignalProc16 = NULL;
423 THUNK *thunk = NULL;
425 if( !defSignalProc16 )
426 defSignalProc16 = MODULE_GetEntryPoint(GetModuleHandle16("USER"), 314 );
428 if( proc == defSignalProc16 )
429 thunk = (THUNK*)SetTaskSignalProc( hTask, (FARPROC16)&USER_SignalProc );
430 else
432 thunk = THUNK_Alloc( proc, (RELAY)CallTo16_word_wwwww );
433 if( !thunk ) return FALSE;
434 thunk = (THUNK*)SetTaskSignalProc( hTask, (FARPROC16)thunk );
437 if( thunk != (THUNK*)USER_SignalProc )
439 if( !thunk ) return NULL;
441 proc = thunk->proc;
442 THUNK_Free( thunk );
443 return proc;
445 return defSignalProc16;
449 /***********************************************************************
450 * THUNK_SetResourceHandler (KERNEL.67)
452 FARPROC16 WINAPI THUNK_SetResourceHandler( HMODULE16 hModule, SEGPTR typeId, FARPROC16 proc )
454 /* loader/ne_resource.c */
455 extern HGLOBAL16 WINAPI NE_DefResourceHandler(HGLOBAL16,HMODULE16,HRSRC16);
457 static FARPROC16 defDIBIconLoader16 = NULL;
458 static FARPROC16 defDIBCursorLoader16 = NULL;
459 static FARPROC16 defResourceLoader16 = NULL;
461 THUNK *thunk = NULL;
463 if( !defResourceLoader16 )
465 HMODULE16 hUser = GetModuleHandle16("USER");
466 defDIBIconLoader16 = MODULE_GetEntryPoint( hUser, 357 );
467 defDIBCursorLoader16 = MODULE_GetEntryPoint( hUser, 356 );
468 defResourceLoader16 = MODULE_GetWndProcEntry16( "DefResourceHandler" );
471 if( proc == defResourceLoader16 )
472 thunk = (THUNK*)&NE_DefResourceHandler;
473 else if( proc == defDIBIconLoader16 )
474 thunk = (THUNK*)&LoadDIBIconHandler;
475 else if( proc == defDIBCursorLoader16 )
476 thunk = (THUNK*)&LoadDIBCursorHandler;
477 else
479 thunk = THUNK_Alloc( proc, (RELAY)CallTo16_word_www );
480 if( !thunk ) return FALSE;
483 thunk = (THUNK*)SetResourceHandler( hModule, typeId, (FARPROC16)thunk );
485 if( thunk == (THUNK*)&NE_DefResourceHandler )
486 return defResourceLoader16;
487 if( thunk == (THUNK*)&LoadDIBIconHandler )
488 return defDIBIconLoader16;
489 if( thunk == (THUNK*)&LoadDIBCursorHandler )
490 return defDIBCursorLoader16;
492 if( thunk )
494 proc = thunk->proc;
495 THUNK_Free( thunk );
496 return proc;
498 return NULL;
502 /***********************************************************************
504 * Win95 internal thunks *
506 ***********************************************************************/
508 /***********************************************************************
509 * Generates a FT_Prolog call.
511 * 0FB6D1 movzbl edx,cl
512 * 8B1495xxxxxxxx mov edx,[4*edx + xxxxxxxx]
513 * 68xxxxxxxx push FT_Prolog
514 * C3 lret
516 static void _write_ftprolog(LPBYTE start,DWORD thunkstart) {
517 LPBYTE x;
519 x = start;
520 *x++ = 0x0f;*x++=0xb6;*x++=0xd1; /* movzbl edx,cl */
521 *x++ = 0x8B;*x++=0x14;*x++=0x95;*(DWORD*)x= thunkstart;
522 x+=4; /* mov edx, [4*edx + thunkstart] */
523 *x++ = 0x68; *(DWORD*)x = (DWORD)GetProcAddress32(GetModuleHandle32A("KERNEL32"),"FT_Prolog");
524 x+=4; /* push FT_Prolog */
525 *x++ = 0xC3; /* lret */
526 /* fill rest with 0xCC / int 3 */
529 /***********************************************************************
530 * Generates a QT_Thunk style call.
532 * 33C9 xor ecx, ecx
533 * 8A4DFC mov cl , [ebp-04]
534 * 8B148Dxxxxxxxx mov edx, [4*ecx + (EAX+EDX)]
535 * B8yyyyyyyy mov eax, QT_Thunk
536 * FFE0 jmp eax
538 static void _write_qtthunk(LPBYTE start,DWORD thunkstart) {
539 LPBYTE x;
541 x = start;
542 *x++ = 0x33;*x++=0xC9; /* xor ecx,ecx */
543 *x++ = 0x8A;*x++=0x4D;*x++=0xFC; /* movb cl,[ebp-04] */
544 *x++ = 0x8B;*x++=0x14;*x++=0x8D;*(DWORD*)x= thunkstart;
545 x+=4; /* mov edx, [4*ecx + (EAX+EDX) */
546 *x++ = 0xB8; *(DWORD*)x = (DWORD)GetProcAddress32(GetModuleHandle32A("KERNEL32"),"QT_Thunk");
547 x+=4; /* mov eax , QT_Thunk */
548 *x++ = 0xFF; *x++ = 0xE0; /* jmp eax */
549 /* should fill the rest of the 32 bytes with 0xCC */
552 /***********************************************************************
553 * ThunkConnect32 (KERNEL32)
554 * Connects a 32bit and a 16bit thunkbuffer.
556 struct thunkstruct
558 char magic[4];
559 DWORD length;
560 DWORD ptr;
561 DWORD x0C;
563 DWORD x10;
564 DWORD x14;
565 DWORD x18;
566 DWORD x1C;
567 DWORD x20;
570 UINT32 WINAPI ThunkConnect32( struct thunkstruct *ths, LPSTR thunkfun16,
571 LPSTR module16, LPSTR module32, HMODULE32 hmod32,
572 DWORD dllinitarg1 )
574 HINSTANCE16 hmm;
575 SEGPTR thkbuf;
576 struct thunkstruct *ths16;
578 fprintf(stdnimp,"ThunkConnect32(<struct>,%s,%s,%s,%x,%lx)\n",
579 thunkfun16,module32,module16,hmod32,dllinitarg1
581 fprintf(stdnimp," magic = %c%c%c%c\n",
582 ths->magic[0],
583 ths->magic[1],
584 ths->magic[2],
585 ths->magic[3]
587 fprintf(stdnimp," length = %lx\n",ths->length);
588 if (lstrncmp32A(ths->magic,"SL01",4)&&lstrncmp32A(ths->magic,"LS01",4))
589 return 0;
590 hmm=LoadModule16(module16,NULL);
591 if (hmm<=32)
592 return 0;
593 thkbuf=(SEGPTR)WIN32_GetProcAddress16(hmm,thunkfun16);
594 if (!thkbuf)
595 return 0;
596 ths16=(struct thunkstruct*)PTR_SEG_TO_LIN(thkbuf);
597 if (lstrncmp32A(ths16->magic,ths->magic,4))
598 return 0;
600 if (!lstrncmp32A(ths->magic,"SL01",4)) {
601 if (ths16->length != ths->length)
602 return 0;
603 ths->x0C = (DWORD)ths16;
605 fprintf(stderr," ths16 magic is 0x%08lx\n",*(DWORD*)ths16->magic);
606 if (*((DWORD*)ths16->magic) != 0x0000304C)
607 return 0;
608 if (!*(WORD*)(((LPBYTE)ths16)+0x12))
609 return 0;
612 if (!lstrncmp32A(ths->magic,"LS01",4)) {
613 if (ths16->length != ths->length)
614 return 0;
615 ths->ptr = (DWORD)PTR_SEG_TO_LIN(ths16->ptr);
616 /* code offset for QT_Thunk is at 0x1C... */
617 _write_qtthunk (((LPBYTE)ths) + ths->x1C,ths->ptr);
618 /* code offset for FT_Prolog is at 0x20... */
619 _write_ftprolog(((LPBYTE)ths) + ths->x20,ths->ptr);
620 return 1;
622 return TRUE;
626 /**********************************************************************
627 * The infamous and undocumented QT_Thunk procedure.
629 * We get arguments in [EBP+8] up to [EBP+38].
630 * We have to set up a frame in the 16 bit stackframe.
631 * saved_ss_sp: bp+0x40
632 * bp+0x3c
633 * ...
634 * bp: bp+0x00
635 * sp:
638 VOID WINAPI QT_Thunk(CONTEXT *context)
640 CONTEXT context16;
641 LPBYTE curstack;
642 DWORD ret;
644 fprintf(stderr,"QT_Thunk(%08lx) ..",EDX_reg(context));
645 fprintf(stderr," argsize probably ebp-esp=%ld\n",
646 EBP_reg(context)-ESP_reg(context)
648 memcpy(&context16,context,sizeof(context16));
650 curstack = (LPBYTE)CURRENT_STACK16;
651 memcpy(curstack-0x44,(LPBYTE)EBP_reg(context),0x40);
652 EBP_reg(&context16) = LOWORD(IF1632_Saved16_ss_sp)-0x40;
653 CS_reg(&context16) = HIWORD(EDX_reg(context));
654 IP_reg(&context16) = LOWORD(EDX_reg(context));
655 #ifndef WINELIB
656 ret = CallTo16_regs_(&context16,-0x40);
657 #endif
658 fprintf(stderr,". returned %08lx\n",ret);
659 EAX_reg(context) = ret;
663 /**********************************************************************
664 * WOWCallback16 (KERNEL32.62)
666 DWORD WINAPI WOWCallback16(FARPROC16 fproc,DWORD arg)
668 DWORD ret;
669 fprintf(stderr,"WOWCallback16(%p,0x%08lx) ",fproc,arg);
670 ret = CallTo16_long_l(fproc,arg);
671 fprintf(stderr,"... returns %ld\n",ret);
672 return ret;
675 /***********************************************************************
676 * _KERNEL32_52 (KERNEL32.52)
677 * Returns a pointer to ThkBuf in the 16bit library SYSTHUNK.DLL.
679 LPVOID WINAPI _KERNEL32_52()
681 HMODULE32 hmod = LoadLibrary16("systhunk.dll");
682 DWORD ret;
684 fprintf(stderr,"_KERNE32_52()\n");
685 if (hmod<=32)
686 return 0;
688 ret = (DWORD)WIN32_GetProcAddress16(hmod,"ThkBuf");
690 fprintf(stderr," GetProcAddress16(0x%04x,\"ThkBuf\") returns %08lx\n",
691 hmod,ret
693 return PTR_SEG_TO_LIN(ret);
696 /***********************************************************************
697 * _KERNEL32_43 (KERNEL32.42)
698 * A thunkbuffer link routine
699 * The thunkbuf looks like:
701 * 00: DWORD length ? don't know exactly
702 * 04: SEGPTR ptr ? where does it point to?
703 * The pointer ptr is written into the first DWORD of 'thunk'.
704 * (probably correct implemented)
706 DWORD WINAPI _KERNEL32_43(LPDWORD thunk,LPCSTR thkbuf,DWORD len,
707 LPCSTR dll16,LPCSTR dll32)
709 HINSTANCE16 hmod;
710 LPDWORD addr;
711 SEGPTR segaddr;
713 fprintf(stderr,"_KERNEL32_43(%p,%s,0x%08lx,%s,%s)\n",thunk,thkbuf,len,dll16,dll32);
715 hmod = LoadLibrary16(dll16);
716 if (hmod<32) {
717 fprintf(stderr,"->failed to load 16bit DLL %s, error %d\n",dll16,hmod);
718 return 0;
720 segaddr = (DWORD)WIN32_GetProcAddress16(hmod,(LPSTR)thkbuf);
721 if (!segaddr) {
722 fprintf(stderr,"->no %s exported from %s!\n",thkbuf,dll16);
723 return 0;
725 addr = (LPDWORD)PTR_SEG_TO_LIN(segaddr);
726 if (addr[0] != len) {
727 fprintf(stderr,"->thkbuf length mismatch? %ld vs %ld\n",len,addr[0]);
728 return 0;
730 if (!addr[1])
731 return 0;
732 fprintf(stderr," addr[1] is %08lx\n",addr[1]);
733 *(DWORD*)thunk = addr[1];
734 return addr[1];
737 /***********************************************************************
738 * _KERNEL32_45 (KERNEL32.44)
739 * Looks like another 32->16 thunk. Dunno why they need two of them.
740 * calls the win16 address in EAX with the current stack.
742 * FIXME: doesn't seem to work correctly yet...
744 VOID WINAPI _KERNEL32_45(CONTEXT *context)
746 CONTEXT context16;
747 LPBYTE curstack;
748 DWORD ret,stacksize;
750 fprintf(stderr,"KERNEL32_45(%%eax=0x%08lx(%%cx=0x%04lx,%%edx=0x%08lx))\n",
751 (DWORD)EAX_reg(context),(DWORD)CX_reg(context),(DWORD)EDX_reg(context)
753 stacksize = EBP_reg(context)-ESP_reg(context);
754 fprintf(stderr," stacksize = %ld\n",stacksize);
756 memcpy(&context16,context,sizeof(context16));
758 curstack = (LPBYTE)CURRENT_STACK16;
759 memcpy(curstack-stacksize-4,(LPBYTE)EBP_reg(context),stacksize);
760 fprintf(stderr,"IF1632_Saved16_ss_sp is 0x%08lx\n",IF1632_Saved16_ss_sp);
761 EBP_reg(&context16) = LOWORD(IF1632_Saved16_ss_sp)-stacksize;
762 DI_reg(&context16) = CX_reg(context);
763 CS_reg(&context16) = HIWORD(EAX_reg(context));
764 IP_reg(&context16) = LOWORD(EAX_reg(context));
765 /* some more registers spronged locally, but I don't think they are
766 * needed
768 #ifndef WINELIB
769 ret = CallTo16_regs_(&context16,-stacksize);
770 #endif
771 fprintf(stderr,". returned %08lx\n",ret);
772 EAX_reg(context) = ret;
775 /***********************************************************************
776 * (KERNEL32.40)
777 * A thunk setup routine.
778 * Expects a pointer to a preinitialized thunkbuffer in the first argument
779 * looking like:
780 * 00..03: unknown (pointer, check _41, _43, _46)
781 * 04: EB1E jmp +0x20
783 * 06..23: unknown (space for replacement code, check .90)
785 * 24:>E800000000 call offset 29
786 * 29:>58 pop eax ( target of call )
787 * 2A: 2D25000000 sub eax,0x00000025 ( now points to offset 4 )
788 * 2F: BAxxxxxxxx mov edx,xxxxxxxx
789 * 34: 68yyyyyyyy push KERNEL32.90
790 * 39: C3 ret
792 * 3A: EB1E jmp +0x20
793 * 3E ... 59: unknown (space for replacement code?)
794 * 5A: E8xxxxxxxx call <32bitoffset xxxxxxxx>
795 * 5F: 5A pop edx
796 * 60: 81EA25xxxxxx sub edx, 0x25xxxxxx
797 * 66: 52 push edx
798 * 67: 68xxxxxxxx push xxxxxxxx
799 * 6C: 68yyyyyyyy push KERNEL32.89
800 * 71: C3 ret
801 * 72: end?
802 * This function checks if the code is there, and replaces the yyyyyyyy entries
803 * by the functionpointers.
804 * The thunkbuf looks like:
806 * 00: DWORD length ? don't know exactly
807 * 04: SEGPTR ptr ? where does it point to?
808 * The segpointer ptr is written into the first DWORD of 'thunk'.
809 * (probably correct implemented)
812 LPVOID WINAPI _KERNEL32_41(LPBYTE thunk,LPCSTR thkbuf,DWORD len,LPCSTR dll16,
813 LPCSTR dll32)
815 HMODULE32 hkrnl32 = GetModuleHandle32A("KERNEL32");
816 HMODULE16 hmod;
817 LPDWORD addr,addr2;
818 DWORD segaddr;
820 fprintf(stderr,"KERNEL32_41(%p,%s,%ld,%s,%s)\n",
821 thunk,thkbuf,len,dll16,dll32
824 /* FIXME: add checks for valid code ... */
825 /* write pointers to kernel32.89 and kernel32.90 (+ordinal base of 1) */
826 *(DWORD*)(thunk+0x35) = (DWORD)GetProcAddress32(hkrnl32,(LPSTR)90);
827 *(DWORD*)(thunk+0x6D) = (DWORD)GetProcAddress32(hkrnl32,(LPSTR)89);
830 hmod = LoadLibrary16(dll16);
831 if (hmod<32) {
832 fprintf(stderr,"->failed to load 16bit DLL %s, error %d\n",dll16,hmod);
833 return NULL;
835 segaddr = (DWORD)WIN32_GetProcAddress16(hmod,(LPSTR)thkbuf);
836 if (!segaddr) {
837 fprintf(stderr,"->no %s exported from %s!\n",thkbuf,dll16);
838 return NULL;
840 addr = (LPDWORD)PTR_SEG_TO_LIN(segaddr);
841 if (addr[0] != len) {
842 fprintf(stderr,"->thkbuf length mismatch? %ld vs %ld\n",len,addr[0]);
843 return NULL;
845 addr2 = PTR_SEG_TO_LIN(addr[1]);
846 fprintf(stderr," addr2 is %08lx:%p\n",addr[1],addr2);
847 if (HIWORD(addr2))
848 *(DWORD*)thunk = (DWORD)addr2;
849 return addr2;
852 /***********************************************************************
853 * (KERNEL32.91)
854 * Thunk priming? function
855 * Rewrites the first part of the thunk to use the QT_Thunk interface
856 * and jumps to the start of that code.
858 VOID WINAPI _KERNEL32_90(CONTEXT *context)
860 fprintf(stderr,"_KERNEL32_90(eax=0x%08lx,edx=0x%08lx,ebp[-4]=0x%02x,target = %08lx, *target =%08lx)\n",
861 EAX_reg(context),EDX_reg(context),((BYTE*)EBP_reg(context))[-4],
862 (*(DWORD*)(EAX_reg(context)+EDX_reg(context)))+4*(((BYTE*)EBP_reg(context))[-4]),
863 *(DWORD*)((*(DWORD*)(EAX_reg(context)+EDX_reg(context)))+4*(((BYTE*)EBP_reg(context))[-4]))
865 _write_qtthunk((LPBYTE)EAX_reg(context),*(DWORD*)(EAX_reg(context)+EDX_reg(context)));
866 /* we just call the real QT_Thunk right now
867 * we can bypass the relaycode, for we already have the registercontext
869 EDX_reg(context) = *(DWORD*)((*(DWORD*)(EAX_reg(context)+EDX_reg(context)))+4*(((BYTE*)EBP_reg(context))[-4]));
870 return QT_Thunk(context);
873 /***********************************************************************
874 * (KERNEL32.45)
875 * Another thunkbuf link routine.
876 * The start of the thunkbuf looks like this:
877 * 00: DWORD length
878 * 04: SEGPTR address for thunkbuffer pointer
880 VOID WINAPI _KERNEL32_46(LPBYTE thunk,LPSTR thkbuf,DWORD len,LPSTR dll16,
881 LPSTR dll32)
883 LPDWORD addr;
884 HMODULE16 hmod;
885 SEGPTR segaddr;
887 fprintf(stderr,"KERNEL32_46(%p,%s,%lx,%s,%s)\n",
888 thunk,thkbuf,len,dll16,dll32
890 hmod = LoadLibrary16(dll16);
891 if (hmod < 32) {
892 fprintf(stderr,"->couldn't load %s, error %d\n",dll16,hmod);
893 return;
895 segaddr = (SEGPTR)WIN32_GetProcAddress16(hmod,thkbuf);
896 if (!segaddr) {
897 fprintf(stderr,"-> haven't found %s in %s!\n",thkbuf,dll16);
898 return;
900 addr = (LPDWORD)PTR_SEG_TO_LIN(segaddr);
901 if (addr[0] != len) {
902 fprintf(stderr,"-> length of thkbuf differs from expected length! (%ld vs %ld)\n",addr[0],len);
903 return;
905 *(DWORD*)PTR_SEG_TO_LIN(addr[1]) = (DWORD)thunk;
908 /**********************************************************************
909 * _KERNEL32_87
910 * Check if thunking is initialized (ss selector set up etc.)
912 BOOL32 WINAPI _KERNEL32_87()
914 fprintf(stderr,"KERNEL32_87 stub, returning TRUE\n");
915 return TRUE;
918 /**********************************************************************
919 * _KERNEL32_88
920 * One of the real thunking functions. This one seems to be for 32<->32
921 * thunks. It should probably be capable of crossing processboundaries.
923 * And YES, I've seen nr=48 (somewhere in the Win95 32<->16 OLE coupling)
925 DWORD WINAPIV _KERNEL32_88( DWORD nr, DWORD flags, FARPROC32 fun, ... )
927 DWORD i,ret;
928 DWORD *args = ((DWORD *)&fun) + 1;
930 fprintf(stderr,"KERNEL32_88(%ld,0x%08lx,%p,[ ",nr,flags,fun);
931 for (i=0;i<nr/4;i++) fprintf(stderr,"0x%08lx,",args[i]);
932 fprintf(stderr,"])");
933 switch (nr) {
934 case 0: ret = fun();
935 break;
936 case 4: ret = fun(args[0]);
937 break;
938 case 8: ret = fun(args[0],args[1]);
939 break;
940 case 12: ret = fun(args[0],args[1],args[2]);
941 break;
942 case 16: ret = fun(args[0],args[1],args[2],args[3]);
943 break;
944 case 20: ret = fun(args[0],args[1],args[2],args[3],args[4]);
945 break;
946 case 24: ret = fun(args[0],args[1],args[2],args[3],args[4],args[5]);
947 break;
948 case 28: ret = fun(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
949 break;
950 case 32: ret = fun(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
951 break;
952 case 36: ret = fun(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
953 break;
954 case 40: ret = fun(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
955 break;
956 case 44: ret = fun(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
957 break;
958 case 48: ret = fun(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11]);
959 break;
960 default:
961 fprintf(stderr," unsupported nr of arguments, %ld\n",nr);
962 ret = 0;
963 break;
966 fprintf(stderr," returning %ld ...\n",ret);
967 return ret;
970 /**********************************************************************
971 * KERNEL_619 (KERNEL)
972 * Seems to store y and z depending on x in some internal lists...
974 WORD WINAPI _KERNEL_619(WORD x,DWORD y,DWORD z)
976 fprintf(stderr,"KERNEL_619(0x%04x,0x%08lx,0x%08lx)\n",x,y,z);
977 return x;
980 /**********************************************************************
981 * AllocSLCallback (KERNEL32)
983 * Win95 uses some structchains for callbacks. It allocates them
984 * in blocks of 100 entries, size 32 bytes each, layout:
985 * blockstart:
986 * 0: PTR nextblockstart
987 * 4: entry *first;
988 * 8: WORD sel ( start points to blockstart)
989 * A: WORD unknown
990 * 100xentry:
991 * 00..17: Code
992 * 18: PDB *owning_process;
993 * 1C: PTR blockstart
995 * We ignore this for now. (Just a note for further developers)
996 * FIXME: use this method, so we don't waste selectors...
998 * Following code is then generated by AllocSLCallback. The code is 16 bit, so
999 * the 0x66 prefix switches from word->long registers.
1001 * 665A pop edx
1002 * 6668x arg2 x pushl <arg2>
1003 * 6652 push edx
1004 * EAx arg1 x jmpf <arg1>
1006 * returns the startaddress of this thunk.
1008 * Note, that they look very similair to the ones allocates by THUNK_Alloc.
1010 DWORD WINAPI
1011 AllocSLCallback(DWORD finalizer,DWORD callback) {
1012 LPBYTE x,thunk = HeapAlloc( GetProcessHeap(), 0, 32 );
1013 WORD sel;
1015 x=thunk;
1016 *x++=0x66;*x++=0x5a; /* popl edx */
1017 *x++=0x66;*x++=0x68;*(DWORD*)x=finalizer;x+=4; /* pushl finalizer */
1018 *x++=0x66;*x++=0x52; /* pushl edx */
1019 *x++=0xea;*(DWORD*)x=callback;x+=4; /* jmpf callback */
1021 *(DWORD*)(thunk+18) = GetCurrentProcessId();
1023 sel = SELECTOR_AllocBlock( thunk , 32, SEGMENT_CODE, FALSE, FALSE );
1024 return (sel<<16)|0;
1027 void WINAPI
1028 FreeSLCallback(DWORD x) {
1029 fprintf(stderr,"FreeSLCallback(0x%08lx)\n",x);
1032 /**********************************************************************
1033 * KERNEL_358 (KERNEL)
1034 * Allocates a code segment which starts at the address passed in x. limit
1035 * 0xfffff, and returns the pointer to the start.
1037 DWORD WINAPI
1038 _KERNEL_358(DWORD x) {
1039 WORD sel;
1041 fprintf(stderr,"_KERNEL_358(0x%08lx),stub\n",x);
1042 if (!HIWORD(x))
1043 return x;
1045 sel = SELECTOR_AllocBlock( PTR_SEG_TO_LIN(x) , 0xffff, SEGMENT_CODE, FALSE, FALSE );
1046 return (sel<<16)|(0x0000);
1049 /**********************************************************************
1050 * KERNEL_359 (KERNEL)
1051 * Frees the code segment of the passed linear pointer (This has usually
1052 * been allocated by _KERNEL_358).
1054 VOID WINAPI
1055 _KERNEL_359(DWORD x) {
1056 DWORD savedsssp;
1058 fprintf(stderr,"_KERNEL_359(0x%08lx),stub\n",x);
1059 if ((HIWORD(x) & 7)!=7)
1060 return;
1061 savedsssp = IF1632_Saved16_ss_sp;IF1632_Saved16_ss_sp = 0;
1062 SELECTOR_FreeBlock(x>>16,1);
1063 IF1632_Saved16_ss_sp = savedsssp;
1064 return;
1067 /**********************************************************************
1068 * KERNEL_472 (KERNEL)
1069 * something like GetCurrenthInstance.
1071 VOID WINAPI
1072 _KERNEL_472(CONTEXT *context) {
1073 fprintf(stderr,"_KERNEL_472(0x%08lx),stub\n",EAX_reg(context));
1074 if (!EAX_reg(context)) {
1075 TDB *pTask = (TDB*)GlobalLock16(GetCurrentTask());
1076 AX_reg(context)=pTask->hInstance;
1077 return;
1079 if (!HIWORD(EAX_reg(context)))
1080 return; /* returns the passed value */
1081 /* hmm ... fixme */