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