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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/port.h"
27 #include "wine/winbase16.h"
35 #include "kernel_private.h"
36 #include "kernel16_private.h"
37 #include "wine/exception.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(thunk
);
41 WINE_DECLARE_DEBUG_CHANNEL(relay
);
42 WINE_DECLARE_DEBUG_CHANNEL(snoop
);
45 * These are the 16-bit side WOW routines. They reside in wownt16.h
46 * in the SDK; since we don't support Win16 source code anyway, I've
47 * placed them here for compilation with Wine ...
50 DWORD WINAPI
GetVDMPointer32W16(SEGPTR
,UINT16
);
52 DWORD WINAPI
LoadLibraryEx32W16(LPCSTR
,DWORD
,DWORD
);
53 DWORD WINAPI
GetProcAddress32W16(DWORD
,LPCSTR
);
54 DWORD WINAPI
FreeLibrary32W16(DWORD
);
56 #define CPEX_DEST_STDCALL 0x00000000L
57 #define CPEX_DEST_CDECL 0x80000000L
59 /* thunk for 16-bit CreateThread */
66 static DWORD CALLBACK
start_thread16( LPVOID threadArgs
)
68 struct thread_args args
= *(struct thread_args
*)threadArgs
;
69 HeapFree( GetProcessHeap(), 0, threadArgs
);
70 return K32WOWCallback16( (DWORD
)args
.proc
, args
.param
);
76 /* symbols exported from relay16.s */
77 extern DWORD WINAPI
wine_call_to_16( FARPROC16 target
, DWORD cbArgs
, PEXCEPTION_HANDLER handler
);
78 extern void WINAPI
wine_call_to_16_regs( CONTEXT86
*context
, DWORD cbArgs
, PEXCEPTION_HANDLER handler
);
79 extern void Call16_Ret_Start();
80 extern void Call16_Ret_End();
81 extern void CallTo16_Ret();
82 extern void CALL32_CBClient_Ret();
83 extern void CALL32_CBClientEx_Ret();
84 extern void DPMI_PendingEventCheck();
85 extern void DPMI_PendingEventCheck_Cleanup();
86 extern void DPMI_PendingEventCheck_Return();
87 extern DWORD CallTo16_DataSelector
;
88 extern SEGPTR CALL32_CBClient_RetAddr
;
89 extern SEGPTR CALL32_CBClientEx_RetAddr
;
90 extern BYTE Call16_Start
;
91 extern BYTE Call16_End
;
93 extern void RELAY16_InitDebugLists(void);
95 static LONG CALLBACK
vectored_handler( EXCEPTION_POINTERS
*ptrs
);
96 static SEGPTR call16_ret_addr
; /* segptr to CallTo16_Ret routine */
98 static WORD dpmi_checker_selector
;
99 static DWORD dpmi_checker_offset_call
;
100 static DWORD dpmi_checker_offset_cleanup
;
101 static DWORD dpmi_checker_offset_return
;
103 /***********************************************************************
106 BOOL
WOWTHUNK_Init(void)
108 /* allocate the code selector for CallTo16 routines */
109 WORD codesel
= SELECTOR_AllocBlock( (void *)Call16_Ret_Start
,
110 (char *)Call16_Ret_End
- (char *)Call16_Ret_Start
,
111 WINE_LDT_FLAGS_CODE
| WINE_LDT_FLAGS_32BIT
);
112 if (!codesel
) return FALSE
;
114 /* Patch the return addresses for CallTo16 routines */
116 CallTo16_DataSelector
= wine_get_ds();
117 call16_ret_addr
= MAKESEGPTR( codesel
, (char*)CallTo16_Ret
- (char*)Call16_Ret_Start
);
118 CALL32_CBClient_RetAddr
=
119 MAKESEGPTR( codesel
, (char*)CALL32_CBClient_Ret
- (char*)Call16_Ret_Start
);
120 CALL32_CBClientEx_RetAddr
=
121 MAKESEGPTR( codesel
, (char*)CALL32_CBClientEx_Ret
- (char*)Call16_Ret_Start
);
123 /* Prepare selector and offsets for DPMI event checking. */
124 dpmi_checker_selector
= codesel
;
125 dpmi_checker_offset_call
=
126 (char*)DPMI_PendingEventCheck
- (char*)Call16_Ret_Start
;
127 dpmi_checker_offset_cleanup
=
128 (char*)DPMI_PendingEventCheck_Cleanup
- (char*)Call16_Ret_Start
;
129 dpmi_checker_offset_return
=
130 (char*)DPMI_PendingEventCheck_Return
- (char*)Call16_Ret_Start
;
132 if (TRACE_ON(relay
) || TRACE_ON(snoop
)) RELAY16_InitDebugLists();
134 /* setup emulation of protected instructions from 32-bit code (only for Win9x versions) */
135 if (GetVersion() & 0x80000000) RtlAddVectoredExceptionHandler( TRUE
, vectored_handler
);
140 /*************************************************************
143 * Fix a selector load that caused an exception if it's in the
146 static BOOL
fix_selector( CONTEXT
*context
)
149 BYTE
*instr
= (BYTE
*)context
->Eip
;
151 if (instr
< &Call16_Start
|| instr
>= &Call16_End
) return FALSE
;
154 while (*instr
== 0x66 || *instr
== 0x67) instr
++;
158 case 0x07: /* pop es */
159 case 0x17: /* pop ss */
160 case 0x1f: /* pop ds */
162 case 0x0f: /* extended instruction */
165 case 0xa1: /* pop fs */
166 case 0xa9: /* pop gs */
175 stack
= wine_ldt_get_ptr( context
->SegSs
, context
->Esp
);
176 TRACE( "fixing up selector %x for pop instruction\n", *stack
);
182 /*************************************************************
185 * Make resuming the context check for pending DPMI events
186 * before the original context is restored. This is required
187 * because DPMI events are asynchronous, they are blocked while
188 * Wine 32-bit code is being executed and we want to prevent
189 * a race when returning back to 16-bit or 32-bit DPMI context.
191 static void insert_event_check( CONTEXT
*context
)
193 char *stack
= wine_ldt_get_ptr( context
->SegSs
, context
->Esp
);
195 /* don't do event check while in system code */
196 if (wine_ldt_is_system(context
->SegCs
))
199 if(context
->SegCs
== dpmi_checker_selector
&&
200 context
->Eip
>= dpmi_checker_offset_call
&&
201 context
->Eip
<= dpmi_checker_offset_cleanup
)
204 * Nested call. Stack will be preserved.
207 else if(context
->SegCs
== dpmi_checker_selector
&&
208 context
->Eip
== dpmi_checker_offset_return
)
211 * Nested call. We have just finished popping the fs
212 * register, lets put it back into stack.
215 stack
-= sizeof(WORD
);
216 *(WORD
*)stack
= context
->SegFs
;
223 * Call is not nested.
224 * Push modified registers into stack.
225 * These will be popped by the assembler stub.
228 stack
-= sizeof(DWORD
);
229 *(DWORD
*)stack
= context
->EFlags
;
231 stack
-= sizeof(DWORD
);
232 *(DWORD
*)stack
= context
->SegCs
;
234 stack
-= sizeof(DWORD
);
235 *(DWORD
*)stack
= context
->Eip
;
237 stack
-= sizeof(WORD
);
238 *(WORD
*)stack
= context
->SegFs
;
244 * Modify the context so that we jump into assembler stub.
245 * TEB access is made easier by providing the stub
246 * with the correct fs register value.
249 context
->SegCs
= dpmi_checker_selector
;
250 context
->Eip
= dpmi_checker_offset_call
;
251 context
->SegFs
= wine_get_fs();
255 /*************************************************************
258 * Handler for exceptions occurring in 16-bit code.
260 static DWORD
call16_handler( EXCEPTION_RECORD
*record
, EXCEPTION_REGISTRATION_RECORD
*frame
,
261 CONTEXT
*context
, EXCEPTION_REGISTRATION_RECORD
**pdispatcher
)
263 if (record
->ExceptionFlags
& (EH_UNWINDING
| EH_EXIT_UNWIND
))
265 /* unwinding: restore the stack pointer in the TEB, and leave the Win16 mutex */
266 STACK32FRAME
*frame32
= (STACK32FRAME
*)((char *)frame
- offsetof(STACK32FRAME
,frame
));
267 NtCurrentTeb()->WOW32Reserved
= (void *)frame32
->frame16
;
270 else if (record
->ExceptionCode
== EXCEPTION_ACCESS_VIOLATION
||
271 record
->ExceptionCode
== EXCEPTION_PRIV_INSTRUCTION
)
273 if (wine_ldt_is_system(context
->SegCs
))
275 if (fix_selector( context
)) return ExceptionContinueExecution
;
280 DWORD ret
= INSTR_EmulateInstruction( record
, context
);
283 * Insert check for pending DPMI events. Note that this
284 * check must be inserted after instructions have been
285 * emulated because the instruction emulation requires
286 * original CS:IP and the emulation may change TEB.dpmi_vif.
288 if(NtCurrentTeb()->dpmi_vif
)
289 insert_event_check( context
);
291 if (ret
!= ExceptionContinueSearch
) return ret
;
293 /* check for Win16 __GP handler */
294 if ((gpHandler
= HasGPHandler16( MAKESEGPTR( context
->SegCs
, context
->Eip
) )))
296 WORD
*stack
= wine_ldt_get_ptr( context
->SegSs
, context
->Esp
);
297 *--stack
= context
->SegCs
;
298 *--stack
= context
->Eip
;
300 if (!IS_SELECTOR_32BIT(context
->SegSs
))
301 context
->Esp
= MAKELONG( LOWORD(context
->Esp
- 2*sizeof(WORD
)),
302 HIWORD(context
->Esp
) );
304 context
->Esp
-= 2*sizeof(WORD
);
306 context
->SegCs
= SELECTOROF( gpHandler
);
307 context
->Eip
= OFFSETOF( gpHandler
);
308 return ExceptionContinueExecution
;
312 else if (record
->ExceptionCode
== EXCEPTION_VM86_STI
)
314 insert_event_check( context
);
316 return ExceptionContinueSearch
;
320 /*************************************************************
323 * Handler for exceptions occurring in vm86 code.
325 static DWORD
vm86_handler( EXCEPTION_RECORD
*record
, EXCEPTION_REGISTRATION_RECORD
*frame
,
326 CONTEXT
*context
, EXCEPTION_REGISTRATION_RECORD
**pdispatcher
)
328 if (record
->ExceptionFlags
& (EH_UNWINDING
| EH_EXIT_UNWIND
))
329 return ExceptionContinueSearch
;
331 if (record
->ExceptionCode
== EXCEPTION_ACCESS_VIOLATION
||
332 record
->ExceptionCode
== EXCEPTION_PRIV_INSTRUCTION
)
334 return INSTR_EmulateInstruction( record
, context
);
337 return ExceptionContinueSearch
;
341 /***********************************************************************
344 * Vectored exception handler used to emulate protected instructions
347 static LONG CALLBACK
vectored_handler( EXCEPTION_POINTERS
*ptrs
)
349 EXCEPTION_RECORD
*record
= ptrs
->ExceptionRecord
;
350 CONTEXT
*context
= ptrs
->ContextRecord
;
352 if (wine_ldt_is_system(context
->SegCs
) &&
353 (record
->ExceptionCode
== EXCEPTION_ACCESS_VIOLATION
||
354 record
->ExceptionCode
== EXCEPTION_PRIV_INSTRUCTION
))
356 if (INSTR_EmulateInstruction( record
, context
) == ExceptionContinueExecution
)
357 return EXCEPTION_CONTINUE_EXECUTION
;
359 return EXCEPTION_CONTINUE_SEARCH
;
365 BOOL
WOWTHUNK_Init(void)
370 #endif /* __i386__ */
374 * 32-bit WOW routines (in WOW32, but actually forwarded to KERNEL32)
377 /**********************************************************************
378 * K32WOWGetDescriptor (KERNEL32.70)
380 BOOL WINAPI
K32WOWGetDescriptor( SEGPTR segptr
, LPLDT_ENTRY ldtent
)
382 return GetThreadSelectorEntry( GetCurrentThread(),
383 segptr
>> 16, ldtent
);
386 /**********************************************************************
387 * K32WOWGetVDMPointer (KERNEL32.56)
389 LPVOID WINAPI
K32WOWGetVDMPointer( DWORD vp
, DWORD dwBytes
, BOOL fProtectedMode
)
391 /* FIXME: add size check too */
393 if ( fProtectedMode
)
396 return DOSMEM_MapRealToLinear( vp
);
399 /**********************************************************************
400 * K32WOWGetVDMPointerFix (KERNEL32.68)
402 LPVOID WINAPI
K32WOWGetVDMPointerFix( DWORD vp
, DWORD dwBytes
, BOOL fProtectedMode
)
405 * Hmmm. According to the docu, we should call:
407 * GlobalFix16( SELECTOROF(vp) );
409 * But this is unnecessary under Wine, as we never move global
410 * memory segments in linear memory anyway.
412 * (I'm not so sure what we are *supposed* to do if
413 * fProtectedMode is TRUE, anyway ...)
416 return K32WOWGetVDMPointer( vp
, dwBytes
, fProtectedMode
);
419 /**********************************************************************
420 * K32WOWGetVDMPointerUnfix (KERNEL32.69)
422 VOID WINAPI
K32WOWGetVDMPointerUnfix( DWORD vp
)
425 * See above why we don't call:
427 * GlobalUnfix16( SELECTOROF(vp) );
432 /**********************************************************************
433 * K32WOWGlobalAlloc16 (KERNEL32.59)
435 WORD WINAPI
K32WOWGlobalAlloc16( WORD wFlags
, DWORD cb
)
437 return (WORD
)GlobalAlloc16( wFlags
, cb
);
440 /**********************************************************************
441 * K32WOWGlobalFree16 (KERNEL32.62)
443 WORD WINAPI
K32WOWGlobalFree16( WORD hMem
)
445 return (WORD
)GlobalFree16( (HGLOBAL16
)hMem
);
448 /**********************************************************************
449 * K32WOWGlobalUnlock16 (KERNEL32.61)
451 BOOL WINAPI
K32WOWGlobalUnlock16( WORD hMem
)
453 return (BOOL
)GlobalUnlock16( (HGLOBAL16
)hMem
);
456 /**********************************************************************
457 * K32WOWGlobalAllocLock16 (KERNEL32.63)
459 DWORD WINAPI
K32WOWGlobalAllocLock16( WORD wFlags
, DWORD cb
, WORD
*phMem
)
461 WORD hMem
= K32WOWGlobalAlloc16( wFlags
, cb
);
462 if (phMem
) *phMem
= hMem
;
464 return K32WOWGlobalLock16( hMem
);
467 /**********************************************************************
468 * K32WOWGlobalLockSize16 (KERNEL32.65)
470 DWORD WINAPI
K32WOWGlobalLockSize16( WORD hMem
, PDWORD pcb
)
473 *pcb
= GlobalSize16( (HGLOBAL16
)hMem
);
475 return K32WOWGlobalLock16( hMem
);
478 /**********************************************************************
479 * K32WOWGlobalUnlockFree16 (KERNEL32.64)
481 WORD WINAPI
K32WOWGlobalUnlockFree16( DWORD vpMem
)
483 if ( !K32WOWGlobalUnlock16( HIWORD(vpMem
) ) )
486 return K32WOWGlobalFree16( HIWORD(vpMem
) );
490 /**********************************************************************
491 * K32WOWYield16 (KERNEL32.66)
493 VOID WINAPI
K32WOWYield16( void )
496 * This does the right thing for both Win16 and Win32 tasks.
497 * More or less, at least :-/
502 /**********************************************************************
503 * K32WOWDirectedYield16 (KERNEL32.67)
505 VOID WINAPI
K32WOWDirectedYield16( WORD htask16
)
508 * Argh. Our scheduler doesn't like DirectedYield by Win32
509 * tasks at all. So we do hope that this routine is indeed
510 * only ever called by Win16 tasks that have thunked up ...
512 DirectedYield16( (HTASK16
)htask16
);
516 /***********************************************************************
517 * K32WOWHandle32 (KERNEL32.57)
519 HANDLE WINAPI
K32WOWHandle32( WORD handle
, WOW_HANDLE_TYPE type
)
530 case WOW_TYPE_HBITMAP
:
531 case WOW_TYPE_HBRUSH
:
532 case WOW_TYPE_HPALETTE
:
534 case WOW_TYPE_HACCEL
:
535 return (HANDLE
)(ULONG_PTR
)handle
;
537 case WOW_TYPE_HMETAFILE
:
538 FIXME( "conversion of metafile handles not supported yet\n" );
539 return (HANDLE
)(ULONG_PTR
)handle
;
542 return ((TDB
*)GlobalLock16(handle
))->teb
->ClientId
.UniqueThread
;
544 case WOW_TYPE_FULLHWND
:
545 FIXME( "conversion of full window handles not supported yet\n" );
546 return (HANDLE
)(ULONG_PTR
)handle
;
549 ERR( "handle 0x%04x of unknown type %d\n", handle
, type
);
550 return (HANDLE
)(ULONG_PTR
)handle
;
554 /***********************************************************************
555 * K32WOWHandle16 (KERNEL32.58)
557 WORD WINAPI
K32WOWHandle16( HANDLE handle
, WOW_HANDLE_TYPE type
)
568 case WOW_TYPE_HBITMAP
:
569 case WOW_TYPE_HBRUSH
:
570 case WOW_TYPE_HPALETTE
:
572 case WOW_TYPE_HACCEL
:
573 case WOW_TYPE_FULLHWND
:
574 if ( HIWORD(handle
) )
575 ERR( "handle %p of type %d has non-zero HIWORD\n", handle
, type
);
576 return LOWORD(handle
);
578 case WOW_TYPE_HMETAFILE
:
579 FIXME( "conversion of metafile handles not supported yet\n" );
580 return LOWORD(handle
);
583 return TASK_GetTaskFromThread( (DWORD
)handle
);
586 ERR( "handle %p of unknown type %d\n", handle
, type
);
587 return LOWORD(handle
);
591 /**********************************************************************
592 * K32WOWCallback16Ex (KERNEL32.55)
594 BOOL WINAPI
K32WOWCallback16Ex( DWORD vpfn16
, DWORD dwFlags
,
595 DWORD cbArgs
, LPVOID pArgs
, LPDWORD pdwRetCode
)
599 * Arguments must be prepared in the correct order by the caller
600 * (both for PASCAL and CDECL calling convention), so we simply
601 * copy them to the 16-bit stack ...
603 char *stack
= (char *)CURRENT_STACK16
- cbArgs
;
605 memcpy( stack
, pArgs
, cbArgs
);
607 if (dwFlags
& (WCB16_REGS
|WCB16_REGS_LONG
))
609 CONTEXT
*context
= (CONTEXT
*)pdwRetCode
;
613 DWORD count
= cbArgs
/ sizeof(WORD
);
614 WORD
* wstack
= (WORD
*)stack
;
616 DPRINTF("%04lx:CallTo16(func=%04lx:%04x,ds=%04lx",
617 GetCurrentThreadId(),
618 context
->SegCs
, LOWORD(context
->Eip
), context
->SegDs
);
619 while (count
) DPRINTF( ",%04x", wstack
[--count
] );
620 DPRINTF(") ss:sp=%04x:%04x",
621 SELECTOROF(NtCurrentTeb()->WOW32Reserved
), OFFSETOF(NtCurrentTeb()->WOW32Reserved
) );
622 DPRINTF(" ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x bp=%04x es=%04x fs=%04x\n",
623 (WORD
)context
->Eax
, (WORD
)context
->Ebx
, (WORD
)context
->Ecx
,
624 (WORD
)context
->Edx
, (WORD
)context
->Esi
, (WORD
)context
->Edi
,
625 (WORD
)context
->Ebp
, (WORD
)context
->SegEs
, (WORD
)context
->SegFs
);
626 SYSLEVEL_CheckNotLevel( 2 );
629 if (context
->EFlags
& 0x00020000) /* v86 mode */
631 EXCEPTION_REGISTRATION_RECORD frame
;
632 frame
.Handler
= vm86_handler
;
633 __wine_push_frame( &frame
);
634 __wine_enter_vm86( context
);
635 __wine_pop_frame( &frame
);
639 /* push return address */
640 if (dwFlags
& WCB16_REGS_LONG
)
642 stack
-= sizeof(DWORD
);
643 *((DWORD
*)stack
) = HIWORD(call16_ret_addr
);
644 stack
-= sizeof(DWORD
);
645 *((DWORD
*)stack
) = LOWORD(call16_ret_addr
);
646 cbArgs
+= 2 * sizeof(DWORD
);
650 stack
-= sizeof(SEGPTR
);
651 *((SEGPTR
*)stack
) = call16_ret_addr
;
652 cbArgs
+= sizeof(SEGPTR
);
656 * Start call by checking for pending events.
657 * Note that wine_call_to_16_regs overwrites context stack
658 * pointer so we may modify it here without a problem.
660 if (NtCurrentTeb()->dpmi_vif
)
662 context
->SegSs
= wine_get_ds();
663 context
->Esp
= (DWORD
)stack
;
664 insert_event_check( context
);
665 cbArgs
+= (DWORD
)stack
- context
->Esp
;
669 wine_call_to_16_regs( context
, cbArgs
, call16_handler
);
675 DPRINTF("%04lx:RetFrom16() ss:sp=%04x:%04x ",
676 GetCurrentThreadId(), SELECTOROF(NtCurrentTeb()->WOW32Reserved
),
677 OFFSETOF(NtCurrentTeb()->WOW32Reserved
));
678 DPRINTF(" ax=%04x bx=%04x cx=%04x dx=%04x bp=%04x sp=%04x\n",
679 (WORD
)context
->Eax
, (WORD
)context
->Ebx
, (WORD
)context
->Ecx
,
680 (WORD
)context
->Edx
, (WORD
)context
->Ebp
, (WORD
)context
->Esp
);
681 SYSLEVEL_CheckNotLevel( 2 );
690 DWORD count
= cbArgs
/ sizeof(WORD
);
691 WORD
* wstack
= (WORD
*)stack
;
693 DPRINTF("%04lx:CallTo16(func=%04x:%04x,ds=%04x",
694 GetCurrentThreadId(), HIWORD(vpfn16
), LOWORD(vpfn16
),
695 SELECTOROF(NtCurrentTeb()->WOW32Reserved
) );
696 while (count
) DPRINTF( ",%04x", wstack
[--count
] );
697 DPRINTF(") ss:sp=%04x:%04x\n",
698 SELECTOROF(NtCurrentTeb()->WOW32Reserved
), OFFSETOF(NtCurrentTeb()->WOW32Reserved
) );
699 SYSLEVEL_CheckNotLevel( 2 );
702 /* push return address */
703 stack
-= sizeof(SEGPTR
);
704 *((SEGPTR
*)stack
) = call16_ret_addr
;
705 cbArgs
+= sizeof(SEGPTR
);
708 * Actually, we should take care whether the called routine cleans up
709 * its stack or not. Fortunately, our wine_call_to_16 core doesn't rely on
710 * the callee to do so; after the routine has returned, the 16-bit
711 * stack pointer is always reset to the position it had before.
714 ret
= wine_call_to_16( (FARPROC16
)vpfn16
, cbArgs
, call16_handler
);
715 if (pdwRetCode
) *pdwRetCode
= ret
;
720 DPRINTF("%04lx:RetFrom16() ss:sp=%04x:%04x retval=%08lx\n",
721 GetCurrentThreadId(), SELECTOROF(NtCurrentTeb()->WOW32Reserved
),
722 OFFSETOF(NtCurrentTeb()->WOW32Reserved
), ret
);
723 SYSLEVEL_CheckNotLevel( 2 );
727 assert(0); /* cannot call to 16-bit on non-Intel architectures */
728 #endif /* __i386__ */
730 return TRUE
; /* success */
733 /**********************************************************************
734 * K32WOWCallback16 (KERNEL32.54)
736 DWORD WINAPI
K32WOWCallback16( DWORD vpfn16
, DWORD dwParam
)
740 if ( !K32WOWCallback16Ex( vpfn16
, WCB16_PASCAL
,
741 sizeof(DWORD
), &dwParam
, &ret
) )
749 * 16-bit WOW routines (in KERNEL)
752 /**********************************************************************
753 * GetVDMPointer32W (KERNEL.516)
755 DWORD WINAPI
GetVDMPointer32W16( SEGPTR vp
, UINT16 fMode
)
757 GlobalPageLock16(GlobalHandle16(SELECTOROF(vp
)));
758 return (DWORD
)K32WOWGetVDMPointer( vp
, 0, (DWORD
)fMode
);
761 /***********************************************************************
762 * LoadLibraryEx32W (KERNEL.513)
764 DWORD WINAPI
LoadLibraryEx32W16( LPCSTR lpszLibFile
, DWORD hFile
, DWORD dwFlags
)
773 SetLastError(ERROR_INVALID_PARAMETER
);
777 /* if the file cannot be found, call LoadLibraryExA anyway, since it might be
778 a builtin module. This case is handled in MODULE_LoadLibraryExA */
780 if ((p
= strrchr( lpszLibFile
, '.' )) && !strchr( p
, '\\' )) /* got an extension */
782 if (OpenFile16( lpszLibFile
, &ofs
, OF_EXIST
) != HFILE_ERROR16
)
783 lpszLibFile
= ofs
.szPathName
;
787 char buffer
[MAX_PATH
+4];
788 strcpy( buffer
, lpszLibFile
);
789 strcat( buffer
, ".dll" );
790 if (OpenFile16( buffer
, &ofs
, OF_EXIST
) != HFILE_ERROR16
)
791 lpszLibFile
= ofs
.szPathName
;
794 ReleaseThunkLock( &mutex_count
);
795 hModule
= LoadLibraryExA( lpszLibFile
, (HANDLE
)hFile
, dwFlags
);
796 RestoreThunkLock( mutex_count
);
798 return (DWORD
)hModule
;
801 /***********************************************************************
802 * GetProcAddress32W (KERNEL.515)
804 DWORD WINAPI
GetProcAddress32W16( DWORD hModule
, LPCSTR lpszProc
)
806 return (DWORD
)GetProcAddress( (HMODULE
)hModule
, lpszProc
);
809 /***********************************************************************
810 * FreeLibrary32W (KERNEL.514)
812 DWORD WINAPI
FreeLibrary32W16( DWORD hLibModule
)
817 ReleaseThunkLock( &mutex_count
);
818 retv
= FreeLibrary( (HMODULE
)hLibModule
);
819 RestoreThunkLock( mutex_count
);
824 /**********************************************************************
827 static DWORD
WOW_CallProc32W16( FARPROC proc32
, DWORD nrofargs
, DWORD
*args
)
832 ReleaseThunkLock( &mutex_count
);
835 * FIXME: If ( nrofargs & CPEX_DEST_CDECL ) != 0, we should call a
836 * 32-bit CDECL routine ...
839 if (!proc32
) ret
= 0;
840 else switch (nrofargs
)
842 case 0: ret
= proc32();
844 case 1: ret
= proc32(args
[0]);
846 case 2: ret
= proc32(args
[0],args
[1]);
848 case 3: ret
= proc32(args
[0],args
[1],args
[2]);
850 case 4: ret
= proc32(args
[0],args
[1],args
[2],args
[3]);
852 case 5: ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4]);
854 case 6: ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5]);
856 case 7: ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6]);
858 case 8: ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7]);
860 case 9: ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8]);
862 case 10:ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8],args
[9]);
864 case 11:ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8],args
[9],args
[10]);
866 case 12:ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8],args
[9],args
[10],args
[11]);
868 case 13:ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],args
[12]);
870 case 14:ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],args
[12],args
[13]);
872 case 15:ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],args
[12],args
[13],args
[14]);
875 /* FIXME: should go up to 32 arguments */
876 ERR("Unsupported number of arguments %ld, please report.\n",nrofargs
);
881 RestoreThunkLock( mutex_count
);
883 TRACE("returns %08lx\n",ret
);
887 /**********************************************************************
888 * CallProc32W (KERNEL.517)
890 DWORD WINAPIV
CallProc32W16( DWORD nrofargs
, DWORD argconvmask
, FARPROC proc32
, VA_LIST16 valist
)
895 TRACE("(%ld,%ld,%p args[",nrofargs
,argconvmask
,proc32
);
897 for (i
=0;i
<nrofargs
;i
++)
899 if (argconvmask
& (1<<i
))
901 SEGPTR ptr
= VA_ARG16( valist
, SEGPTR
);
902 /* pascal convention, have to reverse the arguments order */
903 args
[nrofargs
- i
- 1] = (DWORD
)MapSL(ptr
);
904 TRACE("%08lx(%p),",ptr
,MapSL(ptr
));
908 DWORD arg
= VA_ARG16( valist
, DWORD
);
909 /* pascal convention, have to reverse the arguments order */
910 args
[nrofargs
- i
- 1] = arg
;
916 /* POP nrofargs DWORD arguments and 3 DWORD parameters */
917 stack16_pop( (3 + nrofargs
) * sizeof(DWORD
) );
919 return WOW_CallProc32W16( proc32
, nrofargs
, args
);
922 /**********************************************************************
923 * _CallProcEx32W (KERNEL.518)
925 DWORD WINAPIV
CallProcEx32W16( DWORD nrofargs
, DWORD argconvmask
, FARPROC proc32
, VA_LIST16 valist
)
930 TRACE("(%ld,%ld,%p args[",nrofargs
,argconvmask
,proc32
);
932 for (i
=0;i
<nrofargs
;i
++)
934 if (argconvmask
& (1<<i
))
936 SEGPTR ptr
= VA_ARG16( valist
, SEGPTR
);
937 args
[i
] = (DWORD
)MapSL(ptr
);
938 TRACE("%08lx(%p),",ptr
,MapSL(ptr
));
942 DWORD arg
= VA_ARG16( valist
, DWORD
);
948 return WOW_CallProc32W16( proc32
, nrofargs
, args
);
952 /**********************************************************************
953 * WOW16Call (KERNEL.500)
958 DWORD WINAPIV
WOW16Call(WORD x
, WORD y
, WORD z
, VA_LIST16 args
)
962 FIXME("(0x%04x,0x%04x,%d),calling (",x
,y
,z
);
964 for (i
=0;i
<x
/2;i
++) {
965 WORD a
= VA_ARG16(args
,WORD
);
968 calladdr
= VA_ARG16(args
,DWORD
);
969 stack16_pop( 3*sizeof(WORD
) + x
+ sizeof(DWORD
) );
970 DPRINTF(") calling address was 0x%08lx\n",calladdr
);
975 /***********************************************************************
976 * CreateThread16 (KERNEL.441)
978 HANDLE WINAPI
CreateThread16( SECURITY_ATTRIBUTES
*sa
, DWORD stack
,
979 FARPROC16 start
, SEGPTR param
,
980 DWORD flags
, LPDWORD id
)
982 struct thread_args
*args
= HeapAlloc( GetProcessHeap(), 0, sizeof(*args
) );
983 if (!args
) return INVALID_HANDLE_VALUE
;
986 return CreateThread( sa
, stack
, start_thread16
, args
, flags
, id
);