krnl386.exe: Remove 16 suffix on Get/SetProcessDword since there's no 32-bit version.
[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     return (INT16)strcmp( str1, str2 );
258 }
259
260 /***********************************************************************
261  *           lstrcpy   (KERNEL.88)
262  */
263 SEGPTR WINAPI lstrcpy16( SEGPTR dst, LPCSTR src )
264 {
265     if (!lstrcpyA( MapSL(dst), src )) dst = 0;
266     return dst;
267 }
268
269 /***********************************************************************
270  *           lstrcat   (KERNEL.89)
271  */
272 SEGPTR WINAPI lstrcat16( SEGPTR dst, LPCSTR src )
273 {
274     /* Windows does not check for NULL pointers here, so we don't either */
275     strcat( MapSL(dst), src );
276     return dst;
277 }
278
279 /***********************************************************************
280  *           lstrlen   (KERNEL.90)
281  */
282 INT16 WINAPI lstrlen16( LPCSTR str )
283 {
284     return (INT16)lstrlenA( str );
285 }
286
287 /***********************************************************************
288  *           OutputDebugString   (KERNEL.115)
289  */
290 void WINAPI OutputDebugString16( LPCSTR str )
291 {
292     OutputDebugStringA( str );
293 }
294
295 /***********************************************************************
296  *          GetWinFlags   (KERNEL.132)
297  */
298 DWORD WINAPI GetWinFlags16(void)
299 {
300     static const long cpuflags[5] = { WF_CPU086, WF_CPU186, WF_CPU286, WF_CPU386, WF_CPU486 };
301     SYSTEM_INFO si;
302     OSVERSIONINFOA ovi;
303     DWORD result;
304
305     GetSystemInfo(&si);
306
307     /* There doesn't seem to be any Pentium flag.  */
308     result = cpuflags[min(si.wProcessorLevel, 4)] | WF_ENHANCED | WF_PMODE | WF_80x87 | WF_PAGING;
309     if (si.wProcessorLevel >= 4) result |= WF_HASCPUID;
310     ovi.dwOSVersionInfoSize = sizeof(ovi);
311     GetVersionExA(&ovi);
312     if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
313         result |= WF_WIN32WOW; /* undocumented WF_WINNT */
314     return result;
315 }
316
317 /***********************************************************************
318  *         GetVersionEx   (KERNEL.149)
319  */
320 BOOL16 WINAPI GetVersionEx16(OSVERSIONINFO16 *v)
321 {
322     OSVERSIONINFOA info;
323
324     if (v->dwOSVersionInfoSize < sizeof(OSVERSIONINFO16))
325     {
326         WARN("wrong OSVERSIONINFO size from app\n");
327         return FALSE;
328     }
329
330     info.dwOSVersionInfoSize = sizeof(info);
331     if (!GetVersionExA( &info )) return FALSE;
332
333     v->dwMajorVersion = info.dwMajorVersion;
334     v->dwMinorVersion = info.dwMinorVersion;
335     v->dwBuildNumber  = info.dwBuildNumber;
336     v->dwPlatformId   = info.dwPlatformId;
337     strcpy( v->szCSDVersion, info.szCSDVersion );
338     return TRUE;
339 }
340
341 /***********************************************************************
342  *           DebugBreak   (KERNEL.203)
343  */
344 void WINAPI DebugBreak16( CONTEXT *context )
345 {
346     EXCEPTION_RECORD rec;
347
348     rec.ExceptionCode    = EXCEPTION_BREAKPOINT;
349     rec.ExceptionFlags   = 0;
350     rec.ExceptionRecord  = NULL;
351     rec.ExceptionAddress = (LPVOID)context->Eip;
352     rec.NumberParameters = 0;
353     NtRaiseException( &rec, context, TRUE );
354 }
355
356 /***********************************************************************
357  *           K329                    (KERNEL.329)
358  *
359  * TODO:
360  * Should fill lpBuffer only if DBO_BUFFERFILL has been set by SetWinDebugInfo()
361  */
362 void WINAPI DebugFillBuffer(LPSTR lpBuffer, WORD wBytes)
363 {
364     memset(lpBuffer, 0xf9 /* DBGFILL_BUFFER */, wBytes);
365 }
366
367 /***********************************************************************
368  *           DiagQuery                          (KERNEL.339)
369  *
370  * returns TRUE if Win called with "/b" (bootlog.txt)
371  */
372 BOOL16 WINAPI DiagQuery16(void)
373 {
374     return FALSE;
375 }
376
377 /***********************************************************************
378  *           DiagOutput                         (KERNEL.340)
379  *
380  * writes a debug string into <windir>\bootlog.txt
381  */
382 void WINAPI DiagOutput16(LPCSTR str)
383 {
384     /* FIXME */
385     TRACE("DIAGOUTPUT:%s\n", debugstr_a(str));
386 }
387
388 /***********************************************************************
389  *           hmemcpy   (KERNEL.348)
390  */
391 void WINAPI hmemcpy16( LPVOID dst, LPCVOID src, LONG count )
392 {
393     memcpy( dst, src, count );
394 }
395
396 /***********************************************************************
397  *           lstrcpyn   (KERNEL.353)
398  */
399 SEGPTR WINAPI lstrcpyn16( SEGPTR dst, LPCSTR src, INT16 n )
400 {
401     if (!lstrcpynA( MapSL(dst), src, n )) return 0;
402     return dst;
403 }
404
405 /***********************************************************************
406  *           lstrcatn   (KERNEL.352)
407  */
408 SEGPTR WINAPI lstrcatn16( SEGPTR dst, LPCSTR src, INT16 n )
409 {
410     LPSTR p = MapSL(dst);
411     LPSTR start = p;
412
413     while (*p) p++;
414     if ((n -= (p - start)) <= 0) return dst;
415     lstrcpynA( p, src, n );
416     return dst;
417 }
418
419 #if 0  /* Not used at this time. This is here for documentation only */
420
421 /* WINDEBUGINFO flags values */
422 #define WDI_OPTIONS         0x0001
423 #define WDI_FILTER          0x0002
424 #define WDI_ALLOCBREAK      0x0004
425
426 /* dwOptions values */
427 #define DBO_CHECKHEAP       0x0001
428 #define DBO_BUFFERFILL      0x0004
429 #define DBO_DISABLEGPTRAPPING 0x0010
430 #define DBO_CHECKFREE       0x0020
431
432 #define DBO_SILENT          0x8000
433
434 #define DBO_TRACEBREAK      0x2000
435 #define DBO_WARNINGBREAK    0x1000
436 #define DBO_NOERRORBREAK    0x0800
437 #define DBO_NOFATALBREAK    0x0400
438 #define DBO_INT3BREAK       0x0100
439
440 /* DebugOutput flags values */
441 #define DBF_TRACE           0x0000
442 #define DBF_WARNING         0x4000
443 #define DBF_ERROR           0x8000
444 #define DBF_FATAL           0xc000
445
446 /* dwFilter values */
447 #define DBF_KERNEL          0x1000
448 #define DBF_KRN_MEMMAN      0x0001
449 #define DBF_KRN_LOADMODULE  0x0002
450 #define DBF_KRN_SEGMENTLOAD 0x0004
451 #define DBF_USER            0x0800
452 #define DBF_GDI             0x0400
453 #define DBF_MMSYSTEM        0x0040
454 #define DBF_PENWIN          0x0020
455 #define DBF_APPLICATION     0x0008
456 #define DBF_DRIVER          0x0010
457
458 #endif /* NOLOGERROR */
459
460 /***********************************************************************
461  *          GetWinDebugInfo   (KERNEL.355)
462  */
463 BOOL16 WINAPI GetWinDebugInfo16(WINDEBUGINFO16 *lpwdi, UINT16 flags)
464 {
465     FIXME("(%8lx,%d): stub returning 0\n",
466           (unsigned long)lpwdi, flags);
467     /* 0 means not in debugging mode/version */
468     /* Can this type of debugging be used in wine ? */
469     /* Constants: WDI_OPTIONS WDI_FILTER WDI_ALLOCBREAK */
470     return 0;
471 }
472
473 /***********************************************************************
474  *          SetWinDebugInfo   (KERNEL.356)
475  */
476 BOOL16 WINAPI SetWinDebugInfo16(WINDEBUGINFO16 *lpwdi)
477 {
478     FIXME("(%8lx): stub returning 0\n", (unsigned long)lpwdi);
479     /* 0 means not in debugging mode/version */
480     /* Can this type of debugging be used in wine ? */
481     /* Constants: WDI_OPTIONS WDI_FILTER WDI_ALLOCBREAK */
482     return 0;
483 }
484
485 /***********************************************************************
486  *           UnicodeToAnsi   (KERNEL.434)
487  */
488 INT16 WINAPI UnicodeToAnsi16( LPCWSTR src, LPSTR dst, INT16 codepage )
489 {
490     if ( codepage == -1 ) codepage = CP_ACP;
491     return WideCharToMultiByte( codepage, 0, src, -1, dst, 0x7fffffff, NULL, NULL );
492 }
493
494 /***********************************************************************
495  *       VWin32_EventCreate     (KERNEL.442)
496  */
497 HANDLE WINAPI VWin32_EventCreate(VOID)
498 {
499     HANDLE hEvent = CreateEventW( NULL, FALSE, 0, NULL );
500     return ConvertToGlobalHandle( hEvent );
501 }
502
503 /***********************************************************************
504  *       VWin32_EventDestroy    (KERNEL.443)
505  */
506 VOID WINAPI VWin32_EventDestroy(HANDLE event)
507 {
508     CloseHandle( event );
509 }
510
511 /***********************************************************************
512  *       VWin32_EventWait       (KERNEL.450)
513  */
514 VOID WINAPI VWin32_EventWait(HANDLE event)
515 {
516     DWORD mutex_count;
517
518     ReleaseThunkLock( &mutex_count );
519     WaitForSingleObject( event, INFINITE );
520     RestoreThunkLock( mutex_count );
521 }
522
523 /***********************************************************************
524  *       VWin32_EventSet        (KERNEL.451)
525  *       KERNEL_479             (KERNEL.479)
526  */
527 VOID WINAPI VWin32_EventSet(HANDLE event)
528 {
529     SetEvent( event );
530 }
531
532 /***********************************************************************
533  *           GetProcAddress32                   (KERNEL.453)
534  */
535 FARPROC WINAPI GetProcAddress32_16( HMODULE hModule, LPCSTR function )
536 {
537     /* FIXME: we used to disable snoop when returning proc for Win16 subsystem */
538     return GetProcAddress( hModule, function );
539 }
540
541 /***********************************************************************
542  *           CreateW32Event    (KERNEL.457)
543  */
544 HANDLE WINAPI CreateW32Event( BOOL manual_reset, BOOL initial_state )
545 {
546     return CreateEventW( NULL, manual_reset, initial_state, NULL );
547 }
548
549 /***********************************************************************
550  *           SetW32Event (KERNEL.458)
551  */
552 BOOL WINAPI SetW32Event( HANDLE handle )
553 {
554     return SetEvent( handle );
555 }
556
557 /***********************************************************************
558  *           ResetW32Event (KERNEL.459)
559  */
560 BOOL WINAPI ResetW32Event( HANDLE handle )
561 {
562     return ResetEvent( handle );
563 }
564
565 /***********************************************************************
566  *           WaitForSingleObject   (KERNEL.460)
567  */
568 DWORD WINAPI WaitForSingleObject16( HANDLE handle, DWORD timeout )
569 {
570     DWORD retval, mutex_count;
571
572     ReleaseThunkLock( &mutex_count );
573     retval = WaitForSingleObject( handle, timeout );
574     RestoreThunkLock( mutex_count );
575     return retval;
576 }
577
578 /***********************************************************************
579  *           WaitForMultipleObjects   (KERNEL.461)
580  */
581 DWORD WINAPI WaitForMultipleObjects16( DWORD count, const HANDLE *handles,
582                                        BOOL wait_all, DWORD timeout )
583 {
584     DWORD retval, mutex_count;
585
586     ReleaseThunkLock( &mutex_count );
587     retval = WaitForMultipleObjectsEx( count, handles, wait_all, timeout, FALSE );
588     RestoreThunkLock( mutex_count );
589     return retval;
590 }
591
592 /***********************************************************************
593  *              GetCurrentThreadId (KERNEL.462)
594  */
595 DWORD WINAPI GetCurrentThreadId16(void)
596 {
597     return GetCurrentThreadId();
598 }
599
600 /***********************************************************************
601  *           ExitProcess   (KERNEL.466)
602  */
603 void WINAPI ExitProcess16( WORD status )
604 {
605     DWORD count;
606     ReleaseThunkLock( &count );
607     ExitProcess( status );
608 }
609
610 /***********************************************************************
611  *              GetCurrentProcessId (KERNEL.471)
612  */
613 DWORD WINAPI GetCurrentProcessId16(void)
614 {
615     return GetCurrentProcessId();
616 }
617
618 /*********************************************************************
619  *           CloseW32Handle (KERNEL.474)
620  */
621 BOOL WINAPI CloseW32Handle( HANDLE handle )
622 {
623     return CloseHandle( handle );
624 }
625
626 /***********************************************************************
627  *           ConvertToGlobalHandle   (KERNEL.476)
628  */
629 HANDLE WINAPI ConvertToGlobalHandle16( HANDLE handle )
630 {
631     return ConvertToGlobalHandle( handle );
632 }
633
634 /*********************************************************************
635  *           MapProcessHandle   (KERNEL.483)
636  */
637 DWORD WINAPI MapProcessHandle( HANDLE hProcess )
638 {
639     return GetProcessId( hProcess );
640 }
641
642 /***********************************************************************
643  *           SetProcessDword    (KERNEL.484)
644  * 'Of course you cannot directly access Windows internal structures'
645  */
646 void WINAPI SetProcessDword( DWORD dwProcessID, INT offset, DWORD value )
647 {
648     TRACE("(%d, %d)\n", dwProcessID, offset );
649
650     if (dwProcessID && dwProcessID != GetCurrentProcessId())
651     {
652         ERR("%d: process %x not accessible\n", offset, dwProcessID);
653         return;
654     }
655
656     switch ( offset )
657     {
658     case GPD_APP_COMPAT_FLAGS:
659     case GPD_LOAD_DONE_EVENT:
660     case GPD_HINSTANCE16:
661     case GPD_WINDOWS_VERSION:
662     case GPD_THDB:
663     case GPD_PDB:
664     case GPD_STARTF_SHELLDATA:
665     case GPD_STARTF_HOTKEY:
666     case GPD_STARTF_SHOWWINDOW:
667     case GPD_STARTF_SIZE:
668     case GPD_STARTF_POSITION:
669     case GPD_STARTF_FLAGS:
670     case GPD_PARENT:
671     case GPD_FLAGS:
672         ERR("Not allowed to modify offset %d\n", offset );
673         break;
674     case GPD_USERDATA:
675         process_dword = value;
676         break;
677     default:
678         ERR("Unknown offset %d\n", offset );
679         break;
680     }
681 }
682
683 /***********************************************************************
684  *           GetProcessDword    (KERNEL.485)
685  * 'Of course you cannot directly access Windows internal structures'
686  */
687 DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset )
688 {
689     DWORD               x, y;
690     STARTUPINFOW        siw;
691
692     TRACE("(%d, %d)\n", dwProcessID, offset );
693
694     if (dwProcessID && dwProcessID != GetCurrentProcessId())
695     {
696         ERR("%d: process %x not accessible\n", offset, dwProcessID);
697         return 0;
698     }
699
700     switch ( offset )
701     {
702     case GPD_APP_COMPAT_FLAGS:
703         return GetAppCompatFlags16(0);
704     case GPD_LOAD_DONE_EVENT:
705         return 0;
706     case GPD_HINSTANCE16:
707         return GetTaskDS16();
708     case GPD_WINDOWS_VERSION:
709         return GetExeVersion16();
710     case GPD_THDB:
711         return (DWORD_PTR)NtCurrentTeb() - 0x10 /* FIXME */;
712     case GPD_PDB:
713         return (DWORD_PTR)NtCurrentTeb()->Peb; /* FIXME: truncating a pointer */
714     case GPD_STARTF_SHELLDATA: /* return stdoutput handle from startupinfo ??? */
715         GetStartupInfoW(&siw);
716         return HandleToULong(siw.hStdOutput);
717     case GPD_STARTF_HOTKEY: /* return stdinput handle from startupinfo ??? */
718         GetStartupInfoW(&siw);
719         return HandleToULong(siw.hStdInput);
720     case GPD_STARTF_SHOWWINDOW:
721         GetStartupInfoW(&siw);
722         return siw.wShowWindow;
723     case GPD_STARTF_SIZE:
724         GetStartupInfoW(&siw);
725         x = siw.dwXSize;
726         if ( (INT)x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
727         y = siw.dwYSize;
728         if ( (INT)y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
729         return MAKELONG( x, y );
730     case GPD_STARTF_POSITION:
731         GetStartupInfoW(&siw);
732         x = siw.dwX;
733         if ( (INT)x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
734         y = siw.dwY;
735         if ( (INT)y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
736         return MAKELONG( x, y );
737     case GPD_STARTF_FLAGS:
738         GetStartupInfoW(&siw);
739         return siw.dwFlags;
740     case GPD_PARENT:
741         return 0;
742     case GPD_FLAGS:
743         return GetProcessFlags(0);
744     case GPD_USERDATA:
745         return process_dword;
746     default:
747         ERR("Unknown offset %d\n", offset );
748         return 0;
749     }
750 }
751
752 /***********************************************************************
753  *           FreeLibrary32 (KERNEL.486)
754  */
755 BOOL WINAPI FreeLibrary32_16( HINSTANCE module )
756 {
757     return FreeLibrary( module );
758 }
759
760 /***********************************************************************
761  *              GetModuleFileName32     (KERNEL.487)
762  */
763 DWORD WINAPI GetModuleFileName32_16( HMODULE module, LPSTR buffer, DWORD size )
764 {
765     return GetModuleFileNameA( module, buffer, size );
766 }
767
768 /***********************************************************************
769  *              GetModuleHandle32        (KERNEL.488)
770  */
771 HMODULE WINAPI GetModuleHandle32_16(LPCSTR module)
772 {
773     return GetModuleHandleA( module );
774 }
775
776 /***********************************************************************
777  *              RegisterServiceProcess (KERNEL.491)
778  */
779 DWORD WINAPI RegisterServiceProcess16( DWORD dwProcessId, DWORD dwType )
780 {
781     return 1; /* success */
782 }
783
784 /***********************************************************************
785  *           WaitForMultipleObjectsEx   (KERNEL.495)
786  */
787 DWORD WINAPI WaitForMultipleObjectsEx16( DWORD count, const HANDLE *handles,
788                                          BOOL wait_all, DWORD timeout, BOOL alertable )
789 {
790     DWORD retval, mutex_count;
791
792     ReleaseThunkLock( &mutex_count );
793     retval = WaitForMultipleObjectsEx( count, handles, wait_all, timeout, alertable );
794     RestoreThunkLock( mutex_count );
795     return retval;
796 }
797
798 /**********************************************************************
799  * VWin32_BoostThreadGroup   (KERNEL.535)
800  */
801 VOID WINAPI VWin32_BoostThreadGroup( DWORD threadId, INT boost )
802 {
803     FIXME("(0x%08x,%d): stub\n", threadId, boost);
804 }
805
806
807 /**********************************************************************
808  * VWin32_BoostThreadStatic   (KERNEL.536)
809  */
810 VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
811 {
812     FIXME("(0x%08x,%d): stub\n", threadId, boost);
813 }
814
815 /***********************************************************************
816  *              EnableDos (KERNEL.41)
817  *              DisableDos (KERNEL.42)
818  *              GetLastDiskChange (KERNEL.98)
819  *              ValidateCodeSegments (KERNEL.100)
820  *              KbdRst (KERNEL.123)
821  *              EnableKernel (KERNEL.124)
822  *              DisableKernel (KERNEL.125)
823  *              ValidateFreeSpaces (KERNEL.200)
824  *              K237 (KERNEL.237)
825  *              BUNNY_351 (KERNEL.351)
826  *              PIGLET_361 (KERNEL.361)
827  *
828  * Entry point for kernel functions that do nothing.
829  */
830 LONG WINAPI KERNEL_nop(void)
831 {
832     return 0;
833 }
834
835 /***********************************************************************
836  *           ToolHelpHook                             (KERNEL.341)
837  *      see "Undocumented Windows"
838  */
839 FARPROC16 WINAPI ToolHelpHook16(FARPROC16 func)
840 {
841     static FARPROC16 hook;
842
843     FIXME("(%p), stub.\n", func);
844     return InterlockedExchangePointer( (void **)&hook, func );
845 }
846
847 /* thunk for 16-bit CreateThread */
848 struct thread_args
849 {
850     FARPROC16 proc;
851     DWORD     param;
852 };
853
854 static DWORD CALLBACK start_thread16( LPVOID threadArgs )
855 {
856     struct thread_args args = *(struct thread_args *)threadArgs;
857     HeapFree( GetProcessHeap(), 0, threadArgs );
858     return K32WOWCallback16( (DWORD)args.proc, args.param );
859 }
860
861 /***********************************************************************
862  *           CreateThread16   (KERNEL.441)
863  */
864 HANDLE WINAPI CreateThread16( SECURITY_ATTRIBUTES *sa, DWORD stack,
865                               FARPROC16 start, SEGPTR param,
866                               DWORD flags, LPDWORD id )
867 {
868     struct thread_args *args = HeapAlloc( GetProcessHeap(), 0, sizeof(*args) );
869     if (!args) return INVALID_HANDLE_VALUE;
870     args->proc = start;
871     args->param = param;
872     return CreateThread( sa, stack, start_thread16, args, flags, id );
873 }
874
875 /***********************************************************************
876  *           _DebugOutput                    (KERNEL.328)
877  */
878 void WINAPIV _DebugOutput( WORD flags, LPCSTR spec, VA_LIST16 valist )
879 {
880     char caller[101];
881
882     /* Decode caller address */
883     if (!GetModuleName16( GetExePtr(CURRENT_STACK16->cs), caller, sizeof(caller) ))
884         sprintf( caller, "%04X:%04X", CURRENT_STACK16->cs, CURRENT_STACK16->ip );
885
886     /* FIXME: cannot use wvsnprintf16 from kernel */
887     /* wvsnprintf16( temp, sizeof(temp), spec, valist ); */
888
889     /* Output */
890     FIXME("%s %04x %s\n", caller, flags, debugstr_a(spec) );
891 }