2 * Emulator and Win95 thunks
4 * Copyright 1996 Alexandre Julliard
5 * Copyright 1997 Marcus Meissner
17 #include "stackframe.h"
18 #include "selectors.h"
25 typedef void (*RELAY
)();
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
;
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 /***********************************************************************
55 BOOL32
THUNK_Init(void)
57 /* Set the window proc calling functions */
58 WINPROC_SetCallWndProc16( THUNK_CallWndProc16
);
63 /***********************************************************************
66 static THUNK
*THUNK_Alloc( FARPROC32 func
, RELAY relay
)
68 THUNK
*thunk
= HeapAlloc( GetProcessHeap(), 0, sizeof(*thunk
) );
71 thunk
->popl_eax
= 0x58;
72 thunk
->pushl_func
= 0x68;
74 thunk
->pushl_eax
= 0x50;
76 thunk
->relay
= (RELAY
)((char *)relay
- (char *)(&thunk
->next
));
77 thunk
->next
= firstThunk
;
84 /***********************************************************************
87 static THUNK
*THUNK_Find( FARPROC32 func
)
89 THUNK
*thunk
= firstThunk
;
90 while (thunk
&& (thunk
->proc
!= func
)) thunk
= thunk
->next
;
95 /***********************************************************************
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
;
107 HeapFree( GetProcessHeap(), 0, thunk
);
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
)
126 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
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
);
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
;
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
,
214 DECL_THUNK( thunk
, func
, CallTo16_word_llwl
);
215 return EnumFontFamiliesEx16( hdc
, lpLF
, (FONTENUMPROCEX16
)&thunk
,
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
,
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
,
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
,
281 DECL_THUNK( thunk
, func
, CallTo16_word_wlw
);
283 return GrayString16( hdc
, hbr
, NULL
, lParam
, cch
, x
, y
, cx
, cy
);
285 return GrayString16( hdc
, hbr
, (GRAYSTRINGPROC16
)&thunk
, lParam
, cch
,
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
)
309 THUNK
*thunk
= THUNK_Find( (FARPROC16
)proc
);
310 if (!thunk
) return FALSE
;
311 ret
= UnhookWindowsHook16( id
, (HOOKPROC16
)thunk
);
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
);
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
);
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
)
400 DWORD ret
= GetDCHook( hdc
, (FARPROC16
*)&thunk
);
403 if (thunk
== (THUNK
*)DCHook
)
405 if (!defDCHookProc
) /* Get DCHook Win16 entry point */
406 defDCHookProc
= MODULE_GetEntryPoint(GetModuleHandle16("USER"),
408 *phookProc
= defDCHookProc
;
410 else *phookProc
= thunk
->proc
;
416 /***********************************************************************
417 * THUNK_SetTaskSignalProc (KERNEL.38)
419 FARPROC16 WINAPI
THUNK_SetTaskSignalProc( HTASK16 hTask
, FARPROC16 proc
)
421 static FARPROC16 defSignalProc16
= NULL
;
425 if( !defSignalProc16
)
426 defSignalProc16
= MODULE_GetEntryPoint(GetModuleHandle16("USER"), 314 );
428 if( proc
== defSignalProc16
)
429 thunk
= (THUNK
*)SetTaskSignalProc( hTask
, (FARPROC16
)&USER_SignalProc
);
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
;
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
;
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
;
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
;
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
516 static void _write_ftprolog(LPBYTE start
,DWORD thunkstart
) {
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.
533 * 8A4DFC mov cl , [ebp-04]
534 * 8B148Dxxxxxxxx mov edx, [4*ecx + (EAX+EDX)]
535 * B8yyyyyyyy mov eax, QT_Thunk
538 static void _write_qtthunk(LPBYTE start
,DWORD thunkstart
) {
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.
570 UINT32 WINAPI
ThunkConnect32( struct thunkstruct
*ths
, LPSTR thunkfun16
,
571 LPSTR module16
, LPSTR module32
, HMODULE32 hmod32
,
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",
587 fprintf(stdnimp
," length = %lx\n",ths
->length
);
588 if (lstrncmp32A(ths
->magic
,"SL01",4)&&lstrncmp32A(ths
->magic
,"LS01",4))
590 hmm
=LoadModule16(module16
,NULL
);
593 thkbuf
=(SEGPTR
)WIN32_GetProcAddress16(hmm
,thunkfun16
);
596 ths16
=(struct thunkstruct
*)PTR_SEG_TO_LIN(thkbuf
);
597 if (lstrncmp32A(ths16
->magic
,ths
->magic
,4))
600 if (!lstrncmp32A(ths
->magic
,"SL01",4)) {
601 if (ths16
->length
!= ths
->length
)
603 ths
->x0C
= (DWORD
)ths16
;
605 fprintf(stderr
," ths16 magic is 0x%08lx\n",*(DWORD
*)ths16
->magic
);
606 if (*((DWORD
*)ths16
->magic
) != 0x0000304C)
608 if (!*(WORD
*)(((LPBYTE
)ths16
)+0x12))
612 if (!lstrncmp32A(ths
->magic
,"LS01",4)) {
613 if (ths16
->length
!= ths
->length
)
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
);
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
638 VOID WINAPI
QT_Thunk(CONTEXT
*context
)
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
));
656 ret
= CallTo16_regs_(&context16
,-0x40);
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
)
669 fprintf(stderr
,"WOWCallback16(%p,0x%08lx) ",fproc
,arg
);
670 ret
= CallTo16_long_l(fproc
,arg
);
671 fprintf(stderr
,"... returns %ld\n",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");
684 fprintf(stderr
,"_KERNE32_52()\n");
688 ret
= (DWORD
)WIN32_GetProcAddress16(hmod
,"ThkBuf");
690 fprintf(stderr
," GetProcAddress16(0x%04x,\"ThkBuf\") returns %08lx\n",
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
)
713 fprintf(stderr
,"_KERNEL32_43(%p,%s,0x%08lx,%s,%s)\n",thunk
,thkbuf
,len
,dll16
,dll32
);
715 hmod
= LoadLibrary16(dll16
);
717 fprintf(stderr
,"->failed to load 16bit DLL %s, error %d\n",dll16
,hmod
);
720 segaddr
= (DWORD
)WIN32_GetProcAddress16(hmod
,(LPSTR
)thkbuf
);
722 fprintf(stderr
,"->no %s exported from %s!\n",thkbuf
,dll16
);
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]);
732 fprintf(stderr
," addr[1] is %08lx\n",addr
[1]);
733 *(DWORD
*)thunk
= 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
)
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
769 ret
= CallTo16_regs_(&context16
,-stacksize
);
771 fprintf(stderr
,". returned %08lx\n",ret
);
772 EAX_reg(context
) = ret
;
775 /***********************************************************************
777 * A thunk setup routine.
778 * Expects a pointer to a preinitialized thunkbuffer in the first argument
780 * 00..03: unknown (pointer, check _41, _43, _46)
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
793 * 3E ... 59: unknown (space for replacement code?)
794 * 5A: E8xxxxxxxx call <32bitoffset xxxxxxxx>
796 * 60: 81EA25xxxxxx sub edx, 0x25xxxxxx
798 * 67: 68xxxxxxxx push xxxxxxxx
799 * 6C: 68yyyyyyyy push KERNEL32.89
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
,
815 HMODULE32 hkrnl32
= GetModuleHandle32A("KERNEL32");
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
);
832 fprintf(stderr
,"->failed to load 16bit DLL %s, error %d\n",dll16
,hmod
);
835 segaddr
= (DWORD
)WIN32_GetProcAddress16(hmod
,(LPSTR
)thkbuf
);
837 fprintf(stderr
,"->no %s exported from %s!\n",thkbuf
,dll16
);
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]);
845 addr2
= PTR_SEG_TO_LIN(addr
[1]);
846 fprintf(stderr
," addr2 is %08lx:%p\n",addr
[1],addr2
);
848 *(DWORD
*)thunk
= (DWORD
)addr2
;
852 /***********************************************************************
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 /***********************************************************************
875 * Another thunkbuf link routine.
876 * The start of the thunkbuf looks like this:
878 * 04: SEGPTR address for thunkbuffer pointer
880 VOID WINAPI
_KERNEL32_46(LPBYTE thunk
,LPSTR thkbuf
,DWORD len
,LPSTR dll16
,
887 fprintf(stderr
,"KERNEL32_46(%p,%s,%lx,%s,%s)\n",
888 thunk
,thkbuf
,len
,dll16
,dll32
890 hmod
= LoadLibrary16(dll16
);
892 fprintf(stderr
,"->couldn't load %s, error %d\n",dll16
,hmod
);
895 segaddr
= (SEGPTR
)WIN32_GetProcAddress16(hmod
,thkbuf
);
897 fprintf(stderr
,"-> haven't found %s in %s!\n",thkbuf
,dll16
);
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
);
905 *(DWORD
*)PTR_SEG_TO_LIN(addr
[1]) = (DWORD
)thunk
;
908 /**********************************************************************
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");
918 /**********************************************************************
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
, ... )
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
,"])");
936 case 4: ret
= fun(args
[0]);
938 case 8: ret
= fun(args
[0],args
[1]);
940 case 12: ret
= fun(args
[0],args
[1],args
[2]);
942 case 16: ret
= fun(args
[0],args
[1],args
[2],args
[3]);
944 case 20: ret
= fun(args
[0],args
[1],args
[2],args
[3],args
[4]);
946 case 24: ret
= fun(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5]);
948 case 28: ret
= fun(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6]);
950 case 32: ret
= fun(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7]);
952 case 36: ret
= fun(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8]);
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]);
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]);
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]);
961 fprintf(stderr
," unsupported nr of arguments, %ld\n",nr
);
966 fprintf(stderr
," returning %ld ...\n",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
);
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:
986 * 0: PTR nextblockstart
988 * 8: WORD sel ( start points to blockstart)
992 * 18: PDB *owning_process;
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.
1002 * 6668x arg2 x pushl <arg2>
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.
1011 AllocSLCallback(DWORD finalizer
,DWORD callback
) {
1012 LPBYTE x
,thunk
= HeapAlloc( GetProcessHeap(), 0, 32 );
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
);
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.
1038 _KERNEL_358(DWORD x
) {
1041 fprintf(stderr
,"_KERNEL_358(0x%08lx),stub\n",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).
1055 _KERNEL_359(DWORD x
) {
1058 fprintf(stderr
,"_KERNEL_359(0x%08lx),stub\n",x
);
1059 if ((HIWORD(x
) & 7)!=7)
1061 savedsssp
= IF1632_Saved16_ss_sp
;IF1632_Saved16_ss_sp
= 0;
1062 SELECTOR_FreeBlock(x
>>16,1);
1063 IF1632_Saved16_ss_sp
= savedsssp
;
1067 /**********************************************************************
1068 * KERNEL_472 (KERNEL)
1069 * something like GetCurrenthInstance.
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
;
1079 if (!HIWORD(EAX_reg(context
)))
1080 return; /* returns the passed value */