* Copyright 1997, 1998 Marcus Meissner
* Copyright 1998 Ulrich Weigand
*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include "config.h"
+
#include <string.h>
#include <sys/types.h>
-#include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
+#include "winreg.h"
+#include "winternl.h"
+#include "wownt32.h"
#include "wine/winbase16.h"
-#include "builtin16.h"
-#include "callback.h"
-#include "debugtools.h"
-#include "flatthunk.h"
-#include "heap.h"
+#include "wine/debug.h"
+#include "wine/library.h"
#include "module.h"
-#include "selectors.h"
#include "stackframe.h"
-#include "task.h"
+#include "kernel_private.h"
-DEFAULT_DEBUG_CHANNEL(thunk);
+WINE_DEFAULT_DEBUG_CHANNEL(thunk);
+
+struct ThunkDataCommon
+{
+ char magic[4]; /* 00 */
+ DWORD checksum; /* 04 */
+};
+
+struct ThunkDataLS16
+{
+ struct ThunkDataCommon common; /* 00 */
+ SEGPTR targetTable; /* 08 */
+ DWORD firstTime; /* 0C */
+};
+
+struct ThunkDataLS32
+{
+ struct ThunkDataCommon common; /* 00 */
+ DWORD * targetTable; /* 08 */
+ char lateBinding[4]; /* 0C */
+ DWORD flags; /* 10 */
+ DWORD reserved1; /* 14 */
+ DWORD reserved2; /* 18 */
+ DWORD offsetQTThunk; /* 1C */
+ DWORD offsetFTProlog; /* 20 */
+};
+
+struct ThunkDataSL16
+{
+ struct ThunkDataCommon common; /* 00 */
+ DWORD flags1; /* 08 */
+ DWORD reserved1; /* 0C */
+ struct ThunkDataSL * fpData; /* 10 */
+ SEGPTR spData; /* 14 */
+ DWORD reserved2; /* 18 */
+ char lateBinding[4]; /* 1C */
+ DWORD flags2; /* 20 */
+ DWORD reserved3; /* 20 */
+ SEGPTR apiDatabase; /* 28 */
+};
+
+struct ThunkDataSL32
+{
+ struct ThunkDataCommon common; /* 00 */
+ DWORD reserved1; /* 08 */
+ struct ThunkDataSL * data; /* 0C */
+ char lateBinding[4]; /* 10 */
+ DWORD flags; /* 14 */
+ DWORD reserved2; /* 18 */
+ DWORD reserved3; /* 1C */
+ DWORD offsetTargetTable; /* 20 */
+};
+
+struct ThunkDataSL
+{
+#if 0
+ This structure differs from the Win95 original,
+ but this should not matter since it is strictly internal to
+ the thunk handling routines in KRNL386 / KERNEL32.
+
+ For reference, here is the Win95 layout:
+
+ struct ThunkDataCommon common; /* 00 */
+ DWORD flags1; /* 08 */
+ SEGPTR apiDatabase; /* 0C */
+ WORD exePtr; /* 10 */
+ WORD segMBA; /* 12 */
+ DWORD lenMBATotal; /* 14 */
+ DWORD lenMBAUsed; /* 18 */
+ DWORD flags2; /* 1C */
+ char pszDll16[256]; /* 20 */
+ char pszDll32[256]; /*120 */
+
+ We do it differently since all our thunk handling is done
+ by 32-bit code. Therefore we do not need do provide
+ easy access to this data, especially the process target
+ table database, for 16-bit code.
+#endif
+
+ struct ThunkDataCommon common;
+ DWORD flags1;
+ struct SLApiDB * apiDB;
+ struct SLTargetDB * targetDB;
+ DWORD flags2;
+ char pszDll16[256];
+ char pszDll32[256];
+};
+
+struct SLTargetDB
+{
+ struct SLTargetDB * next;
+ DWORD process;
+ DWORD * targetTable;
+};
+struct SLApiDB
+{
+ DWORD nrArgBytes;
+ DWORD errorReturnValue;
+};
+
+#ifdef __i386__
+extern void __wine_call_from_16_thunk();
+#else
+static void __wine_call_from_16_thunk() { }
+#endif
+
+/* Push a DWORD on the 32-bit stack */
+static inline void stack32_push( CONTEXT86 *context, DWORD val )
+{
+ context->Esp -= sizeof(DWORD);
+ *(DWORD *)context->Esp = val;
+}
+
+/* Pop a DWORD from the 32-bit stack */
+static inline DWORD stack32_pop( CONTEXT86 *context )
+{
+ DWORD ret = *(DWORD *)context->Esp;
+ context->Esp += sizeof(DWORD);
+ return ret;
+}
/***********************************************************************
* *
/***********************************************************************
* LogApiThkLSF (KERNEL32.42)
- *
+ *
* NOTE: needs to preserve all registers!
*/
void WINAPI LogApiThkLSF( LPSTR func, CONTEXT86 *context )
/***********************************************************************
* LogApiThkSL (KERNEL32.44)
- *
+ *
* NOTE: needs to preserve all registers!
*/
void WINAPI LogApiThkSL( LPSTR func, CONTEXT86 *context )
/***********************************************************************
* LogCBThkSL (KERNEL32.47)
- *
+ *
* NOTE: needs to preserve all registers!
*/
void WINAPI LogCBThkSL( LPSTR func, CONTEXT86 *context )
/***********************************************************************
* Generates a FT_Prolog call.
- *
+ *
* 0FB6D1 movzbl edx,cl
* 8B1495xxxxxxxx mov edx,[4*edx + targetTable]
* 68xxxxxxxx push FT_Prolog
*x++ = 0x0f;*x++=0xb6;*x++=0xd1; /* movzbl edx,cl */
*x++ = 0x8B;*x++=0x14;*x++=0x95;*(DWORD**)x= targetTable;
x+=4; /* mov edx, [4*edx + targetTable] */
- *x++ = 0x68; *(DWORD*)x = (DWORD)GetProcAddress(GetModuleHandleA("KERNEL32"),"FT_Prolog");
+ *x++ = 0x68; *(DWORD*)x = (DWORD)GetProcAddress(kernel32_handle,"FT_Prolog");
x+=4; /* push FT_Prolog */
*x++ = 0xC3; /* lret */
/* fill rest with 0xCC / int 3 */
*x++ = 0x8A;*x++=0x4D;*x++=0xFC; /* movb cl,[ebp-04] */
*x++ = 0x8B;*x++=0x14;*x++=0x8D;*(DWORD**)x= targetTable;
x+=4; /* mov edx, [4*ecx + targetTable */
- *x++ = 0xB8; *(DWORD*)x = (DWORD)GetProcAddress(GetModuleHandleA("KERNEL32"),"QT_Thunk");
+ *x++ = 0xB8; *(DWORD*)x = (DWORD)GetProcAddress(kernel32_handle,"QT_Thunk");
x+=4; /* mov eax , QT_Thunk */
*x++ = 0xFF; *x++ = 0xE0; /* jmp eax */
/* should fill the rest of the 32 bytes with 0xCC */
/***********************************************************************
* _loadthunk
*/
-static LPVOID _loadthunk(LPCSTR module, LPCSTR func, LPCSTR module32,
+static LPVOID _loadthunk(LPCSTR module, LPCSTR func, LPCSTR module32,
struct ThunkDataCommon *TD32, DWORD checksum)
{
struct ThunkDataCommon *TD16;
- HMODULE hmod;
+ HMODULE16 hmod;
int ordinal;
- if ((hmod = LoadLibrary16(module)) <= 32)
+ if ((hmod = LoadLibrary16(module)) <= 32)
{
ERR("(%s, %s, %s): Unable to load '%s', error %d\n",
module, func, module32, module, hmod);
if (TD32 && memcmp(TD16->magic, TD32->magic, 4))
{
ERR("(%s, %s, %s): Bad magic %c%c%c%c (should be %c%c%c%c)\n",
- module, func, module32,
+ module, func, module32,
TD16->magic[0], TD16->magic[1], TD16->magic[2], TD16->magic[3],
TD32->magic[0], TD32->magic[1], TD32->magic[2], TD32->magic[3]);
return 0;
}
/***********************************************************************
- * ThunkConnect32 (KERNEL32)
+ * ThunkConnect32 (KERNEL32.@)
* Connects a 32bit and a 16bit thunkbuffer.
*/
-UINT WINAPI ThunkConnect32(
+UINT WINAPI ThunkConnect32(
struct ThunkDataCommon *TD, /* [in/out] thunkbuffer */
LPSTR thunkfun16, /* [in] win16 thunkfunction */
LPSTR module16, /* [in] name of win16 dll */
}
else
{
- ERR("Invalid magic %c%c%c%c\n",
+ ERR("Invalid magic %c%c%c%c\n",
TD->magic[0], TD->magic[1], TD->magic[2], TD->magic[3]);
return 0;
}
-
+
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
tdb->next = SL32->data->targetDB; /* FIXME: not thread-safe! */
SL32->data->targetDB = tdb;
- TRACE("Process %08lx allocated TargetDB entry for ThunkDataSL %08lx\n",
+ TRACE("Process %08lx allocated TargetDB entry for ThunkDataSL %08lx\n",
GetCurrentProcessId(), (DWORD)SL32->data);
}
else
}
/**********************************************************************
- * QT_Thunk (KERNEL32)
+ * QT_Thunk (KERNEL32.@)
*
* The target address is in EDX.
- * The 16 bit arguments start at ESP.
+ * The 16bit arguments start at ESP.
* The number of 16bit argument bytes is EBP-ESP-0x40 (64 Byte thunksetup).
+ * So the stack layout is 16bit argument bytes and then the 64 byte
+ * scratch buffer.
+ * The scratch buffer is used as work space by Windows' QT_Thunk
+ * function.
+ * As the programs unfortunately don't always provide a fixed size
+ * scratch buffer (danger, stack corruption ahead !!), we simply resort
+ * to copying over the whole EBP-ESP range to the 16bit stack
+ * (as there's no way to safely figure out the param count
+ * due to this misbehaviour of some programs).
* [ok]
+ *
+ * See DDJ article 9614c for a very good description of QT_Thunk (also
+ * available online !).
+ *
+ * FIXME: DDJ talks of certain register usage rules; I'm not sure
+ * whether we cover this 100%.
*/
void WINAPI QT_Thunk( CONTEXT86 *context )
{
memcpy(&context16,context,sizeof(context16));
+ context16.SegFs = wine_get_fs();
+ context16.SegGs = wine_get_gs();
context16.SegCs = HIWORD(context->Edx);
context16.Eip = LOWORD(context->Edx);
+ /* point EBP to the STACK16FRAME on the stack
+ * for the call_to_16 to set up the register content on calling */
context16.Ebp = OFFSETOF( NtCurrentTeb()->cur_stack )
+ (WORD)&((STACK16FRAME*)0)->bp;
- argsize = context->Ebp-context->Esp-0x40;
+ /*
+ * used to be (problematic):
+ * argsize = context->Ebp - context->Esp - 0x40;
+ * due to some programs abusing the API, we better assume the full
+ * EBP - ESP range for copying instead: */
+ argsize = context->Ebp - context->Esp;
- memcpy( (LPBYTE)CURRENT_STACK16 - argsize,
- (LPBYTE)context->Esp, argsize );
+ /* ok, too much is insane; let's limit param count a bit again */
+ if (argsize > 64)
+ argsize = 64; /* 32 WORDs */
- wine_call_to_16_regs_short( &context16, argsize );
+ WOWCallback16Ex( 0, WCB16_REGS, argsize, (void *)context->Esp, (DWORD *)&context16 );
context->Eax = context16.Eax;
context->Edx = context16.Edx;
context->Ecx = context16.Ecx;
+ /* make sure to update the Win32 ESP, too, in order to throw away
+ * the number of parameters that the Win16 function
+ * accepted (that it popped from the corresponding Win16 stack) */
context->Esp += LOWORD(context16.Esp) -
( OFFSETOF( NtCurrentTeb()->cur_stack ) - argsize );
}
/**********************************************************************
- * FT_Prolog (KERNEL32.233)
- *
+ * FT_Prolog (KERNEL32.@)
+ *
* The set of FT_... thunk routines is used instead of QT_Thunk,
* if structures have to be converted from 32-bit to 16-bit
* (change of member alignment, conversion of members).
* bits 10..15 number of DWORD arguments
*
* Output: A new stackframe is created, and a 64 byte buffer
- * allocated on the stack. The layout of the stack
+ * allocated on the stack. The layout of the stack
* on return is as follows:
*
* (ebp+4) return address to caller of thunk function
* (ebp-64)
*
* ESP is EBP-64 after return.
- *
+ *
*/
void WINAPI FT_Prolog( CONTEXT86 *context )
}
/**********************************************************************
- * FT_Thunk (KERNEL32.234)
+ * FT_Thunk (KERNEL32.@)
*
- * This routine performs the actual call to 16-bit code,
+ * This routine performs the actual call to 16-bit code,
* similar to QT_Thunk. The differences are:
* - The call target is taken from the buffer created by FT_Prolog
* - Those arguments requested by the thunk code (by setting the
* are guaranteed to point to structures copied to the stack
* by the thunk code, so we always use the 16-bit stack selector
* for those addresses).
- *
+ *
* The bit #i of EBP-20 corresponds here to the DWORD starting at
* ESP+4 + 2*i.
- *
- * FIXME: It is unclear what happens if there are more than 32 WORDs
+ *
+ * FIXME: It is unclear what happens if there are more than 32 WORDs
* of arguments, so that the single DWORD bitmap is no longer
* sufficient ...
*/
CONTEXT86 context16;
DWORD i, argsize;
- LPBYTE newstack, oldstack;
+ DWORD newstack[32];
+ LPBYTE oldstack;
memcpy(&context16,context,sizeof(context16));
+ context16.SegFs = wine_get_fs();
+ context16.SegGs = wine_get_gs();
context16.SegCs = HIWORD(callTarget);
context16.Eip = LOWORD(callTarget);
context16.Ebp = OFFSETOF( NtCurrentTeb()->cur_stack )
+ (WORD)&((STACK16FRAME*)0)->bp;
argsize = context->Ebp-context->Esp-0x40;
- newstack = (LPBYTE)CURRENT_STACK16 - argsize;
+ if (argsize > sizeof(newstack)) argsize = sizeof(newstack);
oldstack = (LPBYTE)context->Esp;
memcpy( newstack, oldstack, argsize );
for (i = 0; i < 32; i++) /* NOTE: What about > 32 arguments? */
if (mapESPrelative & (1 << i))
{
- SEGPTR *arg = (SEGPTR *)(newstack + 2*i);
+ SEGPTR *arg = (SEGPTR *)newstack[i];
*arg = MAKESEGPTR(SELECTOROF(NtCurrentTeb()->cur_stack),
OFFSETOF(NtCurrentTeb()->cur_stack) - argsize
+ (*(LPBYTE *)arg - oldstack));
}
- wine_call_to_16_regs_short( &context16, argsize );
+ WOWCallback16Ex( 0, WCB16_REGS, argsize, newstack, (DWORD *)&context16 );
context->Eax = context16.Eax;
context->Edx = context16.Edx;
context->Ecx = context16.Ecx;
*
* One of the FT_ExitNN functions is called at the end of the thunk code.
* It removes the stack frame created by FT_Prolog, moves the function
- * return from EBX to EAX (yes, FT_Thunk did use EAX for the return
- * value, but the thunk code has moved it from EAX to EBX in the
+ * return from EBX to EAX (yes, FT_Thunk did use EAX for the return
+ * value, but the thunk code has moved it from EAX to EBX in the
* meantime ... :-), restores the caller's EBX, ESI, and EDI registers,
* and perform a return to the CALLER of the thunk code (while removing
* the given number of arguments from the caller's stack).
}
/***********************************************************************
- * FT_Exit0 (KERNEL32.218)
+ * FT_Exit0 (KERNEL32.@)
*/
void WINAPI FT_Exit0 (CONTEXT86 *context) { FT_Exit(context, 0); }
/***********************************************************************
- * FT_Exit4 (KERNEL32.219)
+ * FT_Exit4 (KERNEL32.@)
*/
void WINAPI FT_Exit4 (CONTEXT86 *context) { FT_Exit(context, 4); }
/***********************************************************************
- * FT_Exit8 (KERNEL32.220)
+ * FT_Exit8 (KERNEL32.@)
*/
void WINAPI FT_Exit8 (CONTEXT86 *context) { FT_Exit(context, 8); }
/***********************************************************************
- * FT_Exit12 (KERNEL32.221)
+ * FT_Exit12 (KERNEL32.@)
*/
void WINAPI FT_Exit12(CONTEXT86 *context) { FT_Exit(context, 12); }
/***********************************************************************
- * FT_Exit16 (KERNEL32.222)
+ * FT_Exit16 (KERNEL32.@)
*/
void WINAPI FT_Exit16(CONTEXT86 *context) { FT_Exit(context, 16); }
/***********************************************************************
- * FT_Exit20 (KERNEL32.223)
+ * FT_Exit20 (KERNEL32.@)
*/
void WINAPI FT_Exit20(CONTEXT86 *context) { FT_Exit(context, 20); }
/***********************************************************************
- * FT_Exit24 (KERNEL32.224)
+ * FT_Exit24 (KERNEL32.@)
*/
void WINAPI FT_Exit24(CONTEXT86 *context) { FT_Exit(context, 24); }
/***********************************************************************
- * FT_Exit28 (KERNEL32.225)
+ * FT_Exit28 (KERNEL32.@)
*/
void WINAPI FT_Exit28(CONTEXT86 *context) { FT_Exit(context, 28); }
/***********************************************************************
- * FT_Exit32 (KERNEL32.226)
+ * FT_Exit32 (KERNEL32.@)
*/
void WINAPI FT_Exit32(CONTEXT86 *context) { FT_Exit(context, 32); }
/***********************************************************************
- * FT_Exit36 (KERNEL32.227)
+ * FT_Exit36 (KERNEL32.@)
*/
void WINAPI FT_Exit36(CONTEXT86 *context) { FT_Exit(context, 36); }
/***********************************************************************
- * FT_Exit40 (KERNEL32.228)
+ * FT_Exit40 (KERNEL32.@)
*/
void WINAPI FT_Exit40(CONTEXT86 *context) { FT_Exit(context, 40); }
/***********************************************************************
- * FT_Exit44 (KERNEL32.229)
+ * FT_Exit44 (KERNEL32.@)
*/
void WINAPI FT_Exit44(CONTEXT86 *context) { FT_Exit(context, 44); }
/***********************************************************************
- * FT_Exit48 (KERNEL32.230)
+ * FT_Exit48 (KERNEL32.@)
*/
void WINAPI FT_Exit48(CONTEXT86 *context) { FT_Exit(context, 48); }
/***********************************************************************
- * FT_Exit52 (KERNEL32.231)
+ * FT_Exit52 (KERNEL32.@)
*/
void WINAPI FT_Exit52(CONTEXT86 *context) { FT_Exit(context, 52); }
/***********************************************************************
- * FT_Exit56 (KERNEL32.232)
+ * FT_Exit56 (KERNEL32.@)
*/
void WINAPI FT_Exit56(CONTEXT86 *context) { FT_Exit(context, 56); }
/***********************************************************************
* ThunkInitLS (KERNEL32.43)
- * A thunkbuffer link routine
+ * A thunkbuffer link routine
* The thunkbuf looks like:
*
* 00: DWORD length ? don't know exactly
/***********************************************************************
* Common32ThkLS (KERNEL32.45)
- *
+ *
* This is another 32->16 thunk, independent of the QT_Thunk/FT_Thunk
- * style thunks. The basic difference is that the parameter conversion
+ * style thunks. The basic difference is that the parameter conversion
* is done completely on the *16-bit* side here. Thus we do not call
* the 16-bit target directly, but call a common entry point instead.
* This entry function then calls the target according to the target
* number passed in the DI register.
- *
+ *
* Input: EAX SEGPTR to the common 16-bit entry point
* CX offset in thunk table (target number * 4)
* DX error return value if execution fails (unclear???)
* (esp+40) 32-bit arguments
* ...
* (esp+8) 32 byte of stack space available as buffer
- * (esp) 8 byte return address for use with 0x66 lret
- *
+ * (esp) 8 byte return address for use with 0x66 lret
+ *
* The called 16-bit stub uses a 0x66 lret to return to 32-bit code,
* and uses the EAX register to return a DWORD return value.
- * Thus we need to use a special assembly glue routine
+ * Thus we need to use a special assembly glue routine
* (CallRegisterLongProc instead of CallRegisterShortProc).
*
- * Finally, we return to the caller, popping the arguments off
+ * Finally, we return to the caller, popping the arguments off
* the stack. The number of arguments to be popped is returned
* in the BL register by the called 16-bit routine.
*
memcpy(&context16,context,sizeof(context16));
+ context16.SegFs = wine_get_fs();
+ context16.SegGs = wine_get_gs();
context16.Edi = LOWORD(context->Ecx);
context16.SegCs = HIWORD(context->Eax);
context16.Eip = LOWORD(context->Eax);
if (context->Edx == context->Eip)
argsize = 6 * 4;
- memcpy( (LPBYTE)CURRENT_STACK16 - argsize,
- (LPBYTE)context->Esp, argsize );
-
- wine_call_to_16_regs_long(&context16, argsize + 32);
+ /* Note: the first 32 bytes we copy are just garbage from the 32-bit stack, in order to reserve
+ * the space. It is safe to do that since the register function prefix has reserved
+ * a lot more space than that below context->Esp.
+ */
+ WOWCallback16Ex( 0, WCB16_REGS, argsize + 32, (LPBYTE)context->Esp - 32, (DWORD *)&context16 );
context->Eax = context16.Eax;
/* Clean up caller's stack frame */
- context->Esp += BL_reg(&context16);
+ context->Esp += LOBYTE(context16.Ebx);
}
/***********************************************************************
* YET Another 32->16 thunk. The difference to Common32ThkLS is that
* argument processing is done on both the 32-bit and the 16-bit side:
* The 32-bit side prepares arguments, copying them onto the stack.
- *
- * When this routine is called, the first word on the stack is the
+ *
+ * When this routine is called, the first word on the stack is the
* number of argument bytes prepared by the 32-bit code, and EDX
* contains the 16-bit target address.
*
- * The called 16-bit routine is another relaycode, doing further
+ * The called 16-bit routine is another relaycode, doing further
* argument processing and then calling the real 16-bit target
* whose address is stored at [bp-04].
*
* After return from the 16-bit relaycode, the arguments need
* to be copied *back* to the 32-bit stack, since the 32-bit
* relaycode processes output parameters.
- *
+ *
* Note that we copy twice the number of arguments, since some of the
* 16-bit relaycodes in SYSTHUNK.DLL directly access the original
* arguments of the caller!
memcpy(&context16,context,sizeof(context16));
+ context16.SegFs = wine_get_fs();
+ context16.SegGs = wine_get_gs();
context16.SegCs = HIWORD(context->Edx);
context16.Eip = LOWORD(context->Edx);
context16.Ebp = OFFSETOF( NtCurrentTeb()->cur_stack )
argsize = 2 * *(WORD *)context->Esp + 2;
- memcpy( (LPBYTE)CURRENT_STACK16 - argsize,
- (LPBYTE)context->Esp, argsize );
-
- wine_call_to_16_regs_short(&context16, argsize);
+ WOWCallback16Ex( 0, WCB16_REGS, argsize, (void *)context->Esp, (DWORD *)&context16 );
context->Eax = context16.Eax;
context->Edx = context16.Edx;
/* Copy modified buffers back to 32-bit stack */
- memcpy( (LPBYTE)context->Esp,
+ memcpy( (LPBYTE)context->Esp,
(LPBYTE)CURRENT_STACK16 - argsize, argsize );
context->Esp += LOWORD(context16.Esp) -
* A thunk setup routine.
* Expects a pointer to a preinitialized thunkbuffer in the first argument
* looking like:
- * 00..03: unknown (pointer, check _41, _43, _46)
- * 04: EB1E jmp +0x20
- *
- * 06..23: unknown (space for replacement code, check .90)
- *
- * 24:>E800000000 call offset 29
- * 29:>58 pop eax ( target of call )
- * 2A: 2D25000000 sub eax,0x00000025 ( now points to offset 4 )
- * 2F: BAxxxxxxxx mov edx,xxxxxxxx
- * 34: 68yyyyyyyy push KERNEL32.90
- * 39: C3 ret
- *
- * 3A: EB1E jmp +0x20
- * 3E ... 59: unknown (space for replacement code?)
- * 5A: E8xxxxxxxx call <32bitoffset xxxxxxxx>
- * 5F: 5A pop edx
- * 60: 81EA25xxxxxx sub edx, 0x25xxxxxx
- * 66: 52 push edx
- * 67: 68xxxxxxxx push xxxxxxxx
- * 6C: 68yyyyyyyy push KERNEL32.89
- * 71: C3 ret
- * 72: end?
+ *| 00..03: unknown (pointer, check _41, _43, _46)
+ *| 04: EB1E jmp +0x20
+ *|
+ *| 06..23: unknown (space for replacement code, check .90)
+ *|
+ *| 24:>E800000000 call offset 29
+ *| 29:>58 pop eax ( target of call )
+ *| 2A: 2D25000000 sub eax,0x00000025 ( now points to offset 4 )
+ *| 2F: BAxxxxxxxx mov edx,xxxxxxxx
+ *| 34: 68yyyyyyyy push KERNEL32.90
+ *| 39: C3 ret
+ *|
+ *| 3A: EB1E jmp +0x20
+ *| 3E ... 59: unknown (space for replacement code?)
+ *| 5A: E8xxxxxxxx call <32bitoffset xxxxxxxx>
+ *| 5F: 5A pop edx
+ *| 60: 81EA25xxxxxx sub edx, 0x25xxxxxx
+ *| 66: 52 push edx
+ *| 67: 68xxxxxxxx push xxxxxxxx
+ *| 6C: 68yyyyyyyy push KERNEL32.89
+ *| 71: C3 ret
+ *| 72: end?
* This function checks if the code is there, and replaces the yyyyyyyy entries
* by the functionpointers.
* The thunkbuf looks like:
*
- * 00: DWORD length ? don't know exactly
- * 04: SEGPTR ptr ? where does it point to?
+ *| 00: DWORD length ? don't know exactly
+ *| 04: SEGPTR ptr ? where does it point to?
* The segpointer ptr is written into the first DWORD of 'thunk'.
* [ok probably]
* RETURNS
LPCSTR dll16, /* [in] name of win16 dll */
LPCSTR dll32 /* [in] name of win32 dll */
) {
- HMODULE hkrnl32 = GetModuleHandleA("KERNEL32");
LPDWORD addr,addr2;
/* FIXME: add checks for valid code ... */
/* write pointers to kernel32.89 and kernel32.90 (+ordinal base of 1) */
- *(DWORD*)(thunk+0x35) = (DWORD)GetProcAddress(hkrnl32,(LPSTR)90);
- *(DWORD*)(thunk+0x6D) = (DWORD)GetProcAddress(hkrnl32,(LPSTR)89);
+ *(DWORD*)(thunk+0x35) = (DWORD)GetProcAddress(kernel32_handle,(LPSTR)90);
+ *(DWORD*)(thunk+0x6D) = (DWORD)GetProcAddress(kernel32_handle,(LPSTR)89);
+
-
if (!(addr = _loadthunk( dll16, thkbuf, dll32, NULL, len )))
return 0;
/***********************************************************************
* FT_PrologPrime (KERNEL32.89)
- *
+ *
* This function is called from the relay code installed by
- * ThunkInitLSF. It replaces the location from where it was
+ * ThunkInitLSF. It replaces the location from where it was
* called by a standard FT_Prolog call stub (which is 'primed'
* by inserting the correct target table pointer).
* Finally, it calls that stub.
- *
+ *
* Input: ECX target number + flags (passed through to FT_Prolog)
- * (ESP) offset of location where target table pointer
+ * (ESP) offset of location where target table pointer
* is stored, relative to the start of the relay code
* (ESP+4) pointer to start of relay code
* (this is where the FT_Prolog call stub gets written to)
- *
+ *
* Note: The two DWORD arguments get popped off the stack.
- *
+ *
*/
void WINAPI FT_PrologPrime( CONTEXT86 *context )
{
/***********************************************************************
* QT_ThunkPrime (KERNEL32.90)
*
- * This function corresponds to FT_PrologPrime, but installs a
+ * This function corresponds to FT_PrologPrime, but installs a
* call stub for QT_Thunk instead.
*
* Input: (EBP-4) target number (passed through to QT_Thunk)
* EDX target table pointer location offset
* EAX start of relay code
- *
+ *
*/
void WINAPI QT_ThunkPrime( CONTEXT86 *context )
{
}
/**********************************************************************
- * SSInit KERNEL.700
+ * SSInit (KERNEL.700)
* RETURNS
* TRUE for success.
*/
}
/**********************************************************************
- * SSOnBigStack KERNEL32.87
+ * SSOnBigStack (KERNEL32.87)
* Check if thunking is initialized (ss selector set up etc.)
* We do that differently, so just return TRUE.
* [ok]
}
/**********************************************************************
- * SSConfirmSmallStack KERNEL.704
+ * SSConfirmSmallStack (KERNEL.704)
*
* Abort if not on small stack.
*
}
/**********************************************************************
- * SSCall
+ * SSCall (KERNEL32.88)
* One of the real thunking functions. This one seems to be for 32<->32
* thunks. It should probably be capable of crossing processboundaries.
*
if(TRACE_ON(thunk))
{
DPRINTF("(%ld,0x%08lx,%p,[",nr,flags,fun);
- for (i=0;i<nr/4;i++)
+ for (i=0;i<nr/4;i++)
DPRINTF("0x%08lx,",args[i]);
DPRINTF("])\n");
}
}
/**********************************************************************
- * AllocSLCallback (KERNEL32)
+ * AllocSLCallback (KERNEL32.@)
*
+ * NOTES
* Win95 uses some structchains for callbacks. It allocates them
* in blocks of 100 entries, size 32 bytes each, layout:
* blockstart:
- * 0: PTR nextblockstart
- * 4: entry *first;
- * 8: WORD sel ( start points to blockstart)
- * A: WORD unknown
+ *| 0: PTR nextblockstart
+ *| 4: entry *first;
+ *| 8: WORD sel ( start points to blockstart)
+ *| A: WORD unknown
* 100xentry:
- * 00..17: Code
- * 18: PDB *owning_process;
- * 1C: PTR blockstart
+ *| 00..17: Code
+ *| 18: PDB *owning_process;
+ *| 1C: PTR blockstart
*
* We ignore this for now. (Just a note for further developers)
* FIXME: use this method, so we don't waste selectors...
* Following code is then generated by AllocSLCallback. The code is 16 bit, so
* the 0x66 prefix switches from word->long registers.
*
- * 665A pop edx
- * 6668x arg2 x pushl <arg2>
- * 6652 push edx
- * EAx arg1 x jmpf <arg1>
+ *| 665A pop edx
+ *| 6668x arg2 x pushl <arg2>
+ *| 6652 push edx
+ *| EAx arg1 x jmpf <arg1>
*
* returns the startaddress of this thunk.
*
- * Note, that they look very similair to the ones allocates by THUNK_Alloc.
+ * Note, that they look very similar to the ones allocates by THUNK_Alloc.
* RETURNS
- * segmented pointer to the start of the thunk
+ * A segmented pointer to the start of the thunk
*/
DWORD WINAPI
AllocSLCallback(
- DWORD finalizer, /* [in] finalizer function */
- DWORD callback /* [in] callback function */
+ DWORD finalizer, /* [in] Finalizer function */
+ DWORD callback /* [in] Callback function */
) {
LPBYTE x,thunk = HeapAlloc( GetProcessHeap(), 0, 32 );
WORD sel;
}
/**********************************************************************
- * FreeSLCallback (KERNEL32.274)
+ * FreeSLCallback (KERNEL32.@)
* Frees the specified 16->32 callback
*/
void WINAPI
* GetTEBSelectorFS (KERNEL.475)
* Set the 16-bit %fs to the 32-bit %fs (current TEB selector)
*/
-void WINAPI GetTEBSelectorFS16(void)
+void WINAPI GetTEBSelectorFS16(void)
{
- CURRENT_STACK16->fs = __get_fs();
+ CURRENT_STACK16->fs = wine_get_fs();
}
/**********************************************************************
* IsPeFormat (KERNEL.431)
- * Checks the passed filename if it is a PE format executeable
+ *
+ * Determine if a file is a PE format executable.
+ *
* RETURNS
* TRUE, if it is.
- * FALSE if not.
+ * FALSE if the file could not be opened or is not a PE file.
+ *
+ * NOTES
+ * If fn is given as NULL then the function expects hf16 to be valid.
*/
BOOL16 WINAPI IsPeFormat16(
- LPSTR fn, /* [in] filename to executeable */
- HFILE16 hf16 /* [in] open file, if filename is NULL */
-) {
+ LPSTR fn, /* [in] Filename to the executeable */
+ HFILE16 hf16) /* [in] An open file handle */
+{
BOOL ret = FALSE;
IMAGE_DOS_HEADER mzh;
OFSTRUCT ofs;
/***********************************************************************
- * K32Thk1632Prolog (KERNEL32.492)
+ * K32Thk1632Prolog (KERNEL32.@)
*/
void WINAPI K32Thk1632Prolog( CONTEXT86 *context )
{
This means that SYSTHUNK.DLL itself switches to a 32-bit stack,
and does a far call to the 32-bit code segment of OLECLI32/OLESVR32.
Unfortunately, our CallTo/CallFrom mechanism is therefore completely
- bypassed, which means it will crash the next time the 32-bit OLE
+ bypassed, which means it will crash the next time the 32-bit OLE
code thunks down again to 16-bit (this *will* happen!).
The following hack tries to recognize this situation.
If we recognize this situation, we try to simulate the actions
of our CallTo/CallFrom mechanism by copying the 16-bit stack
- to our 32-bit stack, creating a proper STACK16FRAME and
- updating cur_stack. */
+ to our 32-bit stack, creating a proper STACK16FRAME and
+ updating cur_stack. */
if ( code[5] == 0xFF && code[6] == 0x55 && code[7] == 0xFC
&& code[13] == 0x66 && code[14] == 0xCB)
}
/***********************************************************************
- * K32Thk1632Epilog (KERNEL32.491)
+ * K32Thk1632Epilog (KERNEL32.@)
*/
void WINAPI K32Thk1632Epilog( CONTEXT86 *context )
{
void WINAPI C16ThkSL(CONTEXT86 *context)
{
LPBYTE stub = MapSL(context->Eax), x = stub;
- WORD cs = __get_cs();
- WORD ds = __get_ds();
+ WORD cs = wine_get_cs();
+ WORD ds = wine_get_ds();
/* We produce the following code:
*
struct ThunkDataSL *td = SL16->fpData;
DWORD procAddress = (DWORD)GetProcAddress16(GetModuleHandle16("KERNEL"), (LPCSTR)631);
- WORD cs = __get_cs();
+ WORD cs = wine_get_cs();
if (!td)
{
else
{
struct ThunkDataSL *td = (struct ThunkDataSL *)context->Edx;
- DWORD targetNr = CX_reg(context) / 4;
+ DWORD targetNr = LOWORD(context->Ecx) / 4;
struct SLTargetDB *tdb;
TRACE("Process %08lx calling target %ld of ThunkDataSL %08lx\n",
else
{
WORD *stack = MapSL( MAKESEGPTR(context->SegSs, LOWORD(context->Esp)) );
- DX_reg(context) = HIWORD(td->apiDB[targetNr].errorReturnValue);
- AX_reg(context) = LOWORD(td->apiDB[targetNr].errorReturnValue);
+ context->Edx = (context->Edx & ~0xffff) | HIWORD(td->apiDB[targetNr].errorReturnValue);
+ context->Eax = (context->Eax & ~0xffff) | LOWORD(td->apiDB[targetNr].errorReturnValue);
context->Eip = stack[2];
context->SegCs = stack[3];
context->Esp += td->apiDB[targetNr].nrArgBytes + 4;
#define THUNKLET_TYPE_SL 2
static HANDLE ThunkletHeap = 0;
+static WORD ThunkletCodeSel;
static THUNKLET *ThunkletAnchor = NULL;
static FARPROC ThunkletSysthunkGlueLS = 0;
static FARPROC ThunkletCallbackGlueLS = 0;
static SEGPTR ThunkletCallbackGlueSL = 0;
+
+/* map a thunk allocated on ThunkletHeap to a 16-bit pointer */
+inline static SEGPTR get_segptr( void *thunk )
+{
+ if (!thunk) return 0;
+ return MAKESEGPTR( ThunkletCodeSel, (char *)thunk - (char *)ThunkletHeap );
+}
+
/***********************************************************************
* THUNK_Init
*/
-BOOL THUNK_Init(void)
+static BOOL THUNK_Init(void)
{
LPBYTE thunk;
- ThunkletHeap = HeapCreate(HEAP_WINE_SEGPTR | HEAP_WINE_CODE16SEG, 0, 0);
+ ThunkletHeap = HeapCreate( 0, 0x10000, 0x10000 );
if (!ThunkletHeap) return FALSE;
+ ThunkletCodeSel = SELECTOR_AllocBlock( (void *)ThunkletHeap, 0x10000, WINE_LDT_FLAGS_CODE );
+
thunk = HeapAlloc( ThunkletHeap, 0, 5 );
if (!thunk) return FALSE;
-
+
ThunkletSysthunkGlueLS = (FARPROC)thunk;
*thunk++ = 0x58; /* popl eax */
*thunk++ = 0xC3; /* ret */
- ThunkletSysthunkGlueSL = HEAP_GetSegptr( ThunkletHeap, 0, thunk );
+ ThunkletSysthunkGlueSL = get_segptr( thunk );
*thunk++ = 0x66; *thunk++ = 0x58; /* popl eax */
*thunk++ = 0xCB; /* lret */
/***********************************************************************
* THUNK_FindThunklet
*/
-THUNKLET *THUNK_FindThunklet( DWORD target, DWORD relay,
- DWORD glue, BYTE type )
+THUNKLET *THUNK_FindThunklet( DWORD target, DWORD relay,
+ DWORD glue, BYTE type )
{
- THUNKLET *thunk;
+ THUNKLET *thunk;
for (thunk = ThunkletAnchor; thunk; thunk = thunk->next)
if ( thunk->type == type
&& thunk->target == target
- && thunk->relay == relay
+ && thunk->relay == relay
&& ( type == THUNKLET_TYPE_LS ?
( thunk->glue == glue - (DWORD)&thunk->type )
: ( thunk->glue == glue ) ) )
/***********************************************************************
* THUNK_AllocLSThunklet
*/
-FARPROC THUNK_AllocLSThunklet( SEGPTR target, DWORD relay,
- FARPROC glue, HTASK16 owner )
+FARPROC THUNK_AllocLSThunklet( SEGPTR target, DWORD relay,
+ FARPROC glue, HTASK16 owner )
{
THUNKLET *thunk = THUNK_FindThunklet( (DWORD)target, relay, (DWORD)glue,
THUNKLET_TYPE_LS );
if (!thunk)
{
- TDB *pTask = (TDB*)GlobalLock16( owner );
+ TDB *pTask = GlobalLock16( owner );
+ if (!ThunkletHeap) THUNK_Init();
if ( !(thunk = HeapAlloc( ThunkletHeap, 0, sizeof(THUNKLET) )) )
return 0;
THUNKLET_TYPE_SL );
if (!thunk)
{
- TDB *pTask = (TDB*)GlobalLock16( owner );
+ TDB *pTask = GlobalLock16( owner );
+ if (!ThunkletHeap) THUNK_Init();
if ( !(thunk = HeapAlloc( ThunkletHeap, 0, sizeof(THUNKLET) )) )
return 0;
ThunkletAnchor = thunk;
}
- return HEAP_GetSegptr( ThunkletHeap, 0, thunk );
+ return get_segptr( thunk );
}
/**********************************************************************
/***********************************************************************
* AllocLSThunkletSysthunk (KERNEL.607)
*/
-FARPROC WINAPI AllocLSThunkletSysthunk16( SEGPTR target,
+FARPROC WINAPI AllocLSThunkletSysthunk16( SEGPTR target,
FARPROC relay, DWORD dummy )
{
- return THUNK_AllocLSThunklet( (SEGPTR)relay, (DWORD)target,
+ if (!ThunkletSysthunkGlueLS) THUNK_Init();
+ return THUNK_AllocLSThunklet( (SEGPTR)relay, (DWORD)target,
ThunkletSysthunkGlueLS, GetCurrentTask() );
}
/***********************************************************************
* AllocSLThunkletSysthunk (KERNEL.608)
*/
-SEGPTR WINAPI AllocSLThunkletSysthunk16( FARPROC target,
+SEGPTR WINAPI AllocSLThunkletSysthunk16( FARPROC target,
SEGPTR relay, DWORD dummy )
{
- return THUNK_AllocSLThunklet( (FARPROC)relay, (DWORD)target,
+ if (!ThunkletSysthunkGlueSL) THUNK_Init();
+ return THUNK_AllocSLThunklet( (FARPROC)relay, (DWORD)target,
ThunkletSysthunkGlueSL, GetCurrentTask() );
}
/***********************************************************************
* AllocLSThunkletCallbackEx (KERNEL.567)
*/
-FARPROC WINAPI AllocLSThunkletCallbackEx16( SEGPTR target,
+FARPROC WINAPI AllocLSThunkletCallbackEx16( SEGPTR target,
DWORD relay, HTASK16 task )
{
THUNKLET *thunk = MapSL( target );
if ( !thunk ) return NULL;
- if ( IsSLThunklet16( thunk ) && thunk->relay == relay
+ if ( IsSLThunklet16( thunk ) && thunk->relay == relay
&& thunk->glue == (DWORD)ThunkletCallbackGlueSL )
return (FARPROC)thunk->target;
- return THUNK_AllocLSThunklet( target, relay,
+ return THUNK_AllocLSThunklet( target, relay,
ThunkletCallbackGlueLS, task );
}
/***********************************************************************
* AllocSLThunkletCallbackEx (KERNEL.568)
*/
-SEGPTR WINAPI AllocSLThunkletCallbackEx16( FARPROC target,
+SEGPTR WINAPI AllocSLThunkletCallbackEx16( FARPROC target,
DWORD relay, HTASK16 task )
{
THUNKLET *thunk = (THUNKLET *)target;
if ( !thunk ) return 0;
- if ( IsLSThunklet( thunk ) && thunk->relay == relay
+ if ( IsLSThunklet( thunk ) && thunk->relay == relay
&& thunk->glue == (DWORD)ThunkletCallbackGlueLS - (DWORD)&thunk->type )
return (SEGPTR)thunk->target;
- return THUNK_AllocSLThunklet( target, relay,
+ return THUNK_AllocSLThunklet( target, relay,
ThunkletCallbackGlueSL, task );
}
/***********************************************************************
- * AllocLSThunkletCallback (KERNEL.561) (KERNEL.606)
+ * AllocLSThunkletCallback (KERNEL.561)
+ * AllocLSThunkletCallback_dup (KERNEL.606)
*/
FARPROC WINAPI AllocLSThunkletCallback16( SEGPTR target, DWORD relay )
{
}
/***********************************************************************
- * AllocSLThunkletCallback (KERNEL.562) (KERNEL.605)
+ * AllocSLThunkletCallback (KERNEL.562)
+ * AllocSLThunkletCallback_dup (KERNEL.605)
*/
SEGPTR WINAPI AllocSLThunkletCallback16( FARPROC target, DWORD relay )
{
}
/***********************************************************************
- * FindLSThunkletCallback (KERNEL.563) (KERNEL.609)
+ * FindLSThunkletCallback (KERNEL.563)
+ * FindLSThunkletCallback_dup (KERNEL.609)
*/
FARPROC WINAPI FindLSThunkletCallback( SEGPTR target, DWORD relay )
{
THUNKLET *thunk = MapSL( target );
- if ( thunk && IsSLThunklet16( thunk ) && thunk->relay == relay
+ if ( thunk && IsSLThunklet16( thunk ) && thunk->relay == relay
&& thunk->glue == (DWORD)ThunkletCallbackGlueSL )
return (FARPROC)thunk->target;
- thunk = THUNK_FindThunklet( (DWORD)target, relay,
- (DWORD)ThunkletCallbackGlueLS,
+ thunk = THUNK_FindThunklet( (DWORD)target, relay,
+ (DWORD)ThunkletCallbackGlueLS,
THUNKLET_TYPE_LS );
return (FARPROC)thunk;
}
/***********************************************************************
- * FindSLThunkletCallback (KERNEL.564) (KERNEL.610)
+ * FindSLThunkletCallback (KERNEL.564)
+ * FindSLThunkletCallback_dup (KERNEL.610)
*/
SEGPTR WINAPI FindSLThunkletCallback( FARPROC target, DWORD relay )
{
THUNKLET *thunk = (THUNKLET *)target;
- if ( thunk && IsLSThunklet( thunk ) && thunk->relay == relay
+ if ( thunk && IsLSThunklet( thunk ) && thunk->relay == relay
&& thunk->glue == (DWORD)ThunkletCallbackGlueLS - (DWORD)&thunk->type )
return (SEGPTR)thunk->target;
- thunk = THUNK_FindThunklet( (DWORD)target, relay,
- (DWORD)ThunkletCallbackGlueSL,
+ thunk = THUNK_FindThunklet( (DWORD)target, relay,
+ (DWORD)ThunkletCallbackGlueSL,
THUNKLET_TYPE_SL );
- return HEAP_GetSegptr( ThunkletHeap, 0, thunk );
+ return get_segptr( thunk );
}
/***********************************************************************
- * FreeThunklet16 (KERNEL.611)
+ * FreeThunklet (KERNEL.611)
*/
BOOL16 WINAPI FreeThunklet16( DWORD unused1, DWORD unused2 )
{
/***********************************************************************
* RegisterCBClient (KERNEL.619)
*/
-INT16 WINAPI RegisterCBClient16( INT16 wCBCId,
+INT16 WINAPI RegisterCBClient16( INT16 wCBCId,
SEGPTR relay16, FARPROC *relay32 )
{
/* Search for free Callback ID */
/***********************************************************************
* UnRegisterCBClient (KERNEL.622)
*/
-INT16 WINAPI UnRegisterCBClient16( INT16 wCBCId,
+INT16 WINAPI UnRegisterCBClient16( INT16 wCBCId,
SEGPTR relay16, FARPROC *relay32 )
{
- if ( wCBCId >= N_CBC_FIXED && wCBCId < N_CBC_TOTAL
- && CBClientRelay16[ wCBCId ] == relay16
+ if ( wCBCId >= N_CBC_FIXED && wCBCId < N_CBC_TOTAL
+ && CBClientRelay16[ wCBCId ] == relay16
&& CBClientRelay32[ wCBCId ] == relay32 )
{
CBClientRelay16[ wCBCId ] = 0;
SEGPTR stackSeg = stack16_push( 12 );
LPWORD stackLin = MapSL( stackSeg );
SEGPTR glue, *glueTab;
-
- stackLin[3] = BP_reg( context );
- stackLin[2] = SI_reg( context );
- stackLin[1] = DI_reg( context );
- stackLin[0] = context->SegDs;
+
+ stackLin[3] = (WORD)context->Ebp;
+ stackLin[2] = (WORD)context->Esi;
+ stackLin[1] = (WORD)context->Edi;
+ stackLin[0] = (WORD)context->SegDs;
context->Ebp = OFFSETOF( stackSeg ) + 6;
context->Esp = OFFSETOF( stackSeg ) - 4;
{
/* Call 32-bit relay code */
- LPWORD args = MapSL( MAKESEGPTR( context->SegSs, BP_reg( context ) ) );
+ LPWORD args = MapSL( MAKESEGPTR( context->SegSs, LOWORD(context->Ebp) ) );
FARPROC proc = CBClientRelay32[ args[2] ][ args[1] ];
context->Eax = CALL32_CBClient( proc, args, &context->Esi );
{
/* Call 32-bit relay code */
- LPWORD args = MapSL( MAKESEGPTR( context->SegSs, BP_reg( context ) ) );
+ LPWORD args = MapSL( MAKESEGPTR( context->SegSs, LOWORD(context->Ebp) ) );
FARPROC proc = CBClientRelay32[ args[2] ][ args[1] ];
INT nArgs;
LPWORD stackLin;
/* Restore registers saved by CBClientGlueSL */
stackLin = (LPWORD)((LPBYTE)CURRENT_STACK16 + sizeof(STACK16FRAME) - 4);
- BP_reg( context ) = stackLin[3];
- SI_reg( context ) = stackLin[2];
- DI_reg( context ) = stackLin[1];
+ context->Ebp = (context->Ebp & ~0xffff) | stackLin[3];
+ context->Esi = (context->Esi & ~0xffff) | stackLin[2];
+ context->Edi = (context->Edi & ~0xffff) | stackLin[1];
context->SegDs = stackLin[0];
context->Esp += 16+nArgs;
/***********************************************************************
- * Get16DLLAddress (KERNEL32)
+ * Get16DLLAddress (KERNEL32.@)
*
* This function is used by a Win32s DLL if it wants to call a Win16 function.
* A 16:16 segmented pointer to the function is returned.
* Written without any docu.
*/
-SEGPTR WINAPI Get16DLLAddress(HMODULE handle, LPSTR func_name) {
- HANDLE ThunkHeap = HeapCreate(HEAP_WINE_SEGPTR | HEAP_WINE_CODESEG, 0, 64);
- LPBYTE x;
- LPVOID tmpheap = HeapAlloc(ThunkHeap, 0, 32);
- SEGPTR thunk = HEAP_GetSegptr(ThunkHeap, 0, tmpheap);
- DWORD proc_16;
+SEGPTR WINAPI Get16DLLAddress(HMODULE16 handle, LPSTR func_name)
+{
+ static WORD code_sel32;
+ FARPROC16 proc_16;
+ LPBYTE thunk;
+
+ if (!code_sel32)
+ {
+ if (!ThunkletHeap) THUNK_Init();
+ code_sel32 = SELECTOR_AllocBlock( (void *)ThunkletHeap, 0x10000,
+ WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT );
+ if (!code_sel32) return 0;
+ }
+ if (!(thunk = HeapAlloc( ThunkletHeap, 0, 32 ))) return 0;
- if (!handle) handle=GetModuleHandle16("WIN32S16");
- proc_16 = (DWORD)GetProcAddress16(handle, func_name);
+ if (!handle) handle = GetModuleHandle16("WIN32S16");
+ proc_16 = GetProcAddress16(handle, func_name);
- x=MapSL(thunk);
- *x++=0xba; *(DWORD*)x=proc_16;x+=4; /* movl proc_16, $edx */
- *x++=0xea; *(DWORD*)x=(DWORD)GetProcAddress(GetModuleHandleA("KERNEL32"),"QT_Thunk");x+=4; /* jmpl QT_Thunk */
- *(WORD*)x=__get_cs();
- return thunk;
+ /* movl proc_16, $edx */
+ *thunk++ = 0xba;
+ *(FARPROC16 *)thunk = proc_16;
+ thunk += sizeof(FARPROC16);
+
+ /* jmpl QT_Thunk */
+ *thunk++ = 0xea;
+ *(FARPROC *)thunk = GetProcAddress(kernel32_handle,"QT_Thunk");
+ thunk += sizeof(FARPROC16);
+ *(WORD *)thunk = wine_get_cs();
+
+ return MAKESEGPTR( code_sel32, (char *)thunk - (char *)ThunkletHeap );
}
*/
void WINAPI CommonUnimpStub( CONTEXT86 *context )
{
- if (context->Eax)
- MESSAGE( "*** Unimplemented Win32 API: %s\n", (LPSTR)context->Eax );
+ FIXME("generic stub: %s\n", ((LPSTR)context->Eax ? (LPSTR)context->Eax : "?"));
switch ((context->Ecx >> 4) & 0x0f)
{
}
/**********************************************************************
- * _KERNEL32_100
+ * @ (KERNEL32.100)
*/
BOOL WINAPI _KERNEL32_100(HANDLE threadid,DWORD exitcode,DWORD x)
{
- FIXME("(%d,%ld,0x%08lx): stub\n",threadid,exitcode,x);
+ FIXME("(%p,%ld,0x%08lx): stub\n",threadid,exitcode,x);
return TRUE;
}
/**********************************************************************
- * _KERNEL32_99
+ * @ (KERNEL32.99)
+ *
+ * Checks whether the clock has to be switched from daylight
+ * savings time to standard time or vice versa.
+ *
*/
DWORD WINAPI _KERNEL32_99(DWORD x)
{
lpbuf[6] = context->SegDs;
lpbuf[7] = 0;
lpbuf[8] = context->SegSs;
- AX_reg(context) = 0; /* Return 0 */
+ context->Eax &= ~0xffff; /* Return 0 */
}
{
STACK16FRAME *pFrame;
STACK32FRAME *frame32;
- TEB *teb = NtCurrentTeb();
- AX_reg(context) = retval;
+ context->Eax = (context->Eax & ~0xffff) | (WORD)retval;
/* Find the frame32 corresponding to the frame16 we are jumping to */
- pFrame = THREAD_STACK16(teb);
+ pFrame = CURRENT_STACK16;
frame32 = pFrame->frame32;
while (frame32 && frame32->frame16)
{
- if (OFFSETOF(frame32->frame16) < OFFSETOF(teb->cur_stack))
+ if (OFFSETOF(frame32->frame16) < OFFSETOF(NtCurrentTeb()->cur_stack))
break; /* Something strange is going on */
if (OFFSETOF(frame32->frame16) > lpbuf[2])
{
}
frame32 = ((STACK16FRAME *)MapSL(frame32->frame16))->frame32;
}
+ RtlUnwind( &pFrame->frame32->frame, NULL, NULL, 0 );
context->Eip = lpbuf[0];
context->SegCs = lpbuf[1];