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