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"
37 #include "stackframe.h"
38 #include "kernel_private.h"
39 #include "wine/exception.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(thunk
);
43 WINE_DECLARE_DEBUG_CHANNEL(relay
);
44 WINE_DECLARE_DEBUG_CHANNEL(snoop
);
47 * These are the 16-bit side WOW routines. They reside in wownt16.h
48 * in the SDK; since we don't support Win16 source code anyway, I've
49 * placed them here for compilation with Wine ...
52 DWORD WINAPI
GetVDMPointer32W16(SEGPTR
,UINT16
);
54 DWORD WINAPI
LoadLibraryEx32W16(LPCSTR
,DWORD
,DWORD
);
55 DWORD WINAPI
GetProcAddress32W16(DWORD
,LPCSTR
);
56 DWORD WINAPI
FreeLibrary32W16(DWORD
);
58 #define CPEX_DEST_STDCALL 0x00000000L
59 #define CPEX_DEST_CDECL 0x80000000L
61 /* thunk for 16-bit CreateThread */
68 static DWORD CALLBACK
start_thread16( LPVOID threadArgs
)
70 struct thread_args args
= *(struct thread_args
*)threadArgs
;
71 HeapFree( GetProcessHeap(), 0, threadArgs
);
72 return K32WOWCallback16( (DWORD
)args
.proc
, args
.param
);
78 /* symbols exported from relay16.s */
79 extern DWORD WINAPI
wine_call_to_16( FARPROC16 target
, DWORD cbArgs
, PEXCEPTION_HANDLER handler
);
80 extern void WINAPI
wine_call_to_16_regs( CONTEXT86
*context
, DWORD cbArgs
, PEXCEPTION_HANDLER handler
);
81 extern void Call16_Ret_Start(), Call16_Ret_End();
82 extern void CallTo16_Ret();
83 extern void CALL32_CBClient_Ret();
84 extern void CALL32_CBClientEx_Ret();
85 extern void DPMI_PendingEventCheck();
86 extern void DPMI_PendingEventCheck_Cleanup();
87 extern void DPMI_PendingEventCheck_Return();
88 extern DWORD CallTo16_DataSelector
;
89 extern SEGPTR CALL32_CBClient_RetAddr
;
90 extern SEGPTR CALL32_CBClientEx_RetAddr
;
91 extern BYTE Call16_Start
;
92 extern BYTE Call16_End
;
94 extern void RELAY16_InitDebugLists(void);
96 static LONG CALLBACK
vectored_handler( EXCEPTION_POINTERS
*ptrs
);
97 static SEGPTR call16_ret_addr
; /* segptr to CallTo16_Ret routine */
99 static WORD dpmi_checker_selector
;
100 static DWORD dpmi_checker_offset_call
;
101 static DWORD dpmi_checker_offset_cleanup
;
102 static DWORD dpmi_checker_offset_return
;
104 /***********************************************************************
107 BOOL
WOWTHUNK_Init(void)
109 /* allocate the code selector for CallTo16 routines */
110 WORD codesel
= SELECTOR_AllocBlock( (void *)Call16_Ret_Start
,
111 (char *)Call16_Ret_End
- (char *)Call16_Ret_Start
,
112 WINE_LDT_FLAGS_CODE
| WINE_LDT_FLAGS_32BIT
);
113 if (!codesel
) return FALSE
;
115 /* Patch the return addresses for CallTo16 routines */
117 CallTo16_DataSelector
= wine_get_ds();
118 call16_ret_addr
= MAKESEGPTR( codesel
, (char*)CallTo16_Ret
- (char*)Call16_Ret_Start
);
119 CALL32_CBClient_RetAddr
=
120 MAKESEGPTR( codesel
, (char*)CALL32_CBClient_Ret
- (char*)Call16_Ret_Start
);
121 CALL32_CBClientEx_RetAddr
=
122 MAKESEGPTR( codesel
, (char*)CALL32_CBClientEx_Ret
- (char*)Call16_Ret_Start
);
124 /* Prepare selector and offsets for DPMI event checking. */
125 dpmi_checker_selector
= codesel
;
126 dpmi_checker_offset_call
=
127 (char*)DPMI_PendingEventCheck
- (char*)Call16_Ret_Start
;
128 dpmi_checker_offset_cleanup
=
129 (char*)DPMI_PendingEventCheck_Cleanup
- (char*)Call16_Ret_Start
;
130 dpmi_checker_offset_return
=
131 (char*)DPMI_PendingEventCheck_Return
- (char*)Call16_Ret_Start
;
133 if (TRACE_ON(relay
) || TRACE_ON(snoop
)) RELAY16_InitDebugLists();
135 /* setup emulation of protected instructions from 32-bit code (only for Win9x versions) */
136 if (GetVersion() & 0x80000000) RtlAddVectoredExceptionHandler( TRUE
, vectored_handler
);
141 /*************************************************************
144 * Fix a selector load that caused an exception if it's in the
147 static BOOL
fix_selector( CONTEXT
*context
)
150 BYTE
*instr
= (BYTE
*)context
->Eip
;
152 if (instr
< &Call16_Start
|| instr
>= &Call16_End
) return FALSE
;
155 while (*instr
== 0x66 || *instr
== 0x67) instr
++;
159 case 0x07: /* pop es */
160 case 0x17: /* pop ss */
161 case 0x1f: /* pop ds */
163 case 0x0f: /* extended instruction */
166 case 0xa1: /* pop fs */
167 case 0xa9: /* pop gs */
176 stack
= wine_ldt_get_ptr( context
->SegSs
, context
->Esp
);
177 TRACE( "fixing up selector %x for pop instruction\n", *stack
);
183 /*************************************************************
186 * Make resuming the context check for pending DPMI events
187 * before the original context is restored. This is required
188 * because DPMI events are asynchronous, they are blocked while
189 * Wine 32-bit code is being executed and we want to prevent
190 * a race when returning back to 16-bit or 32-bit DPMI context.
192 static void insert_event_check( CONTEXT
*context
)
194 char *stack
= wine_ldt_get_ptr( context
->SegSs
, context
->Esp
);
196 if(context
->SegCs
== dpmi_checker_selector
&&
197 context
->Eip
>= dpmi_checker_offset_call
&&
198 context
->Eip
<= dpmi_checker_offset_cleanup
)
201 * Nested call. Stack will be preserved.
204 else if(context
->SegCs
== dpmi_checker_selector
&&
205 context
->Eip
== dpmi_checker_offset_return
)
208 * Nested call. We have just finished popping the fs
209 * register, lets put it back into stack.
212 stack
-= sizeof(WORD
);
213 *(WORD
*)stack
= context
->SegFs
;
220 * Call is not nested.
221 * Push modified registers into stack.
222 * These will be popped by the assembler stub.
225 stack
-= sizeof(DWORD
);
226 *(DWORD
*)stack
= context
->EFlags
;
228 stack
-= sizeof(DWORD
);
229 *(DWORD
*)stack
= context
->SegCs
;
231 stack
-= sizeof(DWORD
);
232 *(DWORD
*)stack
= context
->Eip
;
234 stack
-= sizeof(WORD
);
235 *(WORD
*)stack
= context
->SegFs
;
241 * Modify the context so that we jump into assembler stub.
242 * TEB access is made easier by providing the stub
243 * with the correct fs register value.
246 context
->SegCs
= dpmi_checker_selector
;
247 context
->Eip
= dpmi_checker_offset_call
;
248 context
->SegFs
= wine_get_fs();
252 /*************************************************************
255 * Handler for exceptions occurring in 16-bit code.
257 static DWORD
call16_handler( EXCEPTION_RECORD
*record
, EXCEPTION_REGISTRATION_RECORD
*frame
,
258 CONTEXT
*context
, EXCEPTION_REGISTRATION_RECORD
**pdispatcher
)
260 if (record
->ExceptionFlags
& (EH_UNWINDING
| EH_EXIT_UNWIND
))
262 /* unwinding: restore the stack pointer in the TEB, and leave the Win16 mutex */
263 STACK32FRAME
*frame32
= (STACK32FRAME
*)((char *)frame
- offsetof(STACK32FRAME
,frame
));
264 NtCurrentTeb()->cur_stack
= frame32
->frame16
;
267 else if (record
->ExceptionCode
== EXCEPTION_ACCESS_VIOLATION
||
268 record
->ExceptionCode
== EXCEPTION_PRIV_INSTRUCTION
)
270 if (wine_ldt_is_system(context
->SegCs
))
272 if (fix_selector( context
)) return ExceptionContinueExecution
;
277 DWORD ret
= INSTR_EmulateInstruction( record
, context
);
280 * Insert check for pending DPMI events. Note that this
281 * check must be inserted after instructions have been
282 * emulated because the instruction emulation requires
283 * original CS:IP and the emulation may change TEB.dpmi_vif.
285 if(NtCurrentTeb()->dpmi_vif
)
286 insert_event_check( context
);
288 if (ret
!= ExceptionContinueSearch
) return ret
;
290 /* check for Win16 __GP handler */
291 if ((gpHandler
= HasGPHandler16( MAKESEGPTR( context
->SegCs
, context
->Eip
) )))
293 WORD
*stack
= wine_ldt_get_ptr( context
->SegSs
, context
->Esp
);
294 *--stack
= context
->SegCs
;
295 *--stack
= context
->Eip
;
297 if (!IS_SELECTOR_32BIT(context
->SegSs
))
298 context
->Esp
= MAKELONG( LOWORD(context
->Esp
- 2*sizeof(WORD
)),
299 HIWORD(context
->Esp
) );
301 context
->Esp
-= 2*sizeof(WORD
);
303 context
->SegCs
= SELECTOROF( gpHandler
);
304 context
->Eip
= OFFSETOF( gpHandler
);
305 return ExceptionContinueExecution
;
309 else if (record
->ExceptionCode
== EXCEPTION_VM86_STI
)
311 insert_event_check( context
);
313 return ExceptionContinueSearch
;
317 /*************************************************************
320 * Handler for exceptions occurring in vm86 code.
322 static DWORD
vm86_handler( EXCEPTION_RECORD
*record
, EXCEPTION_REGISTRATION_RECORD
*frame
,
323 CONTEXT
*context
, EXCEPTION_REGISTRATION_RECORD
**pdispatcher
)
325 if (record
->ExceptionFlags
& (EH_UNWINDING
| EH_EXIT_UNWIND
))
326 return ExceptionContinueSearch
;
328 if (record
->ExceptionCode
== EXCEPTION_ACCESS_VIOLATION
||
329 record
->ExceptionCode
== EXCEPTION_PRIV_INSTRUCTION
)
331 return INSTR_EmulateInstruction( record
, context
);
334 return ExceptionContinueSearch
;
338 /***********************************************************************
341 * Vectored exception handler used to emulate protected instructions
344 static LONG CALLBACK
vectored_handler( EXCEPTION_POINTERS
*ptrs
)
346 EXCEPTION_RECORD
*record
= ptrs
->ExceptionRecord
;
347 CONTEXT
*context
= ptrs
->ContextRecord
;
349 if (wine_ldt_is_system(context
->SegCs
) &&
350 (record
->ExceptionCode
== EXCEPTION_ACCESS_VIOLATION
||
351 record
->ExceptionCode
== EXCEPTION_PRIV_INSTRUCTION
))
353 if (INSTR_EmulateInstruction( record
, context
) == ExceptionContinueExecution
)
354 return EXCEPTION_CONTINUE_EXECUTION
;
356 return EXCEPTION_CONTINUE_SEARCH
;
362 BOOL
WOWTHUNK_Init(void)
367 #endif /* __i386__ */
371 * 32-bit WOW routines (in WOW32, but actually forwarded to KERNEL32)
374 /**********************************************************************
375 * K32WOWGetDescriptor (KERNEL32.70)
377 BOOL WINAPI
K32WOWGetDescriptor( SEGPTR segptr
, LPLDT_ENTRY ldtent
)
379 return GetThreadSelectorEntry( GetCurrentThread(),
380 segptr
>> 16, ldtent
);
383 /**********************************************************************
384 * K32WOWGetVDMPointer (KERNEL32.56)
386 LPVOID WINAPI
K32WOWGetVDMPointer( DWORD vp
, DWORD dwBytes
, BOOL fProtectedMode
)
388 /* FIXME: add size check too */
390 if ( fProtectedMode
)
393 return DOSMEM_MapRealToLinear( vp
);
396 /**********************************************************************
397 * K32WOWGetVDMPointerFix (KERNEL32.68)
399 LPVOID WINAPI
K32WOWGetVDMPointerFix( DWORD vp
, DWORD dwBytes
, BOOL fProtectedMode
)
402 * Hmmm. According to the docu, we should call:
404 * GlobalFix16( SELECTOROF(vp) );
406 * But this is unnecessary under Wine, as we never move global
407 * memory segments in linear memory anyway.
409 * (I'm not so sure what we are *supposed* to do if
410 * fProtectedMode is TRUE, anyway ...)
413 return K32WOWGetVDMPointer( vp
, dwBytes
, fProtectedMode
);
416 /**********************************************************************
417 * K32WOWGetVDMPointerUnfix (KERNEL32.69)
419 VOID WINAPI
K32WOWGetVDMPointerUnfix( DWORD vp
)
422 * See above why we don't call:
424 * GlobalUnfix16( SELECTOROF(vp) );
429 /**********************************************************************
430 * K32WOWGlobalAlloc16 (KERNEL32.59)
432 WORD WINAPI
K32WOWGlobalAlloc16( WORD wFlags
, DWORD cb
)
434 return (WORD
)GlobalAlloc16( wFlags
, cb
);
437 /**********************************************************************
438 * K32WOWGlobalFree16 (KERNEL32.62)
440 WORD WINAPI
K32WOWGlobalFree16( WORD hMem
)
442 return (WORD
)GlobalFree16( (HGLOBAL16
)hMem
);
445 /**********************************************************************
446 * K32WOWGlobalUnlock16 (KERNEL32.61)
448 BOOL WINAPI
K32WOWGlobalUnlock16( WORD hMem
)
450 return (BOOL
)GlobalUnlock16( (HGLOBAL16
)hMem
);
453 /**********************************************************************
454 * K32WOWGlobalAllocLock16 (KERNEL32.63)
456 DWORD WINAPI
K32WOWGlobalAllocLock16( WORD wFlags
, DWORD cb
, WORD
*phMem
)
458 WORD hMem
= K32WOWGlobalAlloc16( wFlags
, cb
);
459 if (phMem
) *phMem
= hMem
;
461 return K32WOWGlobalLock16( hMem
);
464 /**********************************************************************
465 * K32WOWGlobalLockSize16 (KERNEL32.65)
467 DWORD WINAPI
K32WOWGlobalLockSize16( WORD hMem
, PDWORD pcb
)
470 *pcb
= GlobalSize16( (HGLOBAL16
)hMem
);
472 return K32WOWGlobalLock16( hMem
);
475 /**********************************************************************
476 * K32WOWGlobalUnlockFree16 (KERNEL32.64)
478 WORD WINAPI
K32WOWGlobalUnlockFree16( DWORD vpMem
)
480 if ( !K32WOWGlobalUnlock16( HIWORD(vpMem
) ) )
483 return K32WOWGlobalFree16( HIWORD(vpMem
) );
487 /**********************************************************************
488 * K32WOWYield16 (KERNEL32.66)
490 VOID WINAPI
K32WOWYield16( void )
493 * This does the right thing for both Win16 and Win32 tasks.
494 * More or less, at least :-/
499 /**********************************************************************
500 * K32WOWDirectedYield16 (KERNEL32.67)
502 VOID WINAPI
K32WOWDirectedYield16( WORD htask16
)
505 * Argh. Our scheduler doesn't like DirectedYield by Win32
506 * tasks at all. So we do hope that this routine is indeed
507 * only ever called by Win16 tasks that have thunked up ...
509 DirectedYield16( (HTASK16
)htask16
);
513 /***********************************************************************
514 * K32WOWHandle32 (KERNEL32.57)
516 HANDLE WINAPI
K32WOWHandle32( WORD handle
, WOW_HANDLE_TYPE type
)
527 case WOW_TYPE_HBITMAP
:
528 case WOW_TYPE_HBRUSH
:
529 case WOW_TYPE_HPALETTE
:
531 case WOW_TYPE_HACCEL
:
532 return (HANDLE
)(ULONG_PTR
)handle
;
534 case WOW_TYPE_HMETAFILE
:
535 FIXME( "conversion of metafile handles not supported yet\n" );
536 return (HANDLE
)(ULONG_PTR
)handle
;
539 return ((TDB
*)GlobalLock16(handle
))->teb
->ClientId
.UniqueThread
;
541 case WOW_TYPE_FULLHWND
:
542 FIXME( "conversion of full window handles not supported yet\n" );
543 return (HANDLE
)(ULONG_PTR
)handle
;
546 ERR( "handle 0x%04x of unknown type %d\n", handle
, type
);
547 return (HANDLE
)(ULONG_PTR
)handle
;
551 /***********************************************************************
552 * K32WOWHandle16 (KERNEL32.58)
554 WORD WINAPI
K32WOWHandle16( HANDLE handle
, WOW_HANDLE_TYPE type
)
565 case WOW_TYPE_HBITMAP
:
566 case WOW_TYPE_HBRUSH
:
567 case WOW_TYPE_HPALETTE
:
569 case WOW_TYPE_HACCEL
:
570 case WOW_TYPE_FULLHWND
:
571 if ( HIWORD(handle
) )
572 ERR( "handle %p of type %d has non-zero HIWORD\n", handle
, type
);
573 return LOWORD(handle
);
575 case WOW_TYPE_HMETAFILE
:
576 FIXME( "conversion of metafile handles not supported yet\n" );
577 return LOWORD(handle
);
580 return TASK_GetTaskFromThread( (DWORD
)handle
);
583 ERR( "handle %p of unknown type %d\n", handle
, type
);
584 return LOWORD(handle
);
588 /**********************************************************************
589 * K32WOWCallback16Ex (KERNEL32.55)
591 BOOL WINAPI
K32WOWCallback16Ex( DWORD vpfn16
, DWORD dwFlags
,
592 DWORD cbArgs
, LPVOID pArgs
, LPDWORD pdwRetCode
)
596 * Arguments must be prepared in the correct order by the caller
597 * (both for PASCAL and CDECL calling convention), so we simply
598 * copy them to the 16-bit stack ...
600 WORD
*stack
= (WORD
*)CURRENT_STACK16
- cbArgs
/ sizeof(WORD
);
602 memcpy( stack
, pArgs
, cbArgs
);
604 if (dwFlags
& (WCB16_REGS
|WCB16_REGS_LONG
))
606 CONTEXT
*context
= (CONTEXT
*)pdwRetCode
;
610 DWORD count
= cbArgs
/ sizeof(WORD
);
612 DPRINTF("%04lx:CallTo16(func=%04lx:%04x,ds=%04lx",
613 GetCurrentThreadId(),
614 context
->SegCs
, LOWORD(context
->Eip
), context
->SegDs
);
615 while (count
) DPRINTF( ",%04x", stack
[--count
] );
616 DPRINTF(") ss:sp=%04x:%04x",
617 SELECTOROF(NtCurrentTeb()->cur_stack
), OFFSETOF(NtCurrentTeb()->cur_stack
) );
618 DPRINTF(" ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x bp=%04x es=%04x fs=%04x\n",
619 (WORD
)context
->Eax
, (WORD
)context
->Ebx
, (WORD
)context
->Ecx
,
620 (WORD
)context
->Edx
, (WORD
)context
->Esi
, (WORD
)context
->Edi
,
621 (WORD
)context
->Ebp
, (WORD
)context
->SegEs
, (WORD
)context
->SegFs
);
622 SYSLEVEL_CheckNotLevel( 2 );
625 if (context
->EFlags
& 0x00020000) /* v86 mode */
627 EXCEPTION_REGISTRATION_RECORD frame
;
628 frame
.Handler
= vm86_handler
;
629 __wine_push_frame( &frame
);
630 __wine_enter_vm86( context
);
631 __wine_pop_frame( &frame
);
635 /* push return address */
636 if (dwFlags
& WCB16_REGS_LONG
)
638 *((DWORD
*)stack
- 1) = HIWORD(call16_ret_addr
);
639 *((DWORD
*)stack
- 2) = LOWORD(call16_ret_addr
);
640 cbArgs
+= 2 * sizeof(DWORD
);
644 *((SEGPTR
*)stack
- 1) = call16_ret_addr
;
645 cbArgs
+= sizeof(SEGPTR
);
649 * Start call by checking for pending events.
650 * Note that wine_call_to_16_regs overwrites context stack
651 * pointer so we may modify it here without a problem.
653 if (NtCurrentTeb()->dpmi_vif
)
655 context
->SegSs
= wine_get_ds();
656 context
->Esp
= (DWORD
)stack
;
657 insert_event_check( context
);
658 cbArgs
+= (DWORD
)stack
- context
->Esp
;
662 wine_call_to_16_regs( context
, cbArgs
, call16_handler
);
668 DPRINTF("%04lx:RetFrom16() ss:sp=%04x:%04x ",
669 GetCurrentThreadId(), SELECTOROF(NtCurrentTeb()->cur_stack
),
670 OFFSETOF(NtCurrentTeb()->cur_stack
));
671 DPRINTF(" ax=%04x bx=%04x cx=%04x dx=%04x bp=%04x sp=%04x\n",
672 (WORD
)context
->Eax
, (WORD
)context
->Ebx
, (WORD
)context
->Ecx
,
673 (WORD
)context
->Edx
, (WORD
)context
->Ebp
, (WORD
)context
->Esp
);
674 SYSLEVEL_CheckNotLevel( 2 );
683 DWORD count
= cbArgs
/ sizeof(WORD
);
685 DPRINTF("%04lx:CallTo16(func=%04x:%04x,ds=%04x",
686 GetCurrentThreadId(), HIWORD(vpfn16
), LOWORD(vpfn16
),
687 SELECTOROF(NtCurrentTeb()->cur_stack
) );
688 while (count
) DPRINTF( ",%04x", stack
[--count
] );
689 DPRINTF(") ss:sp=%04x:%04x\n",
690 SELECTOROF(NtCurrentTeb()->cur_stack
), OFFSETOF(NtCurrentTeb()->cur_stack
) );
691 SYSLEVEL_CheckNotLevel( 2 );
694 /* push return address */
695 *((SEGPTR
*)stack
- 1) = call16_ret_addr
;
696 cbArgs
+= sizeof(SEGPTR
);
699 * Actually, we should take care whether the called routine cleans up
700 * its stack or not. Fortunately, our wine_call_to_16 core doesn't rely on
701 * the callee to do so; after the routine has returned, the 16-bit
702 * stack pointer is always reset to the position it had before.
705 ret
= wine_call_to_16( (FARPROC16
)vpfn16
, cbArgs
, call16_handler
);
706 if (pdwRetCode
) *pdwRetCode
= ret
;
711 DPRINTF("%04lx:RetFrom16() ss:sp=%04x:%04x retval=%08lx\n",
712 GetCurrentThreadId(), SELECTOROF(NtCurrentTeb()->cur_stack
),
713 OFFSETOF(NtCurrentTeb()->cur_stack
), ret
);
714 SYSLEVEL_CheckNotLevel( 2 );
718 assert(0); /* cannot call to 16-bit on non-Intel architectures */
719 #endif /* __i386__ */
721 return TRUE
; /* success */
724 /**********************************************************************
725 * K32WOWCallback16 (KERNEL32.54)
727 DWORD WINAPI
K32WOWCallback16( DWORD vpfn16
, DWORD dwParam
)
731 if ( !K32WOWCallback16Ex( vpfn16
, WCB16_PASCAL
,
732 sizeof(DWORD
), &dwParam
, &ret
) )
740 * 16-bit WOW routines (in KERNEL)
743 /**********************************************************************
744 * GetVDMPointer32W (KERNEL.516)
746 DWORD WINAPI
GetVDMPointer32W16( SEGPTR vp
, UINT16 fMode
)
748 GlobalPageLock16(GlobalHandle16(SELECTOROF(vp
)));
749 return (DWORD
)K32WOWGetVDMPointer( vp
, 0, (DWORD
)fMode
);
752 /***********************************************************************
753 * LoadLibraryEx32W (KERNEL.513)
755 DWORD WINAPI
LoadLibraryEx32W16( LPCSTR lpszLibFile
, DWORD hFile
, DWORD dwFlags
)
764 SetLastError(ERROR_INVALID_PARAMETER
);
768 /* if the file can not be found, call LoadLibraryExA anyway, since it might be
769 a builtin module. This case is handled in MODULE_LoadLibraryExA */
771 if ((p
= strrchr( lpszLibFile
, '.' )) && !strchr( p
, '\\' )) /* got an extension */
773 if (OpenFile16( lpszLibFile
, &ofs
, OF_EXIST
) != HFILE_ERROR16
)
774 lpszLibFile
= ofs
.szPathName
;
778 char buffer
[MAX_PATH
+4];
779 strcpy( buffer
, lpszLibFile
);
780 strcat( buffer
, ".dll" );
781 if (OpenFile16( buffer
, &ofs
, OF_EXIST
) != HFILE_ERROR16
)
782 lpszLibFile
= ofs
.szPathName
;
785 ReleaseThunkLock( &mutex_count
);
786 hModule
= LoadLibraryExA( lpszLibFile
, (HANDLE
)hFile
, dwFlags
);
787 RestoreThunkLock( mutex_count
);
789 return (DWORD
)hModule
;
792 /***********************************************************************
793 * GetProcAddress32W (KERNEL.515)
795 DWORD WINAPI
GetProcAddress32W16( DWORD hModule
, LPCSTR lpszProc
)
797 return (DWORD
)GetProcAddress( (HMODULE
)hModule
, lpszProc
);
800 /***********************************************************************
801 * FreeLibrary32W (KERNEL.514)
803 DWORD WINAPI
FreeLibrary32W16( DWORD hLibModule
)
808 ReleaseThunkLock( &mutex_count
);
809 retv
= FreeLibrary( (HMODULE
)hLibModule
);
810 RestoreThunkLock( mutex_count
);
815 /**********************************************************************
818 static DWORD
WOW_CallProc32W16( FARPROC proc32
, DWORD nrofargs
, DWORD
*args
)
823 ReleaseThunkLock( &mutex_count
);
826 * FIXME: If ( nrofargs & CPEX_DEST_CDECL ) != 0, we should call a
827 * 32-bit CDECL routine ...
830 if (!proc32
) ret
= 0;
831 else switch (nrofargs
)
833 case 0: ret
= proc32();
835 case 1: ret
= proc32(args
[0]);
837 case 2: ret
= proc32(args
[0],args
[1]);
839 case 3: ret
= proc32(args
[0],args
[1],args
[2]);
841 case 4: ret
= proc32(args
[0],args
[1],args
[2],args
[3]);
843 case 5: ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4]);
845 case 6: ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5]);
847 case 7: ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6]);
849 case 8: ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7]);
851 case 9: ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8]);
853 case 10:ret
= proc32(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8],args
[9]);
855 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]);
857 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]);
859 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]);
861 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]);
863 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]);
866 /* FIXME: should go up to 32 arguments */
867 ERR("Unsupported number of arguments %ld, please report.\n",nrofargs
);
872 RestoreThunkLock( mutex_count
);
874 TRACE("returns %08lx\n",ret
);
878 /**********************************************************************
879 * CallProc32W (KERNEL.517)
881 DWORD WINAPIV
CallProc32W16( DWORD nrofargs
, DWORD argconvmask
, FARPROC proc32
, VA_LIST16 valist
)
886 TRACE("(%ld,%ld,%p args[",nrofargs
,argconvmask
,proc32
);
888 for (i
=0;i
<nrofargs
;i
++)
890 if (argconvmask
& (1<<i
))
892 SEGPTR ptr
= VA_ARG16( valist
, SEGPTR
);
893 /* pascal convention, have to reverse the arguments order */
894 args
[nrofargs
- i
- 1] = (DWORD
)MapSL(ptr
);
895 TRACE("%08lx(%p),",ptr
,MapSL(ptr
));
899 DWORD arg
= VA_ARG16( valist
, DWORD
);
900 /* pascal convention, have to reverse the arguments order */
901 args
[nrofargs
- i
- 1] = arg
;
907 /* POP nrofargs DWORD arguments and 3 DWORD parameters */
908 stack16_pop( (3 + nrofargs
) * sizeof(DWORD
) );
910 return WOW_CallProc32W16( proc32
, nrofargs
, args
);
913 /**********************************************************************
914 * _CallProcEx32W (KERNEL.518)
916 DWORD WINAPIV
CallProcEx32W16( DWORD nrofargs
, DWORD argconvmask
, FARPROC proc32
, VA_LIST16 valist
)
921 TRACE("(%ld,%ld,%p args[",nrofargs
,argconvmask
,proc32
);
923 for (i
=0;i
<nrofargs
;i
++)
925 if (argconvmask
& (1<<i
))
927 SEGPTR ptr
= VA_ARG16( valist
, SEGPTR
);
928 args
[i
] = (DWORD
)MapSL(ptr
);
929 TRACE("%08lx(%p),",ptr
,MapSL(ptr
));
933 DWORD arg
= VA_ARG16( valist
, DWORD
);
939 return WOW_CallProc32W16( proc32
, nrofargs
, args
);
943 /**********************************************************************
944 * WOW16Call (KERNEL.500)
949 DWORD WINAPIV
WOW16Call(WORD x
, WORD y
, WORD z
, VA_LIST16 args
)
953 FIXME("(0x%04x,0x%04x,%d),calling (",x
,y
,z
);
955 for (i
=0;i
<x
/2;i
++) {
956 WORD a
= VA_ARG16(args
,WORD
);
959 calladdr
= VA_ARG16(args
,DWORD
);
960 stack16_pop( 3*sizeof(WORD
) + x
+ sizeof(DWORD
) );
961 DPRINTF(") calling address was 0x%08lx\n",calladdr
);
966 /***********************************************************************
967 * CreateThread16 (KERNEL.441)
969 HANDLE WINAPI
CreateThread16( SECURITY_ATTRIBUTES
*sa
, DWORD stack
,
970 FARPROC16 start
, SEGPTR param
,
971 DWORD flags
, LPDWORD id
)
973 struct thread_args
*args
= HeapAlloc( GetProcessHeap(), 0, sizeof(*args
) );
974 if (!args
) return INVALID_HANDLE_VALUE
;
977 return CreateThread( sa
, stack
, start_thread16
, args
, flags
, id
);