Fixed some issues found by winapi_check.
[wine] / dlls / kernel / wowthunk.c
1 /*
2  * Win32 WOW Generic Thunk API
3  *
4  * Copyright 1999 Ulrich Weigand
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include "wine/winbase16.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "wownt32.h"
28 #include "winternl.h"
29 #include "file.h"
30 #include "miscemu.h"
31 #include "stackframe.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(thunk);
35
36 /*
37  * These are the 16-bit side WOW routines.  They reside in wownt16.h
38  * in the SDK; since we don't support Win16 source code anyway, I've
39  * placed them here for compilation with Wine ...
40  */
41
42 DWORD WINAPI GetVDMPointer32W16(SEGPTR,UINT16);
43
44 DWORD WINAPI LoadLibraryEx32W16(LPCSTR,DWORD,DWORD);
45 DWORD WINAPI GetProcAddress32W16(DWORD,LPCSTR);
46 DWORD WINAPI FreeLibrary32W16(DWORD);
47
48 #define CPEX_DEST_STDCALL   0x00000000L
49 #define CPEX_DEST_CDECL     0x80000000L
50
51 DWORD WINAPI CallProcExW16(VOID);
52 DWORD WINAPI CallProcEx32W16(VOID);
53
54 /*
55  *  32-bit WOW routines (in WOW32, but actually forwarded to KERNEL32)
56  */
57
58 /**********************************************************************
59  *           K32WOWGetDescriptor        (KERNEL32.70)
60  */
61 BOOL WINAPI K32WOWGetDescriptor( SEGPTR segptr, LPLDT_ENTRY ldtent )
62 {
63     return GetThreadSelectorEntry( GetCurrentThread(),
64                                    segptr >> 16, ldtent );
65 }
66
67 /**********************************************************************
68  *           K32WOWGetVDMPointer        (KERNEL32.56)
69  */
70 LPVOID WINAPI K32WOWGetVDMPointer( DWORD vp, DWORD dwBytes, BOOL fProtectedMode )
71 {
72     /* FIXME: add size check too */
73
74     if ( fProtectedMode )
75         return MapSL( vp );
76     else
77         return DOSMEM_MapRealToLinear( vp );
78 }
79
80 /**********************************************************************
81  *           K32WOWGetVDMPointerFix     (KERNEL32.68)
82  */
83 LPVOID WINAPI K32WOWGetVDMPointerFix( DWORD vp, DWORD dwBytes, BOOL fProtectedMode )
84 {
85     /*
86      * Hmmm. According to the docu, we should call:
87      *
88      *          GlobalFix16( SELECTOROF(vp) );
89      *
90      * But this is unnecessary under Wine, as we never move global
91      * memory segments in linear memory anyway.
92      *
93      * (I'm not so sure what we are *supposed* to do if
94      *  fProtectedMode is TRUE, anyway ...)
95      */
96
97     return K32WOWGetVDMPointer( vp, dwBytes, fProtectedMode );
98 }
99
100 /**********************************************************************
101  *           K32WOWGetVDMPointerUnfix   (KERNEL32.69)
102  */
103 VOID WINAPI K32WOWGetVDMPointerUnfix( DWORD vp )
104 {
105     /*
106      * See above why we don't call:
107      *
108      * GlobalUnfix16( SELECTOROF(vp) );
109      *
110      */
111 }
112
113 /**********************************************************************
114  *           K32WOWGlobalAlloc16        (KERNEL32.59)
115  */
116 WORD WINAPI K32WOWGlobalAlloc16( WORD wFlags, DWORD cb )
117 {
118     return (WORD)GlobalAlloc16( wFlags, cb );
119 }
120
121 /**********************************************************************
122  *           K32WOWGlobalFree16         (KERNEL32.62)
123  */
124 WORD WINAPI K32WOWGlobalFree16( WORD hMem )
125 {
126     return (WORD)GlobalFree16( (HGLOBAL16)hMem );
127 }
128
129 /**********************************************************************
130  *           K32WOWGlobalUnlock16       (KERNEL32.61)
131  */
132 BOOL WINAPI K32WOWGlobalUnlock16( WORD hMem )
133 {
134     return (BOOL)GlobalUnlock16( (HGLOBAL16)hMem );
135 }
136
137 /**********************************************************************
138  *           K32WOWGlobalAllocLock16    (KERNEL32.63)
139  */
140 DWORD WINAPI K32WOWGlobalAllocLock16( WORD wFlags, DWORD cb, WORD *phMem )
141 {
142     WORD hMem = K32WOWGlobalAlloc16( wFlags, cb );
143     if (phMem) *phMem = hMem;
144
145     return K32WOWGlobalLock16( hMem );
146 }
147
148 /**********************************************************************
149  *           K32WOWGlobalLockSize16     (KERNEL32.65)
150  */
151 DWORD WINAPI K32WOWGlobalLockSize16( WORD hMem, PDWORD pcb )
152 {
153     if ( pcb )
154         *pcb = GlobalSize16( (HGLOBAL16)hMem );
155
156     return K32WOWGlobalLock16( hMem );
157 }
158
159 /**********************************************************************
160  *           K32WOWGlobalUnlockFree16   (KERNEL32.64)
161  */
162 WORD WINAPI K32WOWGlobalUnlockFree16( DWORD vpMem )
163 {
164     if ( !K32WOWGlobalUnlock16( HIWORD(vpMem) ) )
165         return FALSE;
166
167     return K32WOWGlobalFree16( HIWORD(vpMem) );
168 }
169
170
171 /**********************************************************************
172  *           K32WOWYield16              (KERNEL32.66)
173  */
174 VOID WINAPI K32WOWYield16( void )
175 {
176     /*
177      * This does the right thing for both Win16 and Win32 tasks.
178      * More or less, at least :-/
179      */
180     Yield16();
181 }
182
183 /**********************************************************************
184  *           K32WOWDirectedYield16       (KERNEL32.67)
185  */
186 VOID WINAPI K32WOWDirectedYield16( WORD htask16 )
187 {
188     /*
189      * Argh.  Our scheduler doesn't like DirectedYield by Win32
190      * tasks at all.  So we do hope that this routine is indeed
191      * only ever called by Win16 tasks that have thunked up ...
192      */
193     DirectedYield16( (HTASK16)htask16 );
194 }
195
196
197 /***********************************************************************
198  *           K32WOWHandle32              (KERNEL32.57)
199  */
200 HANDLE WINAPI K32WOWHandle32( WORD handle, WOW_HANDLE_TYPE type )
201 {
202     switch ( type )
203     {
204     case WOW_TYPE_HWND:
205     case WOW_TYPE_HMENU:
206     case WOW_TYPE_HDWP:
207     case WOW_TYPE_HDROP:
208     case WOW_TYPE_HDC:
209     case WOW_TYPE_HFONT:
210     case WOW_TYPE_HMETAFILE:
211     case WOW_TYPE_HRGN:
212     case WOW_TYPE_HBITMAP:
213     case WOW_TYPE_HBRUSH:
214     case WOW_TYPE_HPALETTE:
215     case WOW_TYPE_HPEN:
216     case WOW_TYPE_HACCEL:
217     case WOW_TYPE_HTASK:
218     case WOW_TYPE_FULLHWND:
219         return (HANDLE)(ULONG_PTR)handle;
220
221     default:
222         ERR( "handle 0x%04x of unknown type %d\n", handle, type );
223         return (HANDLE)(ULONG_PTR)handle;
224     }
225 }
226
227 /***********************************************************************
228  *           K32WOWHandle16              (KERNEL32.58)
229  */
230 WORD WINAPI K32WOWHandle16( HANDLE handle, WOW_HANDLE_TYPE type )
231 {
232     if ( HIWORD(handle ) )
233         ERR( "handle 0x%08x of type %d has non-zero HIWORD\n", handle, type );
234
235     switch ( type )
236     {
237     case WOW_TYPE_HWND:
238     case WOW_TYPE_HMENU:
239     case WOW_TYPE_HDWP:
240     case WOW_TYPE_HDROP:
241     case WOW_TYPE_HDC:
242     case WOW_TYPE_HFONT:
243     case WOW_TYPE_HMETAFILE:
244     case WOW_TYPE_HRGN:
245     case WOW_TYPE_HBITMAP:
246     case WOW_TYPE_HBRUSH:
247     case WOW_TYPE_HPALETTE:
248     case WOW_TYPE_HPEN:
249     case WOW_TYPE_HACCEL:
250     case WOW_TYPE_HTASK:
251     case WOW_TYPE_FULLHWND:
252         return LOWORD(handle);
253
254     default:
255         ERR( "handle 0x%08x of unknown type %d\n", handle, type );
256         return LOWORD(handle);
257     }
258 }
259
260 /**********************************************************************
261  *           K32WOWCallback16Ex         (KERNEL32.55)
262  */
263 BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags,
264                                 DWORD cbArgs, LPVOID pArgs, LPDWORD pdwRetCode )
265 {
266     DWORD ret;
267
268     /*
269      * Arguments must be prepared in the correct order by the caller
270      * (both for PASCAL and CDECL calling convention), so we simply
271      * copy them to the 16-bit stack ...
272      */
273     memcpy( (LPBYTE)CURRENT_STACK16 - cbArgs, (LPBYTE)pArgs, cbArgs );
274
275
276     /*
277      * Actually, we should take care whether the called routine cleans up
278      * its stack or not.  Fortunately, our wine_call_to_16 core doesn't rely on
279      * the callee to do so; after the routine has returned, the 16-bit
280      * stack pointer is always reset to the position it had before.
281      */
282
283     ret = wine_call_to_16_long( (FARPROC16)vpfn16, cbArgs );
284
285     if ( pdwRetCode )
286         *pdwRetCode = ret;
287
288     return TRUE;  /* success */
289 }
290
291 /**********************************************************************
292  *           K32WOWCallback16            (KERNEL32.54)
293  */
294 DWORD WINAPI K32WOWCallback16( DWORD vpfn16, DWORD dwParam )
295 {
296     DWORD ret;
297
298     if ( !K32WOWCallback16Ex( vpfn16, WCB16_PASCAL,
299                            sizeof(DWORD), &dwParam, &ret ) )
300         ret = 0L;
301
302     return ret;
303 }
304
305
306 /*
307  *  16-bit WOW routines (in KERNEL)
308  */
309
310 /**********************************************************************
311  *           GetVDMPointer32W      (KERNEL.516)
312  */
313 DWORD WINAPI GetVDMPointer32W16( SEGPTR vp, UINT16 fMode )
314 {
315     GlobalPageLock16(GlobalHandle16(SELECTOROF(vp)));
316     return (DWORD)K32WOWGetVDMPointer( vp, 0, (DWORD)fMode );
317 }
318
319 /***********************************************************************
320  *           LoadLibraryEx32W      (KERNEL.513)
321  */
322 DWORD WINAPI LoadLibraryEx32W16( LPCSTR lpszLibFile, DWORD hFile, DWORD dwFlags )
323 {
324     HMODULE hModule;
325     DOS_FULL_NAME full_name;
326     DWORD mutex_count;
327     UNICODE_STRING libfileW;
328     LPCWSTR filenameW;
329     static const WCHAR dllW[] = {'.','D','L','L',0};
330
331     if (!lpszLibFile)
332     {
333         SetLastError(ERROR_INVALID_PARAMETER);
334         return 0;
335     }
336
337     if (!RtlCreateUnicodeStringFromAsciiz(&libfileW, lpszLibFile))
338     {
339         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
340         return 0;
341     }
342
343     /* if the file can not be found, call LoadLibraryExA anyway, since it might be
344        a buildin module. This case is handled in MODULE_LoadLibraryExA */
345
346     filenameW = libfileW.Buffer;
347     if ( DIR_SearchPath( NULL, filenameW, dllW, &full_name, FALSE ) )
348         filenameW = full_name.short_name;
349
350     ReleaseThunkLock( &mutex_count );
351     hModule = LoadLibraryExW( filenameW, (HANDLE)hFile, dwFlags );
352     RestoreThunkLock( mutex_count );
353
354     RtlFreeUnicodeString(&libfileW);
355
356     return (DWORD)hModule;
357 }
358
359 /***********************************************************************
360  *           GetProcAddress32W     (KERNEL.515)
361  */
362 DWORD WINAPI GetProcAddress32W16( DWORD hModule, LPCSTR lpszProc )
363 {
364     return (DWORD)GetProcAddress( (HMODULE)hModule, lpszProc );
365 }
366
367 /***********************************************************************
368  *           FreeLibrary32W        (KERNEL.514)
369  */
370 DWORD WINAPI FreeLibrary32W16( DWORD hLibModule )
371 {
372     BOOL retv;
373     DWORD mutex_count;
374
375     ReleaseThunkLock( &mutex_count );
376     retv = FreeLibrary( (HMODULE)hLibModule );
377     RestoreThunkLock( mutex_count );
378     return (DWORD)retv;
379 }
380
381
382 /**********************************************************************
383  *           WOW_CallProc32W
384  */
385 static DWORD WOW_CallProc32W16( BOOL Ex )
386 {
387     DWORD nrofargs, argconvmask;
388     FARPROC proc32;
389     DWORD *args, ret;
390     DWORD mutex_count;
391     VA_LIST16 valist;
392     int i;
393     int aix;
394
395     ReleaseThunkLock( &mutex_count );
396
397     VA_START16( valist );
398     nrofargs    = VA_ARG16( valist, DWORD );
399     argconvmask = VA_ARG16( valist, DWORD );
400     proc32      = VA_ARG16( valist, FARPROC );
401     TRACE("(%ld,%ld,%p, Ex%d args[",nrofargs,argconvmask,proc32,Ex);
402     args = (DWORD*)HeapAlloc( GetProcessHeap(), 0, sizeof(DWORD)*nrofargs );
403     if(args == NULL) proc32 = NULL; /* maybe we should WARN here? */
404     /* CallProcEx doesn't need its args reversed */
405     for (i=0;i<nrofargs;i++) {
406             if (Ex) {
407                aix = i;
408             } else {
409                aix = nrofargs - i - 1;
410             }
411             if (argconvmask & (1<<i))
412             {
413                 SEGPTR ptr = VA_ARG16( valist, SEGPTR );
414                 if (args) args[aix] = (DWORD)MapSL(ptr);
415                 if (TRACE_ON(thunk)) DPRINTF("%08lx(%p),",ptr,MapSL(ptr));
416             }
417             else
418             {
419                 DWORD arg = VA_ARG16( valist, DWORD );
420                 if (args) args[aix] = arg;
421                 if (TRACE_ON(thunk)) DPRINTF("%ld,", arg);
422             }
423     }
424     if (TRACE_ON(thunk)) DPRINTF("])\n");
425     VA_END16( valist );
426
427     /*
428      * FIXME:  If ( nrofargs & CPEX_DEST_CDECL ) != 0, we should call a
429      *         32-bit CDECL routine ...
430      */
431
432     if (!proc32) ret = 0;
433     else switch (nrofargs)
434     {
435     case 0: ret = proc32();
436             break;
437     case 1: ret = proc32(args[0]);
438             break;
439     case 2: ret = proc32(args[0],args[1]);
440             break;
441     case 3: ret = proc32(args[0],args[1],args[2]);
442             break;
443     case 4: ret = proc32(args[0],args[1],args[2],args[3]);
444             break;
445     case 5: ret = proc32(args[0],args[1],args[2],args[3],args[4]);
446             break;
447     case 6: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5]);
448             break;
449     case 7: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
450             break;
451     case 8: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
452             break;
453     case 9: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
454             break;
455     case 10:ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
456             break;
457     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]);
458             break;
459     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]);
460             break;
461     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]);
462             break;
463     default:
464             /* FIXME: should go up to 32  arguments */
465             ERR("Unsupported number of arguments %ld, please report.\n",nrofargs);
466             ret = 0;
467             break;
468     }
469
470     /* POP nrofargs DWORD arguments and 3 DWORD parameters */
471     if (!Ex) stack16_pop( (3 + nrofargs) * sizeof(DWORD) );
472
473     TRACE("returns %08lx\n",ret);
474     HeapFree( GetProcessHeap(), 0, args );
475
476     RestoreThunkLock( mutex_count );
477     return ret;
478 }
479
480 /**********************************************************************
481  *           CallProc32W           (KERNEL.517)
482  *
483  * DWORD PASCAL CallProc32W( DWORD p1, ... , DWORD lpProcAddress,
484  *                           DWORD fAddressConvert, DWORD cParams );
485  */
486 DWORD WINAPI CallProc32W16( void )
487 {
488     return WOW_CallProc32W16( FALSE );
489 }
490
491 /**********************************************************************
492  *           _CallProcEx32W         (KERNEL.518)
493  *
494  * DWORD CallProcEx32W( DWORD cParams, DWORD fAddressConvert,
495  *                      DWORD lpProcAddress, DWORD p1, ... );
496  */
497 DWORD WINAPI CallProcEx32W16( void )
498 {
499     return WOW_CallProc32W16( TRUE );
500 }
501
502
503 /**********************************************************************
504  *           WOW16Call               (KERNEL.500)
505  *
506  * FIXME!!!
507  *
508  */
509 DWORD WINAPI WOW16Call(WORD x,WORD y,WORD z)
510 {
511         int     i;
512         DWORD   calladdr;
513         VA_LIST16 args;
514         FIXME("(0x%04x,0x%04x,%d),calling (",x,y,z);
515
516         VA_START16(args);
517         for (i=0;i<x/2;i++) {
518                 WORD    a = VA_ARG16(args,WORD);
519                 DPRINTF("%04x ",a);
520         }
521         calladdr = VA_ARG16(args,DWORD);
522         VA_END16(args);
523         stack16_pop( x + sizeof(DWORD) );
524         DPRINTF(") calling address was 0x%08lx\n",calladdr);
525         return 0;
526 }