Crash on internal NULL pointers, don't test all over the place.
[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     if ( HIWORD(handle ) )
242         ERR( "handle 0x%08x of type %d has non-zero HIWORD\n", handle, type );
243
244     switch ( type )
245     {
246     case WOW_TYPE_HWND:
247     case WOW_TYPE_HMENU:
248     case WOW_TYPE_HDWP:
249     case WOW_TYPE_HDROP:
250     case WOW_TYPE_HDC:
251     case WOW_TYPE_HFONT:
252     case WOW_TYPE_HRGN:
253     case WOW_TYPE_HBITMAP:
254     case WOW_TYPE_HBRUSH:
255     case WOW_TYPE_HPALETTE:
256     case WOW_TYPE_HPEN:
257     case WOW_TYPE_HACCEL:
258     case WOW_TYPE_FULLHWND:
259         return LOWORD(handle);
260
261     case WOW_TYPE_HMETAFILE:
262         FIXME( "conversion of metafile handles not supported yet\n" );
263         return LOWORD(handle);
264
265     case WOW_TYPE_HTASK:
266         return THREAD_IdToTEB((DWORD)handle)->htask16;
267
268     default:
269         ERR( "handle 0x%08x of unknown type %d\n", handle, type );
270         return LOWORD(handle);
271     }
272 }
273
274 /**********************************************************************
275  *           K32WOWCallback16Ex         (KERNEL32.55)
276  */
277 BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags,
278                                 DWORD cbArgs, LPVOID pArgs, LPDWORD pdwRetCode )
279 {
280     DWORD ret;
281
282     /*
283      * Arguments must be prepared in the correct order by the caller
284      * (both for PASCAL and CDECL calling convention), so we simply
285      * copy them to the 16-bit stack ...
286      */
287     memcpy( (LPBYTE)CURRENT_STACK16 - cbArgs, (LPBYTE)pArgs, cbArgs );
288
289
290     /*
291      * Actually, we should take care whether the called routine cleans up
292      * its stack or not.  Fortunately, our wine_call_to_16 core doesn't rely on
293      * the callee to do so; after the routine has returned, the 16-bit
294      * stack pointer is always reset to the position it had before.
295      */
296
297     ret = wine_call_to_16( (FARPROC16)vpfn16, cbArgs );
298
299     if ( pdwRetCode )
300         *pdwRetCode = ret;
301
302     return TRUE;  /* success */
303 }
304
305 /**********************************************************************
306  *           K32WOWCallback16            (KERNEL32.54)
307  */
308 DWORD WINAPI K32WOWCallback16( DWORD vpfn16, DWORD dwParam )
309 {
310     DWORD ret;
311
312     if ( !K32WOWCallback16Ex( vpfn16, WCB16_PASCAL,
313                            sizeof(DWORD), &dwParam, &ret ) )
314         ret = 0L;
315
316     return ret;
317 }
318
319
320 /*
321  *  16-bit WOW routines (in KERNEL)
322  */
323
324 /**********************************************************************
325  *           GetVDMPointer32W      (KERNEL.516)
326  */
327 DWORD WINAPI GetVDMPointer32W16( SEGPTR vp, UINT16 fMode )
328 {
329     GlobalPageLock16(GlobalHandle16(SELECTOROF(vp)));
330     return (DWORD)K32WOWGetVDMPointer( vp, 0, (DWORD)fMode );
331 }
332
333 /***********************************************************************
334  *           LoadLibraryEx32W      (KERNEL.513)
335  */
336 DWORD WINAPI LoadLibraryEx32W16( LPCSTR lpszLibFile, DWORD hFile, DWORD dwFlags )
337 {
338     HMODULE hModule;
339     DOS_FULL_NAME full_name;
340     DWORD mutex_count;
341     UNICODE_STRING libfileW;
342     LPCWSTR filenameW;
343     static const WCHAR dllW[] = {'.','D','L','L',0};
344
345     if (!lpszLibFile)
346     {
347         SetLastError(ERROR_INVALID_PARAMETER);
348         return 0;
349     }
350
351     if (!RtlCreateUnicodeStringFromAsciiz(&libfileW, lpszLibFile))
352     {
353         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
354         return 0;
355     }
356
357     /* if the file can not be found, call LoadLibraryExA anyway, since it might be
358        a buildin module. This case is handled in MODULE_LoadLibraryExA */
359
360     filenameW = libfileW.Buffer;
361     if ( DIR_SearchPath( NULL, filenameW, dllW, &full_name, FALSE ) )
362         filenameW = full_name.short_name;
363
364     ReleaseThunkLock( &mutex_count );
365     hModule = LoadLibraryExW( filenameW, (HANDLE)hFile, dwFlags );
366     RestoreThunkLock( mutex_count );
367
368     RtlFreeUnicodeString(&libfileW);
369
370     return (DWORD)hModule;
371 }
372
373 /***********************************************************************
374  *           GetProcAddress32W     (KERNEL.515)
375  */
376 DWORD WINAPI GetProcAddress32W16( DWORD hModule, LPCSTR lpszProc )
377 {
378     return (DWORD)GetProcAddress( (HMODULE)hModule, lpszProc );
379 }
380
381 /***********************************************************************
382  *           FreeLibrary32W        (KERNEL.514)
383  */
384 DWORD WINAPI FreeLibrary32W16( DWORD hLibModule )
385 {
386     BOOL retv;
387     DWORD mutex_count;
388
389     ReleaseThunkLock( &mutex_count );
390     retv = FreeLibrary( (HMODULE)hLibModule );
391     RestoreThunkLock( mutex_count );
392     return (DWORD)retv;
393 }
394
395
396 /**********************************************************************
397  *           WOW_CallProc32W
398  */
399 static DWORD WOW_CallProc32W16( BOOL Ex )
400 {
401     DWORD nrofargs, argconvmask;
402     FARPROC proc32;
403     DWORD *args, ret;
404     DWORD mutex_count;
405     VA_LIST16 valist;
406     int i;
407     int aix;
408
409     ReleaseThunkLock( &mutex_count );
410
411     VA_START16( valist );
412     nrofargs    = VA_ARG16( valist, DWORD );
413     argconvmask = VA_ARG16( valist, DWORD );
414     proc32      = VA_ARG16( valist, FARPROC );
415     TRACE("(%ld,%ld,%p, Ex%d args[",nrofargs,argconvmask,proc32,Ex);
416     args = (DWORD*)HeapAlloc( GetProcessHeap(), 0, sizeof(DWORD)*nrofargs );
417     if(args == NULL) proc32 = NULL; /* maybe we should WARN here? */
418     /* CallProcEx doesn't need its args reversed */
419     for (i=0;i<nrofargs;i++) {
420             if (Ex) {
421                aix = i;
422             } else {
423                aix = nrofargs - i - 1;
424             }
425             if (argconvmask & (1<<i))
426             {
427                 SEGPTR ptr = VA_ARG16( valist, SEGPTR );
428                 if (args) args[aix] = (DWORD)MapSL(ptr);
429                 if (TRACE_ON(thunk)) DPRINTF("%08lx(%p),",ptr,MapSL(ptr));
430             }
431             else
432             {
433                 DWORD arg = VA_ARG16( valist, DWORD );
434                 if (args) args[aix] = arg;
435                 if (TRACE_ON(thunk)) DPRINTF("%ld,", arg);
436             }
437     }
438     if (TRACE_ON(thunk)) DPRINTF("])\n");
439     VA_END16( valist );
440
441     /*
442      * FIXME:  If ( nrofargs & CPEX_DEST_CDECL ) != 0, we should call a
443      *         32-bit CDECL routine ...
444      */
445
446     if (!proc32) ret = 0;
447     else switch (nrofargs)
448     {
449     case 0: ret = proc32();
450             break;
451     case 1: ret = proc32(args[0]);
452             break;
453     case 2: ret = proc32(args[0],args[1]);
454             break;
455     case 3: ret = proc32(args[0],args[1],args[2]);
456             break;
457     case 4: ret = proc32(args[0],args[1],args[2],args[3]);
458             break;
459     case 5: ret = proc32(args[0],args[1],args[2],args[3],args[4]);
460             break;
461     case 6: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5]);
462             break;
463     case 7: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
464             break;
465     case 8: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
466             break;
467     case 9: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
468             break;
469     case 10:ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
470             break;
471     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]);
472             break;
473     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]);
474             break;
475     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]);
476             break;
477     default:
478             /* FIXME: should go up to 32  arguments */
479             ERR("Unsupported number of arguments %ld, please report.\n",nrofargs);
480             ret = 0;
481             break;
482     }
483
484     /* POP nrofargs DWORD arguments and 3 DWORD parameters */
485     if (!Ex) stack16_pop( (3 + nrofargs) * sizeof(DWORD) );
486
487     TRACE("returns %08lx\n",ret);
488     HeapFree( GetProcessHeap(), 0, args );
489
490     RestoreThunkLock( mutex_count );
491     return ret;
492 }
493
494 /**********************************************************************
495  *           CallProc32W           (KERNEL.517)
496  *
497  * DWORD PASCAL CallProc32W( DWORD p1, ... , DWORD lpProcAddress,
498  *                           DWORD fAddressConvert, DWORD cParams );
499  */
500 DWORD WINAPI CallProc32W16( void )
501 {
502     return WOW_CallProc32W16( FALSE );
503 }
504
505 /**********************************************************************
506  *           _CallProcEx32W         (KERNEL.518)
507  *
508  * DWORD CallProcEx32W( DWORD cParams, DWORD fAddressConvert,
509  *                      DWORD lpProcAddress, DWORD p1, ... );
510  */
511 DWORD WINAPI CallProcEx32W16( void )
512 {
513     return WOW_CallProc32W16( TRUE );
514 }
515
516
517 /**********************************************************************
518  *           WOW16Call               (KERNEL.500)
519  *
520  * FIXME!!!
521  *
522  */
523 DWORD WINAPI WOW16Call(WORD x,WORD y,WORD z)
524 {
525         int     i;
526         DWORD   calladdr;
527         VA_LIST16 args;
528         FIXME("(0x%04x,0x%04x,%d),calling (",x,y,z);
529
530         VA_START16(args);
531         for (i=0;i<x/2;i++) {
532                 WORD    a = VA_ARG16(args,WORD);
533                 DPRINTF("%04x ",a);
534         }
535         calladdr = VA_ARG16(args,DWORD);
536         VA_END16(args);
537         stack16_pop( x + sizeof(DWORD) );
538         DPRINTF(") calling address was 0x%08lx\n",calladdr);
539         return 0;
540 }