api-ms-win-core-comm-l1-1-0: Add dll.
[wine.git] / dlls / krnl386.exe16 / wowthunk.c
blobda829950bedae9435c1e442e45ea978f5b157488
1 /*
2 * Win32 WOW Generic Thunk API
4 * Copyright 1999 Ulrich Weigand
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <errno.h>
28 #include "wine/winbase16.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winerror.h"
32 #include "wownt32.h"
33 #include "excpt.h"
34 #include "winternl.h"
35 #include "kernel16_private.h"
36 #include "wine/exception.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(thunk);
40 WINE_DECLARE_DEBUG_CHANNEL(relay);
41 WINE_DECLARE_DEBUG_CHANNEL(snoop);
43 /* symbols exported from relay16.s */
44 extern DWORD WINAPI wine_call_to_16( FARPROC16 target, DWORD cbArgs, PEXCEPTION_HANDLER handler );
45 extern void WINAPI wine_call_to_16_regs( CONTEXT *context, DWORD cbArgs, PEXCEPTION_HANDLER handler );
46 extern void __wine_call_to_16_ret(void);
47 extern void CALL32_CBClient_Ret(void);
48 extern void CALL32_CBClientEx_Ret(void);
49 extern BYTE __wine_call16_start[];
50 extern BYTE __wine_call16_end[];
52 static SEGPTR call16_ret_addr; /* segptr to __wine_call_to_16_ret routine */
54 /***********************************************************************
55 * WOWTHUNK_Init
57 BOOL WOWTHUNK_Init(void)
59 /* allocate the code selector for CallTo16 routines */
60 LDT_ENTRY entry;
61 WORD codesel = wine_ldt_alloc_entries(1);
63 if (!codesel) return FALSE;
64 wine_ldt_set_base( &entry, __wine_call16_start );
65 wine_ldt_set_limit( &entry, (BYTE *)(&CallTo16_TebSelector + 1) - __wine_call16_start - 1 );
66 wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT );
67 wine_ldt_set_entry( codesel, &entry );
69 /* Patch the return addresses for CallTo16 routines */
71 CallTo16_DataSelector = wine_get_ds();
72 call16_ret_addr = MAKESEGPTR( codesel, (BYTE *)__wine_call_to_16_ret - __wine_call16_start );
73 CALL32_CBClient_RetAddr =
74 MAKESEGPTR( codesel, (BYTE *)CALL32_CBClient_Ret - __wine_call16_start );
75 CALL32_CBClientEx_RetAddr =
76 MAKESEGPTR( codesel, (BYTE *)CALL32_CBClientEx_Ret - __wine_call16_start );
78 if (TRACE_ON(relay) || TRACE_ON(snoop)) RELAY16_InitDebugLists();
80 return TRUE;
84 /*************************************************************
85 * fix_selector
87 * Fix a selector load that caused an exception if it's in the
88 * 16-bit relay code.
90 static BOOL fix_selector( CONTEXT *context )
92 WORD *stack;
93 BYTE *instr = (BYTE *)context->Eip;
95 if (instr < __wine_call16_start || instr >= __wine_call16_end) return FALSE;
97 /* skip prefixes */
98 while (*instr == 0x66 || *instr == 0x67) instr++;
100 switch(instr[0])
102 case 0x07: /* pop es */
103 case 0x17: /* pop ss */
104 case 0x1f: /* pop ds */
105 break;
106 case 0x0f: /* extended instruction */
107 switch(instr[1])
109 case 0xa1: /* pop fs */
110 case 0xa9: /* pop gs */
111 break;
112 default:
113 return FALSE;
115 break;
116 default:
117 return FALSE;
119 stack = wine_ldt_get_ptr( context->SegSs, context->Esp );
120 TRACE( "fixing up selector %x for pop instruction\n", *stack );
121 *stack = 0;
122 return TRUE;
126 /*************************************************************
127 * call16_handler
129 * Handler for exceptions occurring in 16-bit code.
131 static DWORD call16_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RECORD *frame,
132 CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **pdispatcher )
134 if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
136 /* unwinding: restore the stack pointer in the TEB, and leave the Win16 mutex */
137 STACK32FRAME *frame32 = CONTAINING_RECORD(frame, STACK32FRAME, frame);
138 NtCurrentTeb()->WOW32Reserved = (void *)frame32->frame16;
139 _LeaveWin16Lock();
141 else if (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
142 record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION)
144 if (wine_ldt_is_system(context->SegCs))
146 if (fix_selector( context )) return ExceptionContinueExecution;
148 else
150 SEGPTR gpHandler;
151 DWORD ret = __wine_emulate_instruction( record, context );
153 if (ret != ExceptionContinueSearch) return ret;
155 /* check for Win16 __GP handler */
156 if ((gpHandler = HasGPHandler16( MAKESEGPTR( context->SegCs, context->Eip ) )))
158 WORD *stack = wine_ldt_get_ptr( context->SegSs, context->Esp );
159 *--stack = context->SegCs;
160 *--stack = context->Eip;
162 if (!IS_SELECTOR_32BIT(context->SegSs))
163 context->Esp = MAKELONG( LOWORD(context->Esp - 2*sizeof(WORD)),
164 HIWORD(context->Esp) );
165 else
166 context->Esp -= 2*sizeof(WORD);
168 context->SegCs = SELECTOROF( gpHandler );
169 context->Eip = OFFSETOF( gpHandler );
170 return ExceptionContinueExecution;
174 return ExceptionContinueSearch;
179 * 32-bit WOW routines (in WOW32, but actually forwarded to KERNEL32)
182 /**********************************************************************
183 * K32WOWGetDescriptor (KERNEL32.70)
185 BOOL WINAPI K32WOWGetDescriptor( SEGPTR segptr, LPLDT_ENTRY ldtent )
187 return GetThreadSelectorEntry( GetCurrentThread(),
188 segptr >> 16, ldtent );
191 /**********************************************************************
192 * K32WOWGetVDMPointer (KERNEL32.56)
194 LPVOID WINAPI K32WOWGetVDMPointer( DWORD vp, DWORD dwBytes, BOOL fProtectedMode )
196 /* FIXME: add size check too */
198 if ( fProtectedMode )
199 return MapSL( vp );
200 else
201 return DOSMEM_MapRealToLinear( vp );
204 /**********************************************************************
205 * K32WOWGetVDMPointerFix (KERNEL32.68)
207 LPVOID WINAPI K32WOWGetVDMPointerFix( DWORD vp, DWORD dwBytes, BOOL fProtectedMode )
210 * Hmmm. According to the docu, we should call:
212 * GlobalFix16( SELECTOROF(vp) );
214 * But this is unnecessary under Wine, as we never move global
215 * memory segments in linear memory anyway.
217 * (I'm not so sure what we are *supposed* to do if
218 * fProtectedMode is TRUE, anyway ...)
221 return K32WOWGetVDMPointer( vp, dwBytes, fProtectedMode );
224 /**********************************************************************
225 * K32WOWGetVDMPointerUnfix (KERNEL32.69)
227 VOID WINAPI K32WOWGetVDMPointerUnfix( DWORD vp )
230 * See above why we don't call:
232 * GlobalUnfix16( SELECTOROF(vp) );
237 /**********************************************************************
238 * K32WOWGlobalAlloc16 (KERNEL32.59)
240 WORD WINAPI K32WOWGlobalAlloc16( WORD wFlags, DWORD cb )
242 return (WORD)GlobalAlloc16( wFlags, cb );
245 /**********************************************************************
246 * K32WOWGlobalFree16 (KERNEL32.62)
248 WORD WINAPI K32WOWGlobalFree16( WORD hMem )
250 return (WORD)GlobalFree16( (HGLOBAL16)hMem );
253 /**********************************************************************
254 * K32WOWGlobalUnlock16 (KERNEL32.61)
256 BOOL WINAPI K32WOWGlobalUnlock16( WORD hMem )
258 return (BOOL)GlobalUnlock16( (HGLOBAL16)hMem );
261 /**********************************************************************
262 * K32WOWGlobalAllocLock16 (KERNEL32.63)
264 DWORD WINAPI K32WOWGlobalAllocLock16( WORD wFlags, DWORD cb, WORD *phMem )
266 WORD hMem = K32WOWGlobalAlloc16( wFlags, cb );
267 if (phMem) *phMem = hMem;
269 return K32WOWGlobalLock16( hMem );
272 /**********************************************************************
273 * K32WOWGlobalLockSize16 (KERNEL32.65)
275 DWORD WINAPI K32WOWGlobalLockSize16( WORD hMem, PDWORD pcb )
277 if ( pcb )
278 *pcb = GlobalSize16( (HGLOBAL16)hMem );
280 return K32WOWGlobalLock16( hMem );
283 /**********************************************************************
284 * K32WOWGlobalUnlockFree16 (KERNEL32.64)
286 WORD WINAPI K32WOWGlobalUnlockFree16( DWORD vpMem )
288 if ( !K32WOWGlobalUnlock16( HIWORD(vpMem) ) )
289 return FALSE;
291 return K32WOWGlobalFree16( HIWORD(vpMem) );
295 /**********************************************************************
296 * K32WOWYield16 (KERNEL32.66)
298 VOID WINAPI K32WOWYield16( void )
301 * This does the right thing for both Win16 and Win32 tasks.
302 * More or less, at least :-/
304 Yield16();
307 /**********************************************************************
308 * K32WOWDirectedYield16 (KERNEL32.67)
310 VOID WINAPI K32WOWDirectedYield16( WORD htask16 )
313 * Argh. Our scheduler doesn't like DirectedYield by Win32
314 * tasks at all. So we do hope that this routine is indeed
315 * only ever called by Win16 tasks that have thunked up ...
317 DirectedYield16( (HTASK16)htask16 );
321 /***********************************************************************
322 * K32WOWHandle32 (KERNEL32.57)
324 HANDLE WINAPI K32WOWHandle32( WORD handle, WOW_HANDLE_TYPE type )
326 switch ( type )
328 case WOW_TYPE_HWND:
329 case WOW_TYPE_HMENU:
330 case WOW_TYPE_HDWP:
331 case WOW_TYPE_HDROP:
332 case WOW_TYPE_HDC:
333 case WOW_TYPE_HFONT:
334 case WOW_TYPE_HRGN:
335 case WOW_TYPE_HBITMAP:
336 case WOW_TYPE_HBRUSH:
337 case WOW_TYPE_HPALETTE:
338 case WOW_TYPE_HPEN:
339 case WOW_TYPE_HACCEL:
340 return (HANDLE)(ULONG_PTR)handle;
342 case WOW_TYPE_HMETAFILE:
343 FIXME( "conversion of metafile handles not supported yet\n" );
344 return (HANDLE)(ULONG_PTR)handle;
346 case WOW_TYPE_HTASK:
347 return ((TDB *)GlobalLock16(handle))->teb->ClientId.UniqueThread;
349 case WOW_TYPE_FULLHWND:
350 FIXME( "conversion of full window handles not supported yet\n" );
351 return (HANDLE)(ULONG_PTR)handle;
353 default:
354 ERR( "handle 0x%04x of unknown type %d\n", handle, type );
355 return (HANDLE)(ULONG_PTR)handle;
359 /***********************************************************************
360 * K32WOWHandle16 (KERNEL32.58)
362 WORD WINAPI K32WOWHandle16( HANDLE handle, WOW_HANDLE_TYPE type )
364 switch ( type )
366 case WOW_TYPE_HWND:
367 case WOW_TYPE_HMENU:
368 case WOW_TYPE_HDWP:
369 case WOW_TYPE_HDROP:
370 case WOW_TYPE_HDC:
371 case WOW_TYPE_HFONT:
372 case WOW_TYPE_HRGN:
373 case WOW_TYPE_HBITMAP:
374 case WOW_TYPE_HBRUSH:
375 case WOW_TYPE_HPALETTE:
376 case WOW_TYPE_HPEN:
377 case WOW_TYPE_HACCEL:
378 case WOW_TYPE_FULLHWND:
379 if ( HIWORD(handle ) )
380 ERR( "handle %p of type %d has non-zero HIWORD\n", handle, type );
381 return LOWORD(handle);
383 case WOW_TYPE_HMETAFILE:
384 FIXME( "conversion of metafile handles not supported yet\n" );
385 return LOWORD(handle);
387 case WOW_TYPE_HTASK:
388 return TASK_GetTaskFromThread( (DWORD)handle );
390 default:
391 ERR( "handle %p of unknown type %d\n", handle, type );
392 return LOWORD(handle);
396 /**********************************************************************
397 * K32WOWCallback16Ex (KERNEL32.55)
399 BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags,
400 DWORD cbArgs, LPVOID pArgs, LPDWORD pdwRetCode )
403 * Arguments must be prepared in the correct order by the caller
404 * (both for PASCAL and CDECL calling convention), so we simply
405 * copy them to the 16-bit stack ...
407 char *stack = (char *)CURRENT_STACK16 - cbArgs;
409 memcpy( stack, pArgs, cbArgs );
411 if (dwFlags & (WCB16_REGS|WCB16_REGS_LONG))
413 CONTEXT *context = (CONTEXT *)pdwRetCode;
415 if (TRACE_ON(relay))
417 DWORD count = cbArgs / sizeof(WORD);
418 WORD * wstack = (WORD *)stack;
420 TRACE_(relay)( "\1CallTo16(func=%04x:%04x", context->SegCs, LOWORD(context->Eip) );
421 while (count) TRACE_(relay)( ",%04x", wstack[--count] );
422 TRACE_(relay)( ") ss:sp=%04x:%04x ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x bp=%04x ds=%04x es=%04x\n",
423 SELECTOROF(NtCurrentTeb()->WOW32Reserved),
424 OFFSETOF(NtCurrentTeb()->WOW32Reserved),
425 (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
426 (WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi,
427 (WORD)context->Ebp, (WORD)context->SegDs, (WORD)context->SegEs );
428 SYSLEVEL_CheckNotLevel( 2 );
431 assert( !(context->EFlags & 0x00020000) ); /* vm86 mode no longer supported */
433 /* push return address */
434 if (dwFlags & WCB16_REGS_LONG)
436 stack -= sizeof(DWORD);
437 *((DWORD *)stack) = HIWORD(call16_ret_addr);
438 stack -= sizeof(DWORD);
439 *((DWORD *)stack) = LOWORD(call16_ret_addr);
440 cbArgs += 2 * sizeof(DWORD);
442 else
444 stack -= sizeof(SEGPTR);
445 *((SEGPTR *)stack) = call16_ret_addr;
446 cbArgs += sizeof(SEGPTR);
449 _EnterWin16Lock();
450 wine_call_to_16_regs( context, cbArgs, call16_handler );
451 _LeaveWin16Lock();
453 if (TRACE_ON(relay))
455 TRACE_(relay)( "\1RetFrom16() ss:sp=%04x:%04x ax=%04x bx=%04x cx=%04x dx=%04x bp=%04x sp=%04x\n",
456 SELECTOROF(NtCurrentTeb()->WOW32Reserved),
457 OFFSETOF(NtCurrentTeb()->WOW32Reserved),
458 (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
459 (WORD)context->Edx, (WORD)context->Ebp, (WORD)context->Esp );
460 SYSLEVEL_CheckNotLevel( 2 );
463 else
465 DWORD ret;
467 if (TRACE_ON(relay))
469 DWORD count = cbArgs / sizeof(WORD);
470 WORD * wstack = (WORD *)stack;
472 TRACE_(relay)( "\1CallTo16(func=%04x:%04x,ds=%04x",
473 HIWORD(vpfn16), LOWORD(vpfn16), SELECTOROF(NtCurrentTeb()->WOW32Reserved) );
474 while (count) TRACE_(relay)( ",%04x", wstack[--count] );
475 TRACE_(relay)( ") ss:sp=%04x:%04x\n", SELECTOROF(NtCurrentTeb()->WOW32Reserved),
476 OFFSETOF(NtCurrentTeb()->WOW32Reserved) );
477 SYSLEVEL_CheckNotLevel( 2 );
480 /* push return address */
481 stack -= sizeof(SEGPTR);
482 *((SEGPTR *)stack) = call16_ret_addr;
483 cbArgs += sizeof(SEGPTR);
486 * Actually, we should take care whether the called routine cleans up
487 * its stack or not. Fortunately, our wine_call_to_16 core doesn't rely on
488 * the callee to do so; after the routine has returned, the 16-bit
489 * stack pointer is always reset to the position it had before.
491 _EnterWin16Lock();
492 ret = wine_call_to_16( (FARPROC16)vpfn16, cbArgs, call16_handler );
493 if (pdwRetCode) *pdwRetCode = ret;
494 _LeaveWin16Lock();
496 if (TRACE_ON(relay))
498 TRACE_(relay)( "\1RetFrom16() ss:sp=%04x:%04x retval=%08x\n",
499 SELECTOROF(NtCurrentTeb()->WOW32Reserved),
500 OFFSETOF(NtCurrentTeb()->WOW32Reserved), ret );
501 SYSLEVEL_CheckNotLevel( 2 );
505 return TRUE; /* success */
508 /**********************************************************************
509 * K32WOWCallback16 (KERNEL32.54)
511 DWORD WINAPI K32WOWCallback16( DWORD vpfn16, DWORD dwParam )
513 DWORD ret;
515 if ( !K32WOWCallback16Ex( vpfn16, WCB16_PASCAL,
516 sizeof(DWORD), &dwParam, &ret ) )
517 ret = 0L;
519 return ret;