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