/* * Win32s Universal Thunk API * * Copyright 1999 Ulrich Weigand */ #include "wine/winbase16.h" #include "windef.h" #include "heap.h" #include "module.h" #include "selectors.h" #include "callback.h" #include "process.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; 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 (WPROCS.*) */ 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 = PTR_SEG_TO_LIN( translationList[i] ); *(LPVOID *)flatPtr = PTR_SEG_TO_LIN( *(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( "WPROCS" ); int ordinal = NE_GetOrdinal( hModule, "UTGlue16" ); if ( hModule && ordinal ) UTGlue16_Segptr = NE_GetEntryPoint( hModule, ordinal ); if ( !UTGlue16_Segptr ) return NULL; } ut = HeapAlloc( SegptrHeap, HEAP_ZERO_MEMORY, 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 = PROCESS_Current()->UTState; PROCESS_Current()->UTState = ut; return ut; } /**************************************************************************** * UTFree */ static void UTFree( UTINFO *ut ) { UTINFO **ptr; for ( ptr = &PROCESS_Current()->UTState; *ptr; ptr = &(*ptr)->next ) if ( *ptr == ut ) { *ptr = ut->next; break; } HeapFree( SegptrHeap, 0, ut ); } /**************************************************************************** * UTFind */ static UTINFO *UTFind( HMODULE hModule ) { UTINFO *ut; for ( ut = PROCESS_Current()->UTState; ut; ut =ut->next ) if ( ut->hModule == hModule ) break; return ut; } /**************************************************************************** * UTRegister (KERNEL32.697) */ 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 = WIN32_GetProcAddress16( hModule16, lpszProcName )) == 0 ) return FALSE; /* Allocate UTINFO struct */ EnterCriticalSection( &PROCESS_Current()->crit_section ); if ( (ut = UTFind( hModule )) != NULL ) ut = NULL; else ut = UTAlloc( hModule, hModule16, target16, pfnUT32CallBack ); LeaveCriticalSection( &PROCESS_Current()->crit_section ); if ( !ut ) { FreeLibrary16( hModule16 ); return FALSE; } /* Call UTInit16 if present */ if ( lpszInitName && (init16 = WIN32_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.698) */ VOID WINAPI UTUnRegister( HMODULE hModule ) { UTINFO *ut; HMODULE16 hModule16 = 0; EnterCriticalSection( &PROCESS_Current()->crit_section ); ut = UTFind( hModule ); if ( !ut ) { hModule16 = ut->hModule16; UTFree( ut ); } LeaveCriticalSection( &PROCESS_Current()->crit_section ); if ( hModule16 ) FreeLibrary16( hModule16 ); } /**************************************************************************** * UTInit16 (KERNEL.494) */ WORD WINAPI UTInit16( DWORD x1, DWORD x2, DWORD x3, DWORD x4 ) { FIXME("(%08lx, %08lx, %08lx, %08lx): stub\n", x1, x2, x3, x4 ); return 0; }