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