msvcrt: NULL terminate program arguments list in __getmainargs.
[wine] / dlls / krnl386.exe16 / kernel.c
1 /*
2  * 16-bit kernel initialization code
3  *
4  * Copyright 2000 Alexandre Julliard
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define WINE_NO_INLINE_STRING
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winternl.h"
28 #include "wownt32.h"
29 #include "wine/winuser16.h"
30
31 #include "kernel16_private.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(module);
35
36 extern DWORD WINAPI GetProcessFlags( DWORD processid );
37
38 static DWORD process_dword;
39
40 /***********************************************************************
41  *           KERNEL thread initialisation routine
42  */
43 static void thread_attach(void)
44 {
45     /* allocate the 16-bit stack (FIXME: should be done lazily) */
46     HGLOBAL16 hstack = WOWGlobalAlloc16( GMEM_FIXED, 0x10000 );
47     kernel_get_thread_data()->stack_sel = GlobalHandleToSel16( hstack );
48     NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR( kernel_get_thread_data()->stack_sel,
49                                                         0x10000 - sizeof(STACK16FRAME) );
50     memset( (char *)GlobalLock16(hstack) + 0x10000 - sizeof(STACK16FRAME), 0, sizeof(STACK16FRAME) );
51 }
52
53
54 /***********************************************************************
55  *           KERNEL thread finalisation routine
56  */
57 static void thread_detach(void)
58 {
59     /* free the 16-bit stack */
60     WOWGlobalFree16( kernel_get_thread_data()->stack_sel );
61     NtCurrentTeb()->WOW32Reserved = 0;
62     if (NtCurrentTeb()->Tib.SubSystemTib) TASK_ExitTask();
63 }
64
65
66 /**************************************************************************
67  *              DllMain
68  */
69 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
70 {
71     switch(reason)
72     {
73     case DLL_PROCESS_ATTACH:
74         LoadLibrary16( "krnl386.exe" );
75         /* fall through */
76     case DLL_THREAD_ATTACH:
77         thread_attach();
78         break;
79     case DLL_THREAD_DETACH:
80         thread_detach();
81         break;
82     }
83     return TRUE;
84 }
85
86
87 /**************************************************************************
88  *              DllEntryPoint   (KERNEL.669)
89  */
90 BOOL WINAPI KERNEL_DllEntryPoint( DWORD reasion, HINSTANCE16 inst, WORD ds,
91                                   WORD heap, DWORD reserved1, WORD reserved2 )
92 {
93     static int done;
94
95     /* the entry point can be called multiple times */
96     if (done) return TRUE;
97     done = 1;
98
99     /* create the shared heap for broken win95 native dlls */
100     HeapCreate( HEAP_SHARED, 0, 0 );
101
102     /* setup emulation of protected instructions from 32-bit code */
103     if (GetVersion() & 0x80000000) RtlAddVectoredExceptionHandler( TRUE, INSTR_vectored_handler );
104
105     /* Initialize 16-bit thunking entry points */
106     if (!WOWTHUNK_Init()) return FALSE;
107
108     /* Initialize DOS memory */
109     if (!DOSMEM_Init()) return FALSE;
110
111     /* Initialize special KERNEL entry points */
112
113     NE_SetEntryPoint( inst, 178, GetWinFlags16() );
114
115     NE_SetEntryPoint( inst, 454, wine_get_cs() );
116     NE_SetEntryPoint( inst, 455, wine_get_ds() );
117
118     NE_SetEntryPoint( inst, 183, DOSMEM_0000H );       /* KERNEL.183: __0000H */
119     NE_SetEntryPoint( inst, 173, DOSMEM_BiosSysSeg );  /* KERNEL.173: __ROMBIOS */
120     NE_SetEntryPoint( inst, 193, DOSMEM_BiosDataSeg ); /* KERNEL.193: __0040H */
121     NE_SetEntryPoint( inst, 194, DOSMEM_BiosSysSeg );  /* KERNEL.194: __F000H */
122
123     /* Initialize KERNEL.THHOOK */
124     TASK_InstallTHHook(MapSL((SEGPTR)GetProcAddress16( inst, (LPCSTR)332 )));
125     TASK_CreateMainTask();
126
127     /* Initialize the real-mode selector entry points */
128 #define SET_ENTRY_POINT( num, addr ) \
129     NE_SetEntryPoint( inst, (num), GLOBAL_CreateBlock( GMEM_FIXED, \
130                       DOSMEM_MapDosToLinear(addr), 0x10000, inst, \
131                       WINE_LDT_FLAGS_DATA ))
132
133     SET_ENTRY_POINT( 174, 0xa0000 );  /* KERNEL.174: __A000H */
134     SET_ENTRY_POINT( 181, 0xb0000 );  /* KERNEL.181: __B000H */
135     SET_ENTRY_POINT( 182, 0xb8000 );  /* KERNEL.182: __B800H */
136     SET_ENTRY_POINT( 195, 0xc0000 );  /* KERNEL.195: __C000H */
137     SET_ENTRY_POINT( 179, 0xd0000 );  /* KERNEL.179: __D000H */
138     SET_ENTRY_POINT( 190, 0xe0000 );  /* KERNEL.190: __E000H */
139 #undef SET_ENTRY_POINT
140
141     /* Force loading of some dlls */
142     LoadLibrary16( "system.drv" );
143     LoadLibrary16( "comm.drv" );
144
145     return TRUE;
146 }
147
148 /***********************************************************************
149  *         GetVersion   (KERNEL.3)
150  */
151 DWORD WINAPI GetVersion16(void)
152 {
153     static WORD dosver, winver;
154
155     if (!dosver)  /* not determined yet */
156     {
157         RTL_OSVERSIONINFOEXW info;
158
159         info.dwOSVersionInfoSize = sizeof(info);
160         if (RtlGetVersion( &info )) return 0;
161
162         if (info.dwMajorVersion <= 3)
163             winver = MAKEWORD( info.dwMajorVersion, info.dwMinorVersion );
164         else
165             winver = MAKEWORD( 3, 95 );
166
167         switch(info.dwPlatformId)
168         {
169         case VER_PLATFORM_WIN32s:
170             switch(MAKELONG( info.dwMinorVersion, info.dwMajorVersion ))
171             {
172             case 0x0200:
173                 dosver = 0x0303;  /* DOS 3.3 for Windows 2.0 */
174                 break;
175             case 0x0300:
176                 dosver = 0x0500;  /* DOS 5.0 for Windows 3.0 */
177                 break;
178             default:
179                 dosver = 0x0616;  /* DOS 6.22 for Windows 3.1 and later */
180                 break;
181             }
182             break;
183         case VER_PLATFORM_WIN32_WINDOWS:
184             /* DOS 8.0 for WinME, 7.0 for Win95/98 */
185             if (info.dwMinorVersion >= 90) dosver = 0x0800;
186             else dosver = 0x0700;
187             break;
188         case VER_PLATFORM_WIN32_NT:
189             dosver = 0x0500;  /* always DOS 5.0 for NT */
190             break;
191         }
192         TRACE( "DOS %d.%02d Win %d.%02d\n",
193                HIBYTE(dosver), LOBYTE(dosver), LOBYTE(winver), HIBYTE(winver) );
194     }
195     return MAKELONG( winver, dosver );
196 }
197
198 /***********************************************************************
199  *              Reserved1 (KERNEL.77)
200  */
201 SEGPTR WINAPI KERNEL_AnsiNext16(SEGPTR current)
202 {
203     return (*(char *)MapSL(current)) ? current + 1 : current;
204 }
205
206 /***********************************************************************
207  *              Reserved2(KERNEL.78)
208  */
209 SEGPTR WINAPI KERNEL_AnsiPrev16( SEGPTR start, SEGPTR current )
210 {
211     return (current==start)?start:current-1;
212 }
213
214 /***********************************************************************
215  *              Reserved3 (KERNEL.79)
216  */
217 SEGPTR WINAPI KERNEL_AnsiUpper16( SEGPTR strOrChar )
218 {
219     /* uppercase only one char if strOrChar < 0x10000 */
220     if (HIWORD(strOrChar))
221     {
222         char *s = MapSL(strOrChar);
223         while (*s)
224         {
225             *s = toupper(*s);
226             s++;
227         }
228         return strOrChar;
229     }
230     else return toupper((char)strOrChar);
231 }
232
233 /***********************************************************************
234  *              Reserved4 (KERNEL.80)
235  */
236 SEGPTR WINAPI KERNEL_AnsiLower16( SEGPTR strOrChar )
237 {
238     /* lowercase only one char if strOrChar < 0x10000 */
239     if (HIWORD(strOrChar))
240     {
241         char *s = MapSL(strOrChar);
242         while (*s)
243         {
244             *s = tolower(*s);
245             s++;
246         }
247         return strOrChar;
248     }
249     else return tolower((char)strOrChar);
250 }
251
252 /***********************************************************************
253  *              Reserved5 (KERNEL.87)
254  */
255 INT16 WINAPI KERNEL_lstrcmp16( LPCSTR str1, LPCSTR str2 )
256 {
257     int ret = strcmp( str1, str2 );
258
259     /* Looks too complicated, but in optimized strcpy we might get
260      * a 32bit wide difference and would truncate it to 16 bit, so
261      * erroneously returning equality. */
262     if (ret < 0) return -1;
263     if (ret > 0) return  1;
264     return 0;
265 }
266
267 /***********************************************************************
268  *           lstrcpy   (KERNEL.88)
269  */
270 SEGPTR WINAPI lstrcpy16( SEGPTR dst, LPCSTR src )
271 {
272     if (!lstrcpyA( MapSL(dst), src )) dst = 0;
273     return dst;
274 }
275
276 /***********************************************************************
277  *           lstrcat   (KERNEL.89)
278  */
279 SEGPTR WINAPI lstrcat16( SEGPTR dst, LPCSTR src )
280 {
281     /* Windows does not check for NULL pointers here, so we don't either */
282     strcat( MapSL(dst), src );
283     return dst;
284 }
285
286 /***********************************************************************
287  *           lstrlen   (KERNEL.90)
288  */
289 INT16 WINAPI lstrlen16( LPCSTR str )
290 {
291     return (INT16)lstrlenA( str );
292 }
293
294 /***********************************************************************
295  *           OutputDebugString   (KERNEL.115)
296  */
297 void WINAPI OutputDebugString16( LPCSTR str )
298 {
299     OutputDebugStringA( str );
300 }
301
302 /***********************************************************************
303  *          GetWinFlags   (KERNEL.132)
304  */
305 DWORD WINAPI GetWinFlags16(void)
306 {
307     static const long cpuflags[5] = { WF_CPU086, WF_CPU186, WF_CPU286, WF_CPU386, WF_CPU486 };
308     SYSTEM_INFO si;
309     OSVERSIONINFOA ovi;
310     DWORD result;
311
312     GetSystemInfo(&si);
313
314     /* There doesn't seem to be any Pentium flag.  */
315     result = cpuflags[min(si.wProcessorLevel, 4)] | WF_ENHANCED | WF_PMODE | WF_80x87 | WF_PAGING;
316     if (si.wProcessorLevel >= 4) result |= WF_HASCPUID;
317     ovi.dwOSVersionInfoSize = sizeof(ovi);
318     GetVersionExA(&ovi);
319     if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
320         result |= WF_WIN32WOW; /* undocumented WF_WINNT */
321     return result;
322 }
323
324 /***********************************************************************
325  *         GetVersionEx   (KERNEL.149)
326  */
327 BOOL16 WINAPI GetVersionEx16(OSVERSIONINFO16 *v)
328 {
329     OSVERSIONINFOA info;
330
331     if (v->dwOSVersionInfoSize < sizeof(OSVERSIONINFO16))
332     {
333         WARN("wrong OSVERSIONINFO size from app\n");
334         return FALSE;
335     }
336
337     info.dwOSVersionInfoSize = sizeof(info);
338     if (!GetVersionExA( &info )) return FALSE;
339
340     v->dwMajorVersion = info.dwMajorVersion;
341     v->dwMinorVersion = info.dwMinorVersion;
342     v->dwBuildNumber  = info.dwBuildNumber;
343     v->dwPlatformId   = info.dwPlatformId;
344     strcpy( v->szCSDVersion, info.szCSDVersion );
345     return TRUE;
346 }
347
348 /***********************************************************************
349  *           DebugBreak   (KERNEL.203)
350  */
351 void WINAPI DebugBreak16( CONTEXT *context )
352 {
353     EXCEPTION_RECORD rec;
354
355     rec.ExceptionCode    = EXCEPTION_BREAKPOINT;
356     rec.ExceptionFlags   = 0;
357     rec.ExceptionRecord  = NULL;
358     rec.ExceptionAddress = (LPVOID)context->Eip;
359     rec.NumberParameters = 0;
360     NtRaiseException( &rec, context, TRUE );
361 }
362
363 /***********************************************************************
364  *           K329                    (KERNEL.329)
365  *
366  * TODO:
367  * Should fill lpBuffer only if DBO_BUFFERFILL has been set by SetWinDebugInfo()
368  */
369 void WINAPI DebugFillBuffer(LPSTR lpBuffer, WORD wBytes)
370 {
371     memset(lpBuffer, 0xf9 /* DBGFILL_BUFFER */, wBytes);
372 }
373
374 /***********************************************************************
375  *           DiagQuery                          (KERNEL.339)
376  *
377  * returns TRUE if Win called with "/b" (bootlog.txt)
378  */
379 BOOL16 WINAPI DiagQuery16(void)
380 {
381     return FALSE;
382 }
383
384 /***********************************************************************
385  *           DiagOutput                         (KERNEL.340)
386  *
387  * writes a debug string into <windir>\bootlog.txt
388  */
389 void WINAPI DiagOutput16(LPCSTR str)
390 {
391     /* FIXME */
392     TRACE("DIAGOUTPUT:%s\n", debugstr_a(str));
393 }
394
395 /***********************************************************************
396  *           hmemcpy   (KERNEL.348)
397  */
398 void WINAPI hmemcpy16( LPVOID dst, LPCVOID src, LONG count )
399 {
400     memcpy( dst, src, count );
401 }
402
403 /***********************************************************************
404  *           lstrcpyn   (KERNEL.353)
405  */
406 SEGPTR WINAPI lstrcpyn16( SEGPTR dst, LPCSTR src, INT16 n )
407 {
408     if (!lstrcpynA( MapSL(dst), src, n )) return 0;
409     return dst;
410 }
411
412 /***********************************************************************
413  *           lstrcatn   (KERNEL.352)
414  */
415 SEGPTR WINAPI lstrcatn16( SEGPTR dst, LPCSTR src, INT16 n )
416 {
417     LPSTR p = MapSL(dst);
418     LPSTR start = p;
419
420     while (*p) p++;
421     if ((n -= (p - start)) <= 0) return dst;
422     lstrcpynA( p, src, n );
423     return dst;
424 }
425
426 #if 0  /* Not used at this time. This is here for documentation only */
427
428 /* WINDEBUGINFO flags values */
429 #define WDI_OPTIONS         0x0001
430 #define WDI_FILTER          0x0002
431 #define WDI_ALLOCBREAK      0x0004
432
433 /* dwOptions values */
434 #define DBO_CHECKHEAP       0x0001
435 #define DBO_BUFFERFILL      0x0004
436 #define DBO_DISABLEGPTRAPPING 0x0010
437 #define DBO_CHECKFREE       0x0020
438
439 #define DBO_SILENT          0x8000
440
441 #define DBO_TRACEBREAK      0x2000
442 #define DBO_WARNINGBREAK    0x1000
443 #define DBO_NOERRORBREAK    0x0800
444 #define DBO_NOFATALBREAK    0x0400
445 #define DBO_INT3BREAK       0x0100
446
447 /* DebugOutput flags values */
448 #define DBF_TRACE           0x0000
449 #define DBF_WARNING         0x4000
450 #define DBF_ERROR           0x8000
451 #define DBF_FATAL           0xc000
452
453 /* dwFilter values */
454 #define DBF_KERNEL          0x1000
455 #define DBF_KRN_MEMMAN      0x0001
456 #define DBF_KRN_LOADMODULE  0x0002
457 #define DBF_KRN_SEGMENTLOAD 0x0004
458 #define DBF_USER            0x0800
459 #define DBF_GDI             0x0400
460 #define DBF_MMSYSTEM        0x0040
461 #define DBF_PENWIN          0x0020
462 #define DBF_APPLICATION     0x0008
463 #define DBF_DRIVER          0x0010
464
465 #endif /* NOLOGERROR */
466
467 /***********************************************************************
468  *          GetWinDebugInfo   (KERNEL.355)
469  */
470 BOOL16 WINAPI GetWinDebugInfo16(WINDEBUGINFO16 *lpwdi, UINT16 flags)
471 {
472     FIXME("(%8lx,%d): stub returning 0\n",
473           (unsigned long)lpwdi, flags);
474     /* 0 means not in debugging mode/version */
475     /* Can this type of debugging be used in wine ? */
476     /* Constants: WDI_OPTIONS WDI_FILTER WDI_ALLOCBREAK */
477     return 0;
478 }
479
480 /***********************************************************************
481  *          SetWinDebugInfo   (KERNEL.356)
482  */
483 BOOL16 WINAPI SetWinDebugInfo16(WINDEBUGINFO16 *lpwdi)
484 {
485     FIXME("(%8lx): stub returning 0\n", (unsigned long)lpwdi);
486     /* 0 means not in debugging mode/version */
487     /* Can this type of debugging be used in wine ? */
488     /* Constants: WDI_OPTIONS WDI_FILTER WDI_ALLOCBREAK */
489     return 0;
490 }
491
492 /***********************************************************************
493  *           UnicodeToAnsi   (KERNEL.434)
494  */
495 INT16 WINAPI UnicodeToAnsi16( LPCWSTR src, LPSTR dst, INT16 codepage )
496 {
497     if ( codepage == -1 ) codepage = CP_ACP;
498     return WideCharToMultiByte( codepage, 0, src, -1, dst, 0x7fffffff, NULL, NULL );
499 }
500
501 /***********************************************************************
502  *       VWin32_EventCreate     (KERNEL.442)
503  */
504 HANDLE WINAPI VWin32_EventCreate(VOID)
505 {
506     HANDLE hEvent = CreateEventW( NULL, FALSE, 0, NULL );
507     return ConvertToGlobalHandle( hEvent );
508 }
509
510 /***********************************************************************
511  *       VWin32_EventDestroy    (KERNEL.443)
512  */
513 VOID WINAPI VWin32_EventDestroy(HANDLE event)
514 {
515     CloseHandle( event );
516 }
517
518 /***********************************************************************
519  *       VWin32_EventWait       (KERNEL.450)
520  */
521 VOID WINAPI VWin32_EventWait(HANDLE event)
522 {
523     DWORD mutex_count;
524
525     ReleaseThunkLock( &mutex_count );
526     WaitForSingleObject( event, INFINITE );
527     RestoreThunkLock( mutex_count );
528 }
529
530 /***********************************************************************
531  *       VWin32_EventSet        (KERNEL.451)
532  *       KERNEL_479             (KERNEL.479)
533  */
534 VOID WINAPI VWin32_EventSet(HANDLE event)
535 {
536     SetEvent( event );
537 }
538
539 /***********************************************************************
540  *           GetProcAddress32                   (KERNEL.453)
541  */
542 FARPROC WINAPI GetProcAddress32_16( HMODULE hModule, LPCSTR function )
543 {
544     /* FIXME: we used to disable snoop when returning proc for Win16 subsystem */
545     return GetProcAddress( hModule, function );
546 }
547
548 /***********************************************************************
549  *           CreateW32Event    (KERNEL.457)
550  */
551 HANDLE WINAPI CreateW32Event( BOOL manual_reset, BOOL initial_state )
552 {
553     return CreateEventW( NULL, manual_reset, initial_state, NULL );
554 }
555
556 /***********************************************************************
557  *           SetW32Event (KERNEL.458)
558  */
559 BOOL WINAPI SetW32Event( HANDLE handle )
560 {
561     return SetEvent( handle );
562 }
563
564 /***********************************************************************
565  *           ResetW32Event (KERNEL.459)
566  */
567 BOOL WINAPI ResetW32Event( HANDLE handle )
568 {
569     return ResetEvent( handle );
570 }
571
572 /***********************************************************************
573  *           WaitForSingleObject   (KERNEL.460)
574  */
575 DWORD WINAPI WaitForSingleObject16( HANDLE handle, DWORD timeout )
576 {
577     DWORD retval, mutex_count;
578
579     ReleaseThunkLock( &mutex_count );
580     retval = WaitForSingleObject( handle, timeout );
581     RestoreThunkLock( mutex_count );
582     return retval;
583 }
584
585 /***********************************************************************
586  *           WaitForMultipleObjects   (KERNEL.461)
587  */
588 DWORD WINAPI WaitForMultipleObjects16( DWORD count, const HANDLE *handles,
589                                        BOOL wait_all, DWORD timeout )
590 {
591     DWORD retval, mutex_count;
592
593     ReleaseThunkLock( &mutex_count );
594     retval = WaitForMultipleObjectsEx( count, handles, wait_all, timeout, FALSE );
595     RestoreThunkLock( mutex_count );
596     return retval;
597 }
598
599 /***********************************************************************
600  *              GetCurrentThreadId (KERNEL.462)
601  */
602 DWORD WINAPI GetCurrentThreadId16(void)
603 {
604     return GetCurrentThreadId();
605 }
606
607 /***********************************************************************
608  *           ExitProcess   (KERNEL.466)
609  */
610 void WINAPI ExitProcess16( WORD status )
611 {
612     DWORD count;
613     ReleaseThunkLock( &count );
614     ExitProcess( status );
615 }
616
617 /***********************************************************************
618  *              GetCurrentProcessId (KERNEL.471)
619  */
620 DWORD WINAPI GetCurrentProcessId16(void)
621 {
622     return GetCurrentProcessId();
623 }
624
625 /*********************************************************************
626  *           CloseW32Handle (KERNEL.474)
627  */
628 BOOL WINAPI CloseW32Handle( HANDLE handle )
629 {
630     return CloseHandle( handle );
631 }
632
633 /***********************************************************************
634  *           ConvertToGlobalHandle   (KERNEL.476)
635  */
636 HANDLE WINAPI ConvertToGlobalHandle16( HANDLE handle )
637 {
638     return ConvertToGlobalHandle( handle );
639 }
640
641 /*********************************************************************
642  *           MapProcessHandle   (KERNEL.483)
643  */
644 DWORD WINAPI MapProcessHandle( HANDLE hProcess )
645 {
646     return GetProcessId( hProcess );
647 }
648
649 /***********************************************************************
650  *           SetProcessDword    (KERNEL.484)
651  * 'Of course you cannot directly access Windows internal structures'
652  */
653 void WINAPI SetProcessDword( DWORD dwProcessID, INT offset, DWORD value )
654 {
655     TRACE("(%d, %d)\n", dwProcessID, offset );
656
657     if (dwProcessID && dwProcessID != GetCurrentProcessId())
658     {
659         ERR("%d: process %x not accessible\n", offset, dwProcessID);
660         return;
661     }
662
663     switch ( offset )
664     {
665     case GPD_APP_COMPAT_FLAGS:
666     case GPD_LOAD_DONE_EVENT:
667     case GPD_HINSTANCE16:
668     case GPD_WINDOWS_VERSION:
669     case GPD_THDB:
670     case GPD_PDB:
671     case GPD_STARTF_SHELLDATA:
672     case GPD_STARTF_HOTKEY:
673     case GPD_STARTF_SHOWWINDOW:
674     case GPD_STARTF_SIZE:
675     case GPD_STARTF_POSITION:
676     case GPD_STARTF_FLAGS:
677     case GPD_PARENT:
678     case GPD_FLAGS:
679         ERR("Not allowed to modify offset %d\n", offset );
680         break;
681     case GPD_USERDATA:
682         process_dword = value;
683         break;
684     default:
685         ERR("Unknown offset %d\n", offset );
686         break;
687     }
688 }
689
690 /***********************************************************************
691  *           GetProcessDword    (KERNEL.485)
692  * 'Of course you cannot directly access Windows internal structures'
693  */
694 DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset )
695 {
696     DWORD               x, y;
697     STARTUPINFOW        siw;
698
699     TRACE("(%d, %d)\n", dwProcessID, offset );
700
701     if (dwProcessID && dwProcessID != GetCurrentProcessId())
702     {
703         ERR("%d: process %x not accessible\n", offset, dwProcessID);
704         return 0;
705     }
706
707     switch ( offset )
708     {
709     case GPD_APP_COMPAT_FLAGS:
710         return GetAppCompatFlags16(0);
711     case GPD_LOAD_DONE_EVENT:
712         return 0;
713     case GPD_HINSTANCE16:
714         return GetTaskDS16();
715     case GPD_WINDOWS_VERSION:
716         return GetExeVersion16();
717     case GPD_THDB:
718         return (DWORD_PTR)NtCurrentTeb() - 0x10 /* FIXME */;
719     case GPD_PDB:
720         return (DWORD_PTR)NtCurrentTeb()->Peb; /* FIXME: truncating a pointer */
721     case GPD_STARTF_SHELLDATA: /* return stdoutput handle from startupinfo ??? */
722         GetStartupInfoW(&siw);
723         return HandleToULong(siw.hStdOutput);
724     case GPD_STARTF_HOTKEY: /* return stdinput handle from startupinfo ??? */
725         GetStartupInfoW(&siw);
726         return HandleToULong(siw.hStdInput);
727     case GPD_STARTF_SHOWWINDOW:
728         GetStartupInfoW(&siw);
729         return siw.wShowWindow;
730     case GPD_STARTF_SIZE:
731         GetStartupInfoW(&siw);
732         x = siw.dwXSize;
733         if ( (INT)x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
734         y = siw.dwYSize;
735         if ( (INT)y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
736         return MAKELONG( x, y );
737     case GPD_STARTF_POSITION:
738         GetStartupInfoW(&siw);
739         x = siw.dwX;
740         if ( (INT)x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
741         y = siw.dwY;
742         if ( (INT)y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
743         return MAKELONG( x, y );
744     case GPD_STARTF_FLAGS:
745         GetStartupInfoW(&siw);
746         return siw.dwFlags;
747     case GPD_PARENT:
748         return 0;
749     case GPD_FLAGS:
750         return GetProcessFlags(0);
751     case GPD_USERDATA:
752         return process_dword;
753     default:
754         ERR("Unknown offset %d\n", offset );
755         return 0;
756     }
757 }
758
759 /***********************************************************************
760  *           FreeLibrary32 (KERNEL.486)
761  */
762 BOOL WINAPI FreeLibrary32_16( HINSTANCE module )
763 {
764     return FreeLibrary( module );
765 }
766
767 /***********************************************************************
768  *              GetModuleFileName32     (KERNEL.487)
769  */
770 DWORD WINAPI GetModuleFileName32_16( HMODULE module, LPSTR buffer, DWORD size )
771 {
772     return GetModuleFileNameA( module, buffer, size );
773 }
774
775 /***********************************************************************
776  *              GetModuleHandle32        (KERNEL.488)
777  */
778 HMODULE WINAPI GetModuleHandle32_16(LPCSTR module)
779 {
780     return GetModuleHandleA( module );
781 }
782
783 /***********************************************************************
784  *              RegisterServiceProcess (KERNEL.491)
785  */
786 DWORD WINAPI RegisterServiceProcess16( DWORD dwProcessId, DWORD dwType )
787 {
788     return 1; /* success */
789 }
790
791 /***********************************************************************
792  *           WaitForMultipleObjectsEx   (KERNEL.495)
793  */
794 DWORD WINAPI WaitForMultipleObjectsEx16( DWORD count, const HANDLE *handles,
795                                          BOOL wait_all, DWORD timeout, BOOL alertable )
796 {
797     DWORD retval, mutex_count;
798
799     ReleaseThunkLock( &mutex_count );
800     retval = WaitForMultipleObjectsEx( count, handles, wait_all, timeout, alertable );
801     RestoreThunkLock( mutex_count );
802     return retval;
803 }
804
805 /**********************************************************************
806  * VWin32_BoostThreadGroup   (KERNEL.535)
807  */
808 VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT boost )
809 {
810     FIXME("(0x%08x,%d): stub\n", threadId, boost);
811 }
812
813
814 /**********************************************************************
815  * VWin32_BoostThreadStatic   (KERNEL.536)
816  */
817 VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
818 {
819     FIXME("(0x%08x,%d): stub\n", threadId, boost);
820 }
821
822 /***********************************************************************
823  *              EnableDos (KERNEL.41)
824  *              DisableDos (KERNEL.42)
825  *              GetLastDiskChange (KERNEL.98)
826  *              ValidateCodeSegments (KERNEL.100)
827  *              KbdRst (KERNEL.123)
828  *              EnableKernel (KERNEL.124)
829  *              DisableKernel (KERNEL.125)
830  *              ValidateFreeSpaces (KERNEL.200)
831  *              K237 (KERNEL.237)
832  *              BUNNY_351 (KERNEL.351)
833  *              PIGLET_361 (KERNEL.361)
834  *
835  * Entry point for kernel functions that do nothing.
836  */
837 LONG WINAPI KERNEL_nop(void)
838 {
839     return 0;
840 }
841
842 /***********************************************************************
843  *           ToolHelpHook                             (KERNEL.341)
844  *      see "Undocumented Windows"
845  */
846 FARPROC16 WINAPI ToolHelpHook16(FARPROC16 func)
847 {
848     static FARPROC16 hook;
849
850     FIXME("(%p), stub.\n", func);
851     return InterlockedExchangePointer( (void **)&hook, func );
852 }
853
854 /* thunk for 16-bit CreateThread */
855 struct thread_args
856 {
857     FARPROC16 proc;
858     DWORD     param;
859 };
860
861 static DWORD CALLBACK start_thread16( LPVOID threadArgs )
862 {
863     struct thread_args args = *(struct thread_args *)threadArgs;
864     HeapFree( GetProcessHeap(), 0, threadArgs );
865     return K32WOWCallback16( (DWORD)args.proc, args.param );
866 }
867
868 /***********************************************************************
869  *           CreateThread16   (KERNEL.441)
870  */
871 HANDLE WINAPI CreateThread16( SECURITY_ATTRIBUTES *sa, DWORD stack,
872                               FARPROC16 start, SEGPTR param,
873                               DWORD flags, LPDWORD id )
874 {
875     struct thread_args *args = HeapAlloc( GetProcessHeap(), 0, sizeof(*args) );
876     if (!args) return INVALID_HANDLE_VALUE;
877     args->proc = start;
878     args->param = param;
879     return CreateThread( sa, stack, start_thread16, args, flags, id );
880 }
881
882 /***********************************************************************
883  *           _DebugOutput                    (KERNEL.328)
884  */
885 void WINAPIV _DebugOutput( WORD flags, LPCSTR spec, VA_LIST16 valist )
886 {
887     char caller[101];
888
889     /* Decode caller address */
890     if (!GetModuleName16( GetExePtr(CURRENT_STACK16->cs), caller, sizeof(caller) ))
891         sprintf( caller, "%04X:%04X", CURRENT_STACK16->cs, CURRENT_STACK16->ip );
892
893     /* FIXME: cannot use wvsnprintf16 from kernel */
894     /* wvsnprintf16( temp, sizeof(temp), spec, valist ); */
895
896     /* Output */
897     FIXME("%s %04x %s\n", caller, flags, debugstr_a(spec) );
898 }