Release 970914
[wine.git] / if1632 / thunk.c
blob901a9bbc7cf6a95c9d3654e070b8d7dc05297a4b
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 "except.h"
19 #include "stddebug.h"
20 #include "debug.h"
22 typedef void (*RELAY)();
24 #pragma pack(1)
26 typedef struct tagTHUNK
28 BYTE popl_eax; /* 0x58 popl %eax (return address)*/
29 BYTE pushl_func; /* 0x68 pushl $proc */
30 FARPROC32 proc WINE_PACKED;
31 BYTE pushl_eax; /* 0x50 pushl %eax */
32 BYTE jmp; /* 0xe9 jmp relay (relative jump)*/
33 RELAY relay WINE_PACKED;
34 struct tagTHUNK *next WINE_PACKED;
35 } THUNK;
37 #pragma pack(4)
39 #define DECL_THUNK(name,proc,relay) \
40 THUNK name = { 0x58, 0x68, (FARPROC32)(proc), 0x50, 0xe9, \
41 (RELAY)((char *)(relay) - (char *)(&(name).next)), NULL }
44 static THUNK *firstThunk = NULL;
46 static LRESULT THUNK_CallWndProc16( WNDPROC16 proc, HWND16 hwnd, UINT16 msg,
47 WPARAM16 wParam, LPARAM lParam );
49 /***********************************************************************
50 * THUNK_Init
52 BOOL32 THUNK_Init(void)
54 /* Set the window proc calling functions */
55 WINPROC_SetCallWndProc16( THUNK_CallWndProc16 );
56 return TRUE;
60 /***********************************************************************
61 * THUNK_Alloc
63 static THUNK *THUNK_Alloc( FARPROC32 func, RELAY relay )
65 THUNK *thunk = HeapAlloc( GetProcessHeap(), 0, sizeof(*thunk) );
66 if (thunk)
68 thunk->popl_eax = 0x58;
69 thunk->pushl_func = 0x68;
70 thunk->proc = func;
71 thunk->pushl_eax = 0x50;
72 thunk->jmp = 0xe9;
73 thunk->relay = (RELAY)((char *)relay - (char *)(&thunk->next));
74 thunk->next = firstThunk;
75 firstThunk = thunk;
77 return thunk;
81 /***********************************************************************
82 * THUNK_Find
84 static THUNK *THUNK_Find( FARPROC32 func )
86 THUNK *thunk = firstThunk;
87 while (thunk && (thunk->proc != func)) thunk = thunk->next;
88 return thunk;
92 /***********************************************************************
93 * THUNK_Free
95 static void THUNK_Free( THUNK *thunk )
97 if (HEAP_IsInsideHeap( GetProcessHeap(), 0, thunk ))
99 THUNK **prev = &firstThunk;
100 while (*prev && (*prev != thunk)) prev = &(*prev)->next;
101 if (*prev)
103 *prev = thunk->next;
104 HeapFree( GetProcessHeap(), 0, thunk );
105 return;
108 fprintf( stderr, "THUNK_Free: invalid thunk addr %p\n", thunk );
112 /***********************************************************************
113 * THUNK_CallWndProc16
115 * Call a 16-bit window procedure
117 static LRESULT THUNK_CallWndProc16( WNDPROC16 proc, HWND16 hwnd, UINT16 msg,
118 WPARAM16 wParam, LPARAM lParam )
120 if (((msg == WM_CREATE) || (msg == WM_NCCREATE)) && lParam)
122 CREATESTRUCT16 *cs = (CREATESTRUCT16 *)PTR_SEG_TO_LIN(lParam);
123 /* Build the CREATESTRUCT on the 16-bit stack. */
124 /* This is really ugly, but some programs (notably the */
125 /* "Undocumented Windows" examples) want it that way. */
126 return CallTo16_wndp_lllllllwlwwwl( (FARPROC16)proc,
127 cs->dwExStyle, cs->lpszClass, cs->lpszName, cs->style,
128 MAKELONG( cs->y, cs->x ), MAKELONG( cs->cy, cs->cx ),
129 MAKELONG( cs->hMenu, cs->hwndParent ), cs->hInstance,
130 (LONG)cs->lpCreateParams, hwnd, msg, wParam,
131 IF1632_Saved16_ss_sp - sizeof(CREATESTRUCT16) );
133 return CallTo16_wndp_wwwl( (FARPROC16)proc, hwnd, msg, wParam, lParam );
137 /***********************************************************************
138 * THUNK_EnumObjects16 (GDI.71)
140 INT16 WINAPI THUNK_EnumObjects16( HDC16 hdc, INT16 nObjType,
141 GOBJENUMPROC16 func, LPARAM lParam )
143 DECL_THUNK( thunk, func, CallTo16_word_ll );
144 return EnumObjects16( hdc, nObjType, (GOBJENUMPROC16)&thunk, lParam );
148 /*************************************************************************
149 * THUNK_EnumFonts16 (GDI.70)
151 INT16 WINAPI THUNK_EnumFonts16( HDC16 hdc, LPCSTR lpFaceName,
152 FONTENUMPROC16 func, LPARAM lParam )
154 DECL_THUNK( thunk, func, CallTo16_word_llwl );
155 return EnumFonts16( hdc, lpFaceName, (FONTENUMPROC16)&thunk, lParam );
158 /******************************************************************
159 * THUNK_EnumMetaFile16 (GDI.175)
161 BOOL16 WINAPI THUNK_EnumMetaFile16( HDC16 hdc, HMETAFILE16 hmf,
162 MFENUMPROC16 func, LPARAM lParam )
164 DECL_THUNK( thunk, func, CallTo16_word_wllwl );
165 return EnumMetaFile16( hdc, hmf, (MFENUMPROC16)&thunk, lParam );
169 /*************************************************************************
170 * THUNK_EnumFontFamilies16 (GDI.330)
172 INT16 WINAPI THUNK_EnumFontFamilies16( HDC16 hdc, LPCSTR lpszFamily,
173 FONTENUMPROC16 func, LPARAM lParam )
175 DECL_THUNK( thunk, func, CallTo16_word_llwl );
176 return EnumFontFamilies16(hdc, lpszFamily, (FONTENUMPROC16)&thunk, lParam);
180 /*************************************************************************
181 * THUNK_EnumFontFamiliesEx16 (GDI.613)
183 INT16 WINAPI THUNK_EnumFontFamiliesEx16( HDC16 hdc, LPLOGFONT16 lpLF,
184 FONTENUMPROCEX16 func, LPARAM lParam,
185 DWORD reserved )
187 DECL_THUNK( thunk, func, CallTo16_word_llwl );
188 return EnumFontFamiliesEx16( hdc, lpLF, (FONTENUMPROCEX16)&thunk,
189 lParam, reserved );
193 /**********************************************************************
194 * THUNK_LineDDA16 (GDI.100)
196 void WINAPI THUNK_LineDDA16( INT16 nXStart, INT16 nYStart, INT16 nXEnd,
197 INT16 nYEnd, LINEDDAPROC16 func, LPARAM lParam )
199 DECL_THUNK( thunk, func, CallTo16_word_wwl );
200 LineDDA16( nXStart, nYStart, nXEnd, nYEnd, (LINEDDAPROC16)&thunk, lParam );
204 /*******************************************************************
205 * THUNK_EnumWindows16 (USER.54)
207 BOOL16 WINAPI THUNK_EnumWindows16( WNDENUMPROC16 func, LPARAM lParam )
209 DECL_THUNK( thunk, func, CallTo16_word_wl );
210 return EnumWindows16( (WNDENUMPROC16)&thunk, lParam );
214 /**********************************************************************
215 * THUNK_EnumChildWindows16 (USER.55)
217 BOOL16 WINAPI THUNK_EnumChildWindows16( HWND16 parent, WNDENUMPROC16 func,
218 LPARAM lParam )
220 DECL_THUNK( thunk, func, CallTo16_word_wl );
221 return EnumChildWindows16( parent, (WNDENUMPROC16)&thunk, lParam );
225 /**********************************************************************
226 * THUNK_EnumTaskWindows16 (USER.225)
228 BOOL16 WINAPI THUNK_EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
229 LPARAM lParam )
231 DECL_THUNK( thunk, func, CallTo16_word_wl );
232 return EnumTaskWindows16( hTask, (WNDENUMPROC16)&thunk, lParam );
236 /***********************************************************************
237 * THUNK_EnumProps16 (USER.27)
239 INT16 WINAPI THUNK_EnumProps16( HWND16 hwnd, PROPENUMPROC16 func )
241 DECL_THUNK( thunk, func, CallTo16_word_wlw );
242 return EnumProps16( hwnd, (PROPENUMPROC16)&thunk );
246 /***********************************************************************
247 * THUNK_GrayString16 (USER.185)
249 BOOL16 WINAPI THUNK_GrayString16( HDC16 hdc, HBRUSH16 hbr,
250 GRAYSTRINGPROC16 func, LPARAM lParam,
251 INT16 cch, INT16 x, INT16 y,
252 INT16 cx, INT16 cy )
254 DECL_THUNK( thunk, func, CallTo16_word_wlw );
255 if (!func)
256 return GrayString16( hdc, hbr, NULL, lParam, cch, x, y, cx, cy );
257 else
258 return GrayString16( hdc, hbr, (GRAYSTRINGPROC16)&thunk, lParam, cch,
259 x, y, cx, cy );
263 /***********************************************************************
264 * THUNK_SetWindowsHook16 (USER.121)
266 FARPROC16 WINAPI THUNK_SetWindowsHook16( INT16 id, HOOKPROC16 proc )
268 HINSTANCE16 hInst = FarGetOwner( HIWORD(proc) );
269 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
270 THUNK *thunk = THUNK_Alloc( (FARPROC16)proc, (RELAY)CallTo16_long_wwl );
271 if (!thunk) return 0;
272 return (FARPROC16)SetWindowsHookEx16( id, (HOOKPROC16)thunk, hInst, hTask);
276 /***********************************************************************
277 * THUNK_UnhookWindowsHook16 (USER.234)
279 BOOL16 WINAPI THUNK_UnhookWindowsHook16( INT16 id, HOOKPROC16 proc )
281 BOOL16 ret;
282 THUNK *thunk = THUNK_Find( (FARPROC16)proc );
283 if (!thunk) return FALSE;
284 ret = UnhookWindowsHook16( id, (HOOKPROC16)thunk );
285 THUNK_Free( thunk );
286 return ret;
290 /***********************************************************************
291 * THUNK_SetWindowsHookEx16 (USER.291)
293 HHOOK WINAPI THUNK_SetWindowsHookEx16( INT16 id, HOOKPROC16 proc,
294 HINSTANCE16 hInst, HTASK16 hTask )
296 THUNK *thunk = THUNK_Alloc( (FARPROC16)proc, (RELAY)CallTo16_long_wwl );
297 if (!thunk) return 0;
298 return SetWindowsHookEx16( id, (HOOKPROC16)thunk, hInst, hTask );
302 /***********************************************************************
303 * THUNK_UnhookWindowHookEx16 (USER.292)
305 BOOL16 WINAPI THUNK_UnhookWindowsHookEx16( HHOOK hhook )
307 THUNK *thunk = (THUNK *)HOOK_GetProc16( hhook );
308 BOOL16 ret = UnhookWindowsHookEx16( hhook );
309 if (thunk) THUNK_Free( thunk );
310 return ret;
314 /***********************************************************************
315 * THUNK_CreateSystemTimer (SYSTEM.2)
317 WORD WINAPI THUNK_CreateSystemTimer( WORD rate, FARPROC16 callback )
319 THUNK *thunk = THUNK_Alloc( callback, (RELAY)CallTo16_word_ );
320 if (!thunk) return 0;
321 return CreateSystemTimer( rate, (FARPROC16)thunk );
325 /***********************************************************************
326 * THUNK_KillSystemTimer (SYSTEM.3)
328 WORD WINAPI THUNK_KillSystemTimer( WORD timer )
330 extern WORD SYSTEM_KillSystemTimer( WORD timer ); /* misc/system.c */
331 extern FARPROC16 SYSTEM_GetTimerProc( WORD timer ); /* misc/system.c */
333 THUNK *thunk = (THUNK *)SYSTEM_GetTimerProc( timer );
334 WORD ret = SYSTEM_KillSystemTimer( timer );
335 if (thunk) THUNK_Free( thunk );
336 return ret;
340 static FARPROC16 defDCHookProc = NULL;
342 /***********************************************************************
343 * THUNK_SetDCHook (GDI.190)
345 BOOL16 WINAPI THUNK_SetDCHook( HDC16 hdc, FARPROC16 proc, DWORD dwHookData )
347 THUNK *thunk, *oldThunk;
349 if (!defDCHookProc) /* Get DCHook Win16 entry point */
350 defDCHookProc = MODULE_GetEntryPoint( GetModuleHandle16("USER"), 362 );
352 if (proc != defDCHookProc)
354 thunk = THUNK_Alloc( proc, (RELAY)CallTo16_word_wwll );
355 if (!thunk) return FALSE;
357 else thunk = (THUNK *)DCHook;
359 /* Free the previous thunk */
360 GetDCHook( hdc, (FARPROC16 *)&oldThunk );
361 if (oldThunk && (oldThunk != (THUNK *)DCHook)) THUNK_Free( oldThunk );
363 return SetDCHook( hdc, (FARPROC16)thunk, dwHookData );
367 /***********************************************************************
368 * THUNK_GetDCHook (GDI.191)
370 DWORD WINAPI THUNK_GetDCHook( HDC16 hdc, FARPROC16 *phookProc )
372 THUNK *thunk = NULL;
373 DWORD ret = GetDCHook( hdc, (FARPROC16 *)&thunk );
374 if (thunk)
376 if (thunk == (THUNK *)DCHook)
378 if (!defDCHookProc) /* Get DCHook Win16 entry point */
379 defDCHookProc = MODULE_GetEntryPoint(GetModuleHandle16("USER"),
380 362 );
381 *phookProc = defDCHookProc;
383 else *phookProc = thunk->proc;
385 return ret;
389 /***********************************************************************
390 * THUNK_SetTaskSignalProc (KERNEL.38)
392 FARPROC16 WINAPI THUNK_SetTaskSignalProc( HTASK16 hTask, FARPROC16 proc )
394 static FARPROC16 defSignalProc16 = NULL;
396 THUNK *thunk = NULL;
398 if( !defSignalProc16 )
399 defSignalProc16 = MODULE_GetEntryPoint(GetModuleHandle16("USER"), 314 );
401 if( proc == defSignalProc16 )
402 thunk = (THUNK*)SetTaskSignalProc( hTask, (FARPROC16)&USER_SignalProc );
403 else
405 thunk = THUNK_Alloc( proc, (RELAY)CallTo16_word_wwwww );
406 if( !thunk ) return FALSE;
407 thunk = (THUNK*)SetTaskSignalProc( hTask, (FARPROC16)thunk );
410 if( thunk != (THUNK*)USER_SignalProc )
412 if( !thunk ) return NULL;
414 proc = thunk->proc;
415 THUNK_Free( thunk );
416 return proc;
418 return defSignalProc16;
422 /***********************************************************************
423 * THUNK_SetResourceHandler (KERNEL.67)
425 FARPROC16 WINAPI THUNK_SetResourceHandler( HMODULE16 hModule, SEGPTR typeId, FARPROC16 proc )
427 /* loader/ne_resource.c */
428 extern HGLOBAL16 WINAPI NE_DefResourceHandler(HGLOBAL16,HMODULE16,HRSRC16);
430 static FARPROC16 defDIBIconLoader16 = NULL;
431 static FARPROC16 defDIBCursorLoader16 = NULL;
432 static FARPROC16 defResourceLoader16 = NULL;
434 THUNK *thunk = NULL;
436 if( !defResourceLoader16 )
438 HMODULE16 hUser = GetModuleHandle16("USER");
439 defDIBIconLoader16 = MODULE_GetEntryPoint( hUser, 357 );
440 defDIBCursorLoader16 = MODULE_GetEntryPoint( hUser, 356 );
441 defResourceLoader16 = MODULE_GetWndProcEntry16( "DefResourceHandler" );
444 if( proc == defResourceLoader16 )
445 thunk = (THUNK*)&NE_DefResourceHandler;
446 else if( proc == defDIBIconLoader16 )
447 thunk = (THUNK*)&LoadDIBIconHandler;
448 else if( proc == defDIBCursorLoader16 )
449 thunk = (THUNK*)&LoadDIBCursorHandler;
450 else
452 thunk = THUNK_Alloc( proc, (RELAY)CallTo16_word_www );
453 if( !thunk ) return FALSE;
456 thunk = (THUNK*)SetResourceHandler( hModule, typeId, (FARPROC16)thunk );
458 if( thunk == (THUNK*)&NE_DefResourceHandler )
459 return defResourceLoader16;
460 if( thunk == (THUNK*)&LoadDIBIconHandler )
461 return defDIBIconLoader16;
462 if( thunk == (THUNK*)&LoadDIBCursorHandler )
463 return defDIBCursorLoader16;
465 if( thunk )
467 proc = thunk->proc;
468 THUNK_Free( thunk );
469 return proc;
471 return NULL;
475 /***********************************************************************
477 * Win95 internal thunks *
479 ***********************************************************************/
481 /***********************************************************************
482 * Generates a FT_Prolog call.
484 * 0FB6D1 movzbl edx,cl
485 * 8B1495xxxxxxxx mov edx,[4*edx + xxxxxxxx]
486 * 68xxxxxxxx push FT_Prolog
487 * C3 lret
489 static void _write_ftprolog(LPBYTE start,DWORD thunkstart) {
490 LPBYTE x;
492 x = start;
493 *x++ = 0x0f;*x++=0xb6;*x++=0xd1; /* movzbl edx,cl */
494 *x++ = 0x8B;*x++=0x14;*x++=0x95;*(DWORD*)x= thunkstart;
495 x+=4; /* mov edx, [4*edx + thunkstart] */
496 *x++ = 0x68; *(DWORD*)x = (DWORD)GetProcAddress32(GetModuleHandle32A("KERNEL32"),"FT_Prolog");
497 x+=4; /* push FT_Prolog */
498 *x++ = 0xC3; /* lret */
499 /* fill rest with 0xCC / int 3 */
502 /***********************************************************************
503 * Generates a QT_Thunk style call.
505 * 33C9 xor ecx, ecx
506 * 8A4DFC mov cl , [ebp-04]
507 * 8B148Dxxxxxxxx mov edx, [4*ecx + (EAX+EDX)]
508 * B8yyyyyyyy mov eax, QT_Thunk
509 * FFE0 jmp eax
511 static void _write_qtthunk(LPBYTE start,DWORD thunkstart) {
512 LPBYTE x;
514 x = start;
515 *x++ = 0x33;*x++=0xC9; /* xor ecx,ecx */
516 *x++ = 0x8A;*x++=0x4D;*x++=0xFC; /* movb cl,[ebp-04] */
517 *x++ = 0x8B;*x++=0x14;*x++=0x8D;*(DWORD*)x= thunkstart;
518 x+=4; /* mov edx, [4*ecx + (EAX+EDX) */
519 *x++ = 0xB8; *(DWORD*)x = (DWORD)GetProcAddress32(GetModuleHandle32A("KERNEL32"),"QT_Thunk");
520 x+=4; /* mov eax , QT_Thunk */
521 *x++ = 0xFF; *x++ = 0xE0; /* jmp eax */
522 /* should fill the rest of the 32 bytes with 0xCC */
525 /***********************************************************************
526 * ThunkConnect32 (KERNEL32)
527 * Connects a 32bit and a 16bit thunkbuffer.
529 struct thunkstruct
531 char magic[4];
532 DWORD length;
533 DWORD ptr;
534 DWORD x0C;
536 DWORD x10;
537 DWORD x14;
538 DWORD x18;
539 DWORD x1C;
540 DWORD x20;
543 UINT32 WINAPI ThunkConnect32( struct thunkstruct *ths, LPSTR thunkfun16,
544 LPSTR module16, LPSTR module32, HMODULE32 hmod32,
545 DWORD dllinitarg1 )
547 HINSTANCE16 hmm;
548 SEGPTR thkbuf;
549 struct thunkstruct *ths16;
551 fprintf(stdnimp,"ThunkConnect32(<struct>,%s,%s,%s,%x,%lx)\n",
552 thunkfun16,module32,module16,hmod32,dllinitarg1
554 fprintf(stdnimp," magic = %c%c%c%c\n",
555 ths->magic[0],
556 ths->magic[1],
557 ths->magic[2],
558 ths->magic[3]
560 fprintf(stdnimp," length = %lx\n",ths->length);
561 if (lstrncmp32A(ths->magic,"SL01",4)&&lstrncmp32A(ths->magic,"LS01",4))
562 return 0;
563 hmm=LoadModule16(module16,NULL);
564 if (hmm<=32)
565 return 0;
566 thkbuf=(SEGPTR)WIN32_GetProcAddress16(hmm,thunkfun16);
567 if (!thkbuf)
568 return 0;
569 ths16=(struct thunkstruct*)PTR_SEG_TO_LIN(thkbuf);
570 if (lstrncmp32A(ths16->magic,ths->magic,4))
571 return 0;
573 if (!lstrncmp32A(ths->magic,"SL01",4)) {
574 if (ths16->length != ths->length)
575 return 0;
576 ths->x0C = (DWORD)ths16;
578 fprintf(stderr," ths16 magic is 0x%08lx\n",*(DWORD*)ths16->magic);
579 if (*((DWORD*)ths16->magic) != 0x0000304C)
580 return 0;
581 if (!*(WORD*)(((LPBYTE)ths16)+0x12))
582 return 0;
585 if (!lstrncmp32A(ths->magic,"LS01",4)) {
586 if (ths16->length != ths->length)
587 return 0;
588 ths->ptr = (DWORD)PTR_SEG_TO_LIN(ths16->ptr);
589 /* code offset for QT_Thunk is at 0x1C... */
590 _write_qtthunk (((LPBYTE)ths) + ths->x1C,ths->ptr);
591 /* code offset for FT_Prolog is at 0x20... */
592 _write_ftprolog(((LPBYTE)ths) + ths->x20,ths->ptr);
593 return 1;
595 return TRUE;
599 /**********************************************************************
600 * The infamous and undocumented QT_Thunk procedure.
602 * We get arguments in [EBP+8] up to [EBP+38].
603 * We have to set up a frame in the 16 bit stackframe.
604 * saved_ss_sp: bp+0x40
605 * bp+0x3c
606 * ...
607 * bp: bp+0x00
608 * sp:
611 extern DWORD IF1632_Saved16_ss_sp;
612 VOID WINAPI QT_Thunk(CONTEXT *context)
614 CONTEXT context16;
615 LPBYTE curstack;
616 DWORD ret;
618 fprintf(stderr,"QT_Thunk(%08lx) ..",EDX_reg(context));
619 fprintf(stderr," argsize probably ebp-esp=%ld\n",
620 EBP_reg(context)-ESP_reg(context)
622 memcpy(&context16,context,sizeof(context16));
624 curstack = PTR_SEG_TO_LIN(IF1632_Saved16_ss_sp);
625 memcpy(curstack-0x40,(LPBYTE)EBP_reg(context),0x40);
626 EBP_reg(&context16) = LOWORD(IF1632_Saved16_ss_sp)-0x40;
627 IF1632_Saved16_ss_sp -= 0x3c;
629 CS_reg(&context16) = HIWORD(EDX_reg(context));
630 IP_reg(&context16) = LOWORD(EDX_reg(context));
631 #ifndef WINELIB
632 ret = CallTo16_regs_(&context16);
633 #endif
634 fprintf(stderr,". returned %08lx\n",ret);
635 EAX_reg(context) = ret;
636 IF1632_Saved16_ss_sp += 0x3c;
640 /**********************************************************************
641 * WOWCallback16 (KERNEL32.62)
643 DWORD WINAPI WOWCallback16(FARPROC16 fproc,DWORD arg)
645 DWORD ret;
646 fprintf(stderr,"WOWCallback16(%p,0x%08lx) ",fproc,arg);
647 ret = CallTo16_long_l(fproc,arg);
648 fprintf(stderr,"... returns %ld\n",ret);
649 return ret;
652 /***********************************************************************
653 * _KERNEL32_52 (KERNEL32.52)
654 * FIXME: what does it really do?
656 VOID WINAPI _KERNEL32_52(DWORD arg1,CONTEXT *regs)
658 fprintf(stderr,"_KERNE32_52(arg1=%08lx,%08lx)\n",arg1,EDI_reg(regs));
660 EAX_reg(regs) = (DWORD)WIN32_GetProcAddress16(EDI_reg(regs),"ThkBuf");
662 fprintf(stderr," GetProcAddress16(\"ThkBuf\") returns %08lx\n",
663 EAX_reg(regs)
667 /***********************************************************************
668 * _KERNEL32_43 (KERNEL32.42)
669 * A thunkbuffer link routine
670 * The thunkbuf looks like:
672 * 00: DWORD length ? don't know exactly
673 * 04: SEGPTR ptr ? where does it point to?
674 * The pointer ptr is written into the first DWORD of 'thunk'.
675 * (probably correct implemented)
677 BOOL32 WINAPI _KERNEL32_43(LPDWORD thunk,LPCSTR thkbuf,DWORD len,
678 LPCSTR dll16,LPCSTR dll32)
680 HINSTANCE16 hmod;
681 LPDWORD addr;
682 SEGPTR segaddr;
684 fprintf(stderr,"_KERNEL32_43(%p,%s,0x%08lx,%s,%s)\n",thunk,thkbuf,len,dll16,dll32);
686 hmod = LoadLibrary16(dll16);
687 if (hmod<32) {
688 fprintf(stderr,"->failed to load 16bit DLL %s, error %d\n",dll16,hmod);
689 return NULL;
691 segaddr = (DWORD)WIN32_GetProcAddress16(hmod,(LPSTR)thkbuf);
692 if (!segaddr) {
693 fprintf(stderr,"->no %s exported from %s!\n",thkbuf,dll16);
694 return NULL;
696 addr = (LPDWORD)PTR_SEG_TO_LIN(segaddr);
697 if (addr[0] != len) {
698 fprintf(stderr,"->thkbuf length mismatch? %ld vs %ld\n",len,addr[0]);
699 return NULL;
701 if (!addr[1])
702 return 0;
703 fprintf(stderr," addr[1] is %08lx\n",addr[1]);
704 *(DWORD*)thunk = addr[1];
705 return addr[1];
708 /***********************************************************************
709 * _KERNEL32_45 (KERNEL32.44)
710 * Looks like another 32->16 thunk. Dunno why they need two of them.
711 * calls the win16 address in EAX with the current stack.
713 * FIXME: doesn't seem to work correctly yet...
715 VOID WINAPI _KERNEL32_45(CONTEXT *context)
717 CONTEXT context16;
718 LPBYTE curstack;
719 DWORD ret,stacksize;
721 fprintf(stderr,"KERNEL32_45(%%eax=0x%08lx(%%cx=0x%04lx,%%edx=0x%08lx))\n",
722 (DWORD)EAX_reg(context),(DWORD)CX_reg(context),(DWORD)EDX_reg(context)
724 stacksize = EBP_reg(context)-ESP_reg(context);
725 fprintf(stderr," stacksize = %ld\n",stacksize);
727 memcpy(&context16,context,sizeof(context16));
729 curstack = PTR_SEG_TO_LIN(IF1632_Saved16_ss_sp);
730 memcpy(curstack-stacksize,(LPBYTE)EBP_reg(context),stacksize);
731 fprintf(stderr,"IF1632_Saved16_ss_sp is 0x%08lx\n",IF1632_Saved16_ss_sp);
732 EBP_reg(&context16) = LOWORD(IF1632_Saved16_ss_sp)-stacksize;
733 IF1632_Saved16_ss_sp -= stacksize;
735 DI_reg(&context16) = CX_reg(context);
736 CS_reg(&context16) = HIWORD(EAX_reg(context));
737 IP_reg(&context16) = LOWORD(EAX_reg(context));
738 /* some more registers spronged locally, but I don't think they are
739 * needed
741 #ifndef WINELIB
742 ret = CallTo16_regs_(&context16);
743 #endif
744 fprintf(stderr,". returned %08lx\n",ret);
745 EAX_reg(context) = ret;
746 IF1632_Saved16_ss_sp += stacksize;
750 /***********************************************************************
751 * (KERNEL32.40)
752 * A thunk setup routine.
753 * Expects a pointer to a preinitialized thunkbuffer in the first argument
754 * looking like:
755 * 00..03: unknown (pointer, check _41, _43, _46)
756 * 04: EB1E jmp +0x20
758 * 06..23: unknown (space for replacement code, check .90)
760 * 24:>E800000000 call offset 29
761 * 29:>58 pop eax ( target of call )
762 * 2A: 2D25000000 sub eax,0x00000025 ( now points to offset 4 )
763 * 2F: BAxxxxxxxx mov edx,xxxxxxxx
764 * 34: 68yyyyyyyy push KERNEL32.90
765 * 39: C3 ret
767 * 3A: EB1E jmp +0x20
768 * 3E ... 59: unknown (space for replacement code?)
769 * 5A: E8xxxxxxxx call <32bitoffset xxxxxxxx>
770 * 5F: 5A pop edx
771 * 60: 81EA25xxxxxx sub edx, 0x25xxxxxx
772 * 66: 52 push edx
773 * 67: 68xxxxxxxx push xxxxxxxx
774 * 6C: 68yyyyyyyy push KERNEL32.89
775 * 71: C3 ret
776 * 72: end?
777 * This function checks if the code is there, and replaces the yyyyyyyy entries
778 * by the functionpointers.
779 * The thunkbuf looks like:
781 * 00: DWORD length ? don't know exactly
782 * 04: SEGPTR ptr ? where does it point to?
783 * The segpointer ptr is written into the first DWORD of 'thunk'.
784 * (probably correct implemented)
787 LPVOID WINAPI _KERNEL32_41(LPBYTE thunk,LPCSTR thkbuf,DWORD len,LPCSTR dll16,
788 LPCSTR dll32)
790 HMODULE32 hkrnl32 = GetModuleHandle32A("KERNEL32");
791 HMODULE16 hmod;
792 LPDWORD addr,addr2;
793 DWORD segaddr;
795 fprintf(stderr,"KERNEL32_41(%p,%s,%ld,%s,%s)\n",
796 thunk,thkbuf,len,dll16,dll32
799 /* FIXME: add checks for valid code ... */
800 /* write pointers to kernel32.89 and kernel32.90 (+ordinal base of 1) */
801 *(DWORD*)(thunk+0x35) = (DWORD)GetProcAddress32(hkrnl32,(LPSTR)90);
802 *(DWORD*)(thunk+0x6D) = (DWORD)GetProcAddress32(hkrnl32,(LPSTR)89);
805 hmod = LoadLibrary16(dll16);
806 if (hmod<32) {
807 fprintf(stderr,"->failed to load 16bit DLL %s, error %d\n",dll16,hmod);
808 return NULL;
810 segaddr = (DWORD)WIN32_GetProcAddress16(hmod,(LPSTR)thkbuf);
811 if (!segaddr) {
812 fprintf(stderr,"->no %s exported from %s!\n",thkbuf,dll16);
813 return NULL;
815 addr = (LPDWORD)PTR_SEG_TO_LIN(segaddr);
816 if (addr[0] != len) {
817 fprintf(stderr,"->thkbuf length mismatch? %ld vs %ld\n",len,addr[0]);
818 return NULL;
820 addr2 = PTR_SEG_TO_LIN(addr[1]);
821 fprintf(stderr," addr2 is %08lx:%p\n",addr[1],addr2);
822 if (HIWORD(addr2))
823 *(DWORD*)thunk = (DWORD)addr2;
824 return addr2;
827 /***********************************************************************
828 * (KERNEL32.91)
829 * Thunk priming? function
830 * Rewrites the first part of the thunk to use the QT_Thunk interface
831 * and jumps to the start of that code.
833 VOID WINAPI _KERNEL32_90(CONTEXT *context)
835 fprintf(stderr,"_KERNEL32_90(eax=0x%08lx,edx=0x%08lx,ebp[-4]=0x%02x,target = %08lx, *target =%08lx)\n",
836 EAX_reg(context),EDX_reg(context),((BYTE*)EBP_reg(context))[-4],
837 (*(DWORD*)(EAX_reg(context)+EDX_reg(context)))+4*(((BYTE*)EBP_reg(context))[-4]),
838 *(DWORD*)((*(DWORD*)(EAX_reg(context)+EDX_reg(context)))+4*(((BYTE*)EBP_reg(context))[-4]))
840 _write_qtthunk((LPBYTE)EAX_reg(context),*(DWORD*)(EAX_reg(context)+EDX_reg(context)));
841 /* we just call the real QT_Thunk right now
842 * we can bypass the relaycode, for we already have the registercontext
844 EDX_reg(context) = *(DWORD*)((*(DWORD*)(EAX_reg(context)+EDX_reg(context)))+4*(((BYTE*)EBP_reg(context))[-4]));
845 return QT_Thunk(context);
848 /***********************************************************************
849 * (KERNEL32.45)
850 * Another thunkbuf link routine.
851 * The start of the thunkbuf looks like this:
852 * 00: DWORD length
853 * 04: SEGPTR address for thunkbuffer pointer
855 VOID WINAPI _KERNEL32_46(LPBYTE thunk,LPSTR thkbuf,DWORD len,LPSTR dll16,
856 LPSTR dll32)
858 LPDWORD addr;
859 HMODULE16 hmod;
860 SEGPTR segaddr;
862 fprintf(stderr,"KERNEL32_46(%p,%s,%lx,%s,%s)\n",
863 thunk,thkbuf,len,dll16,dll32
865 hmod = LoadLibrary16(dll16);
866 if (hmod < 32) {
867 fprintf(stderr,"->couldn't load %s, error %d\n",dll16,hmod);
868 return;
870 segaddr = (SEGPTR)WIN32_GetProcAddress16(hmod,thkbuf);
871 if (!segaddr) {
872 fprintf(stderr,"-> haven't found %s in %s!\n",thkbuf,dll16);
873 return;
875 addr = (LPDWORD)PTR_SEG_TO_LIN(segaddr);
876 if (addr[0] != len) {
877 fprintf(stderr,"-> length of thkbuf differs from expected length! (%ld vs %ld)\n",addr[0],len);
878 return;
880 *(DWORD*)PTR_SEG_TO_LIN(addr[1]) = (DWORD)thunk;
883 /**********************************************************************
884 * _KERNEL32_87
885 * Check if thunking is initialized (ss selector set up etc.)
887 BOOL32 WINAPI _KERNEL32_87()
889 fprintf(stderr,"KERNEL32_87 stub, returning TRUE\n");
890 return TRUE;
893 /**********************************************************************
894 * _KERNEL32_88
895 * One of the real thunking functions. This one seems to be for 32<->32
896 * thunks. It should probably be capable of crossing processboundaries.
898 * And YES, I've seen nr=48 (somewhere in the Win95 32<->16 OLE coupling)
900 DWORD WINAPIV _KERNEL32_88( DWORD nr, DWORD flags, FARPROC32 fun, ... )
902 DWORD i,ret;
903 DWORD *args = ((DWORD *)&fun) + 1;
905 fprintf(stderr,"KERNEL32_88(%ld,0x%08lx,%p,[ ",nr,flags,fun);
906 for (i=0;i<nr/4;i++) fprintf(stderr,"0x%08lx,",args[i]);
907 fprintf(stderr,"])");
908 #ifndef WINELIB
909 switch (nr) {
910 case 0: ret = CallTo32_0(fun);
911 break;
912 case 4: ret = CallTo32_1(fun,args[0]);
913 break;
914 case 8: ret = CallTo32_2(fun,args[0],args[1]);
915 break;
916 case 12: ret = CallTo32_3(fun,args[0],args[1],args[2]);
917 break;
918 case 16: ret = CallTo32_4(fun,args[0],args[1],args[2],args[3]);
919 break;
920 case 20: ret = CallTo32_5(fun,args[0],args[1],args[2],args[3],args[4]);
921 break;
922 case 24: ret = CallTo32_6(fun,args[0],args[1],args[2],args[3],args[4],args[5]);
923 break;
924 case 28: ret = CallTo32_7(fun,args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
925 break;
926 case 32: ret = CallTo32_8(fun,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
927 break;
928 case 36: ret = CallTo32_9(fun,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
929 break;
930 case 40: ret = CallTo32_10(fun,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
931 break;
932 case 44: ret = CallTo32_11(fun,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
933 break;
934 case 48: ret = CallTo32_12(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]);
935 break;
936 default:
937 fprintf(stderr," unsupported nr of arguments, %ld\n",nr);
938 ret = 0;
939 break;
942 #endif
943 fprintf(stderr," returning %ld ...\n",ret);
944 return ret;
947 /**********************************************************************
948 * KERNEL_619 (KERNEL)
949 * Seems to store y and z depending on x in some internal lists...
951 WORD WINAPI _KERNEL_619(WORD x,DWORD y,DWORD z)
953 fprintf(stderr,"KERNEL_619(0x%04x,0x%08lx,0x%08lx)\n",x,y,z);
954 return x;