blob: 74f42c1b1b07ade9f44b83d5a43c1878120e32cf [file] [log] [blame]
/*
* Win32s Universal Thunk API
*
* Copyright 1999 Ulrich Weigand
*/
#include "wine/winbase16.h"
#include "ntddk.h"
#include "heap.h"
#include "module.h"
#include "callback.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(thunk);
#include "pshpack1.h"
typedef struct
{
BYTE popl_eax;
BYTE pushl;
DWORD target;
BYTE pushl_eax;
BYTE ljmp;
DWORD utglue16;
} UT16THUNK;
typedef struct
{
BYTE popl_eax;
BYTE pushl;
DWORD target;
BYTE pushl_eax;
BYTE jmp;
DWORD utglue32;
} UT32THUNK;
#include "poppack.h"
typedef struct _UTINFO
{
struct _UTINFO *next;
HMODULE hModule;
HMODULE16 hModule16;
UT16THUNK ut16;
UT32THUNK ut32;
} UTINFO;
static UTINFO *UT_head; /* head of Universal Thunk list */
typedef DWORD CALLBACK (*UTGLUEPROC)( LPVOID lpBuff, DWORD dwUserDefined );
BOOL WINAPI UTRegister( HMODULE hModule, LPSTR lpsz16BITDLL,
LPSTR lpszInitName, LPSTR lpszProcName,
FARPROC *ppfn32Thunk, FARPROC pfnUT32CallBack,
LPVOID lpBuff );
VOID WINAPI UTUnRegister( HMODULE hModule );
/* ### start build ### */
extern LONG CALLBACK UTTHUNK_CallTo16_long_ll(FARPROC16,LONG,LONG);
/* ### stop build ### */
/****************************************************************************
* UTGlue16 (KERNEL.666) (KERNEL Wine-specific export)
*/
DWORD WINAPI UTGlue16( LPVOID lpBuff, DWORD dwUserDefined, SEGPTR *translationList,
UTGLUEPROC target )
{
INT i;
/* Convert arguments to flat pointers */
if ( translationList )
for ( i = 0; translationList[i]; i++ )
{
LPVOID flatPtr = MapSL( translationList[i] );
*(LPVOID *)flatPtr = MapSL( *(SEGPTR *)flatPtr );
}
/* Call 32-bit routine */
return target( lpBuff, dwUserDefined );
}
/****************************************************************************
* UTGlue32
*/
static DWORD WINAPI UTGlue32( FARPROC16 target, LPVOID lpBuff, DWORD dwUserDefined,
LPVOID translationList[] )
{
SEGPTR segBuff, *segptrList = NULL;
INT i, nList = 0;
DWORD retv;
/* Convert arguments to SEGPTRs */
if ( translationList )
for ( nList = 0; translationList[nList]; nList++ )
;
if ( nList )
{
segptrList = HeapAlloc( GetProcessHeap(), 0, sizeof(SEGPTR)*nList );
if ( !segptrList )
{
FIXME("Unable to allocate segptrList!" );
return 0;
}
for ( i = 0; i < nList; i++ )
segptrList[i] = *(SEGPTR *)translationList[i]
= MapLS( *(LPVOID *)translationList[i] );
}
segBuff = MapLS( lpBuff );
/* Call 16-bit routine */
retv = UTTHUNK_CallTo16_long_ll( target, segBuff, dwUserDefined );
/* Free temporary selectors */
UnMapLS( segBuff );
if ( nList )
{
for ( i = 0; i < nList; i++ )
UnMapLS( segptrList[i] );
HeapFree( GetProcessHeap(), 0, segptrList );
}
return retv;
}
/****************************************************************************
* UTAlloc
*/
static UTINFO *UTAlloc( HMODULE hModule, HMODULE16 hModule16,
FARPROC16 target16, FARPROC target32 )
{
static FARPROC16 UTGlue16_Segptr = NULL;
UTINFO *ut;
if ( !UTGlue16_Segptr )
{
HMODULE16 hModule = GetModuleHandle16( "KERNEL" );
UTGlue16_Segptr = GetProcAddress16( hModule, "UTGlue16" );
if ( !UTGlue16_Segptr ) return NULL;
}
ut = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY|HEAP_WINE_SEGPTR, sizeof(UTINFO) );
if ( !ut ) return NULL;
ut->hModule = hModule;
ut->hModule16 = hModule16;
ut->ut16.popl_eax = 0x58;
ut->ut16.pushl = 0x68;
ut->ut16.target = (DWORD)target32;
ut->ut16.pushl_eax = 0x50;
ut->ut16.ljmp = 0xea;
ut->ut16.utglue16 = (DWORD)UTGlue16_Segptr;
ut->ut32.popl_eax = 0x58;
ut->ut32.pushl = 0x68;
ut->ut32.target = (DWORD)target16;
ut->ut32.pushl_eax = 0x50;
ut->ut32.jmp = 0xe9;
ut->ut32.utglue32 = (DWORD)UTGlue32 - ((DWORD)&ut->ut32.utglue32 + sizeof(DWORD));
ut->next = UT_head;
UT_head = ut;
return ut;
}
/****************************************************************************
* UTFree
*/
static void UTFree( UTINFO *ut )
{
UTINFO **ptr;
for ( ptr = &UT_head; *ptr; ptr = &(*ptr)->next )
if ( *ptr == ut )
{
*ptr = ut->next;
break;
}
HeapFree( GetProcessHeap(), HEAP_WINE_SEGPTR, ut );
}
/****************************************************************************
* UTFind
*/
static UTINFO *UTFind( HMODULE hModule )
{
UTINFO *ut;
for ( ut = UT_head; ut; ut =ut->next )
if ( ut->hModule == hModule )
break;
return ut;
}
/****************************************************************************
* UTRegister (KERNEL32.698)
*/
BOOL WINAPI UTRegister( HMODULE hModule, LPSTR lpsz16BITDLL,
LPSTR lpszInitName, LPSTR lpszProcName,
FARPROC *ppfn32Thunk, FARPROC pfnUT32CallBack,
LPVOID lpBuff )
{
UTINFO *ut;
HMODULE16 hModule16;
FARPROC16 target16, init16;
/* Load 16-bit DLL and get UTProc16 entry point */
if ( (hModule16 = LoadLibrary16( lpsz16BITDLL )) <= 32
|| (target16 = GetProcAddress16( hModule16, lpszProcName )) == 0 )
return FALSE;
/* Allocate UTINFO struct */
RtlAcquirePebLock();
if ( (ut = UTFind( hModule )) != NULL )
ut = NULL;
else
ut = UTAlloc( hModule, hModule16, target16, pfnUT32CallBack );
RtlReleasePebLock();
if ( !ut )
{
FreeLibrary16( hModule16 );
return FALSE;
}
/* Call UTInit16 if present */
if ( lpszInitName
&& (init16 = GetProcAddress16( hModule16, lpszInitName )) != 0 )
{
SEGPTR callback = SEGPTR_GET( &ut->ut16 );
SEGPTR segBuff = MapLS( lpBuff );
if ( !UTTHUNK_CallTo16_long_ll( init16, callback, segBuff ) )
{
UnMapLS( segBuff );
UTUnRegister( hModule );
return FALSE;
}
UnMapLS( segBuff );
}
/* Return 32-bit thunk */
*ppfn32Thunk = (FARPROC) &ut->ut32;
return TRUE;
}
/****************************************************************************
* UTUnRegister (KERNEL32.699)
*/
VOID WINAPI UTUnRegister( HMODULE hModule )
{
UTINFO *ut;
HMODULE16 hModule16 = 0;
RtlAcquirePebLock();
ut = UTFind( hModule );
if ( !ut )
{
hModule16 = ut->hModule16;
UTFree( ut );
}
RtlReleasePebLock();
if ( hModule16 )
FreeLibrary16( hModule16 );
}
/****************************************************************************
* UTInit16 (KERNEL.493)
*/
WORD WINAPI UTInit16( DWORD x1, DWORD x2, DWORD x3, DWORD x4 )
{
FIXME("(%08lx, %08lx, %08lx, %08lx): stub\n", x1, x2, x3, x4 );
return 0;
}