Don't build d3d8 if we don't have OpenGL support.
[wine] / memory / environ.c
1 /*
2  * Process environment management
3  *
4  * Copyright 1996, 1998 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "windef.h"
28 #include "winerror.h"
29
30 #include "wine/winbase16.h"
31 #include "wine/server.h"
32 #include "wine/library.h"
33 #include "heap.h"
34 #include "winternl.h"
35 #include "selectors.h"
36
37 /* Win32 process environment database */
38 typedef struct _ENVDB
39 {
40     LPSTR            env;              /* 00 Process environment strings */
41     DWORD            unknown1;         /* 04 Unknown */
42     LPSTR            cmd_line;         /* 08 Command line */
43     LPSTR            cur_dir;          /* 0c Current directory */
44     STARTUPINFOA    *startup_info;     /* 10 Startup information */
45     HANDLE           hStdin;           /* 14 Handle for standard input */
46     HANDLE           hStdout;          /* 18 Handle for standard output */
47     HANDLE           hStderr;          /* 1c Handle for standard error */
48     DWORD            unknown2;         /* 20 Unknown */
49     DWORD            inherit_console;  /* 24 Inherit console flag */
50     DWORD            break_type;       /* 28 Console events flag */
51     void            *break_sem;        /* 2c SetConsoleCtrlHandler semaphore */
52     void            *break_event;      /* 30 SetConsoleCtrlHandler event */
53     void            *break_thread;     /* 34 SetConsoleCtrlHandler thread */
54     void            *break_handlers;   /* 38 List of console handlers */
55 } ENVDB;
56
57
58 /* Format of an environment block:
59  * ASCIIZ   string 1 (xx=yy format)
60  * ...
61  * ASCIIZ   string n
62  * BYTE     0
63  * WORD     1
64  * ASCIIZ   program name (e.g. C:\WINDOWS\SYSTEM\KRNL386.EXE)
65  *
66  * Notes:
67  * - contrary to Microsoft docs, the environment strings do not appear
68  *   to be sorted on Win95 (although they are on NT); so we don't bother
69  *   to sort them either.
70  */
71
72 static const char ENV_program_name[] = "C:\\WINDOWS\\SYSTEM\\KRNL386.EXE";
73
74 /* Maximum length of a Win16 environment string (including NULL) */
75 #define MAX_WIN16_LEN  128
76
77 STARTUPINFOA current_startupinfo =
78 {
79     sizeof(STARTUPINFOA),    /* cb */
80     0,                       /* lpReserved */
81     0,                       /* lpDesktop */
82     0,                       /* lpTitle */
83     0,                       /* dwX */
84     0,                       /* dwY */
85     0,                       /* dwXSize */
86     0,                       /* dwYSize */
87     0,                       /* dwXCountChars */
88     0,                       /* dwYCountChars */
89     0,                       /* dwFillAttribute */
90     0,                       /* dwFlags */
91     0,                       /* wShowWindow */
92     0,                       /* cbReserved2 */
93     0,                       /* lpReserved2 */
94     0,                       /* hStdInput */
95     0,                       /* hStdOutput */
96     0                        /* hStdError */
97 };
98
99 ENVDB current_envdb =
100 {
101     0,                       /* environ */
102     0,                       /* unknown1 */
103     0,                       /* cmd_line */
104     0,                       /* cur_dir */
105     &current_startupinfo,    /* startup_info */
106     0,                       /* hStdin */
107     0,                       /* hStdout */
108     0,                       /* hStderr */
109     0,                       /* unknown2 */
110     0,                       /* inherit_console */
111     0,                       /* break_type */
112     0,                       /* break_sem */
113     0,                       /* break_event */
114     0,                       /* break_thread */
115     0                        /* break_handlers */
116 };
117
118
119 static WCHAR *cmdlineW;  /* Unicode command line */
120 static WORD env_sel;     /* selector to the environment */
121
122 /***********************************************************************
123  *           ENV_FindVariable
124  *
125  * Find a variable in the environment and return a pointer to the value.
126  * Helper function for GetEnvironmentVariable and ExpandEnvironmentStrings.
127  */
128 static LPCSTR ENV_FindVariable( LPCSTR env, LPCSTR name, INT len )
129 {
130     while (*env)
131     {
132         if (!strncasecmp( name, env, len ) && (env[len] == '='))
133             return env + len + 1;
134         env += strlen(env) + 1;
135     }
136     return NULL;
137 }
138
139
140 /***********************************************************************
141  *           build_environment
142  *
143  * Build the environment for the initial process
144  */
145 static BOOL build_environment(void)
146 {
147     extern char **environ;
148     static const WORD one = 1;
149     LPSTR p, *e;
150     int size;
151
152     /* Compute the total size of the Unix environment */
153
154     size = sizeof(BYTE) + sizeof(WORD) + sizeof(ENV_program_name);
155     for (e = environ; *e; e++) size += strlen(*e) + 1;
156
157     /* Now allocate the environment */
158
159     if (!(p = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
160     current_envdb.env = p;
161     env_sel = SELECTOR_AllocBlock( p, 0x10000, WINE_LDT_FLAGS_DATA );
162
163     /* And fill it with the Unix environment */
164
165     for (e = environ; *e; e++)
166     {
167         strcpy( p, *e );
168         p += strlen(p) + 1;
169     }
170
171     /* Now add the program name */
172
173     *p++ = 0;
174     memcpy( p, &one, sizeof(WORD) );
175     strcpy( p + sizeof(WORD), ENV_program_name );
176     return TRUE;
177 }
178
179
180 /***********************************************************************
181  *           copy_str
182  *
183  * Small helper for ENV_InitStartupInfo.
184  */
185 inline static char *copy_str( char **dst, const char **src, size_t len )
186 {
187     char *ret;
188
189     if (!len) return NULL;
190     ret = *dst;
191     memcpy( ret, *src, len );
192     ret[len] = 0;
193     *dst += len + 1;
194     *src += len;
195     return ret;
196 }
197
198
199 /***********************************************************************
200  *           ENV_InitStartupInfo
201  *
202  * Fill the startup info structure from the server.
203  */
204 ENVDB *ENV_InitStartupInfo( size_t info_size, char *main_exe_name, size_t main_exe_size )
205 {
206     startup_info_t info;
207     void *data;
208     char *dst;
209     const char *src;
210     size_t len;
211
212     if (!build_environment()) return NULL;
213     if (!info_size) return &current_envdb;  /* nothing to retrieve */
214
215     if (!(data = HeapAlloc( GetProcessHeap(), 0, info_size ))) return NULL;
216
217     SERVER_START_REQ( get_startup_info )
218     {
219         wine_server_set_reply( req, data, info_size );
220         wine_server_call( req );
221         info_size = wine_server_reply_size( reply );
222     }
223     SERVER_END_REQ;
224     if (info_size < sizeof(info.size)) goto done;
225     len = min( info_size, ((startup_info_t *)data)->size );
226     memset( &info, 0, sizeof(info) );
227     memcpy( &info, data, len );
228     src = (char *)data + len;
229     info_size -= len;
230
231     /* fixup the lengths */
232     if (info.filename_len > info_size) info.filename_len = info_size;
233     info_size -= info.filename_len;
234     if (info.cmdline_len > info_size) info.cmdline_len = info_size;
235     info_size -= info.cmdline_len;
236     if (info.desktop_len > info_size) info.desktop_len = info_size;
237     info_size -= info.desktop_len;
238     if (info.title_len > info_size) info.title_len = info_size;
239
240     /* store the filename */
241     if (info.filename_len)
242     {
243         len = min( info.filename_len, main_exe_size-1 );
244         memcpy( main_exe_name, src, len );
245         main_exe_name[len] = 0;
246         src += info.filename_len;
247     }
248
249     /* copy the other strings */
250     len = info.cmdline_len + info.desktop_len + info.title_len;
251     if (len && (dst = HeapAlloc( GetProcessHeap(), 0, len + 3 )))
252     {
253         current_envdb.cmd_line = copy_str( &dst, &src, info.cmdline_len );
254         current_startupinfo.lpDesktop = copy_str( &dst, &src, info.desktop_len );
255         current_startupinfo.lpTitle = copy_str( &dst, &src, info.title_len );
256     }
257
258     current_startupinfo.dwX             = info.x;
259     current_startupinfo.dwY             = info.y;
260     current_startupinfo.dwXSize         = info.cx;
261     current_startupinfo.dwYSize         = info.cy;
262     current_startupinfo.dwXCountChars   = info.x_chars;
263     current_startupinfo.dwYCountChars   = info.y_chars;
264     current_startupinfo.dwFillAttribute = info.attribute;
265     current_startupinfo.wShowWindow     = info.cmd_show;
266     current_startupinfo.dwFlags         = info.flags;
267  done:
268     HeapFree( GetProcessHeap(), 0, data );
269     return &current_envdb;
270 }
271
272
273
274 /***********************************************************************
275  *              set_library_argv
276  *
277  * Set the Wine library argc/argv global variables.
278  */
279 static void set_library_argv( char **argv )
280 {
281     int argc;
282     WCHAR *p;
283     WCHAR **wargv;
284     DWORD total = 0;
285
286     for (argc = 0; argv[argc]; argc++)
287         total += MultiByteToWideChar( CP_ACP, 0, argv[argc], -1, NULL, 0 );
288
289     wargv = HeapAlloc( GetProcessHeap(), 0,
290                        total * sizeof(WCHAR) + (argc + 1) * sizeof(*wargv) );
291     p = (WCHAR *)(wargv + argc + 1);
292     for (argc = 0; argv[argc]; argc++)
293     {
294         DWORD len = MultiByteToWideChar( CP_ACP, 0, argv[argc], -1, p, total );
295         wargv[argc] = p;
296         p += len;
297         total -= len;
298     }
299     wargv[argc] = NULL;
300
301     __wine_main_argc  = argc;
302     __wine_main_argv  = argv;
303     __wine_main_wargv = wargv;
304 }
305
306
307 /***********************************************************************
308  *           ENV_BuildCommandLine
309  *
310  * Build the command line of a process from the argv array.
311  *
312  * Note that it does NOT necessarily include the file name.
313  * Sometimes we don't even have any command line options at all.
314  *
315  * We must quote and escape characters so that the argv array can be rebuilt
316  * from the command line:
317  * - spaces and tabs must be quoted
318  *   'a b'   -> '"a b"'
319  * - quotes must be escaped
320  *   '"'     -> '\"'
321  * - if '\'s are followed by a '"', they must be doubled and followed by '\"',
322  *   resulting in an odd number of '\' followed by a '"'
323  *   '\"'    -> '\\\"'
324  *   '\\"'   -> '\\\\\"'
325  * - '\'s that are not followed by a '"' can be left as is
326  *   'a\b'   == 'a\b'
327  *   'a\\b'  == 'a\\b'
328  */
329 BOOL ENV_BuildCommandLine( char **argv )
330 {
331     int len;
332     char *p, **arg;
333
334     set_library_argv( argv );
335
336     if (current_envdb.cmd_line) goto done;  /* already got it from the server */
337
338     len = 0;
339     for (arg = argv; *arg; arg++)
340     {
341         int has_space,bcount;
342         char* a;
343
344         has_space=0;
345         bcount=0;
346         a=*arg;
347         while (*a!='\0') {
348             if (*a=='\\') {
349                 bcount++;
350             } else {
351                 if (*a==' ' || *a=='\t') {
352                     has_space=1;
353                 } else if (*a=='"') {
354                     /* doubling of '\' preceeding a '"',
355                      * plus escaping of said '"'
356                      */
357                     len+=2*bcount+1;
358                 }
359                 bcount=0;
360             }
361             a++;
362         }
363         len+=(a-*arg)+1 /* for the separating space */;
364         if (has_space)
365             len+=2; /* for the quotes */
366     }
367
368     if (!(current_envdb.cmd_line = HeapAlloc( GetProcessHeap(), 0, len )))
369         return FALSE;
370
371     p = current_envdb.cmd_line;
372     for (arg = argv; *arg; arg++)
373     {
374         int has_space,has_quote;
375         char* a;
376
377         /* Check for quotes and spaces in this argument */
378         has_space=has_quote=0;
379         a=*arg;
380         while (*a!='\0') {
381             if (*a==' ' || *a=='\t') {
382                 has_space=1;
383                 if (has_quote)
384                     break;
385             } else if (*a=='"') {
386                 has_quote=1;
387                 if (has_space)
388                     break;
389             }
390             a++;
391         }
392
393         /* Now transfer it to the command line */
394         if (has_space)
395             *p++='"';
396         if (has_quote) {
397             int bcount;
398             char* a;
399
400             bcount=0;
401             a=*arg;
402             while (*a!='\0') {
403                 if (*a=='\\') {
404                     *p++=*a;
405                     bcount++;
406                 } else {
407                     if (*a=='"') {
408                         int i;
409
410                         /* Double all the '\\' preceeding this '"', plus one */
411                         for (i=0;i<=bcount;i++)
412                             *p++='\\';
413                         *p++='"';
414                     } else {
415                         *p++=*a;
416                     }
417                     bcount=0;
418                 }
419                 a++;
420             }
421         } else {
422             strcpy(p,*arg);
423             p+=strlen(*arg);
424         }
425         if (has_space)
426             *p++='"';
427         *p++=' ';
428     }
429     if (p > current_envdb.cmd_line)
430         p--;  /* remove last space */
431     *p = '\0';
432
433     /* now allocate the Unicode version */
434  done:
435     len = MultiByteToWideChar( CP_ACP, 0, current_envdb.cmd_line, -1, NULL, 0 );
436     if (!(cmdlineW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
437         return FALSE;
438     MultiByteToWideChar( CP_ACP, 0, current_envdb.cmd_line, -1, cmdlineW, len );
439     return TRUE;
440 }
441
442
443 /***********************************************************************
444  *           GetCommandLineA      (KERNEL32.@)
445  *
446  * WARNING: there's a Windows incompatibility lurking here !
447  * Win32s always includes the full path of the program file,
448  * whereas Windows NT only returns the full file path plus arguments
449  * in case the program has been started with a full path.
450  * Win9x seems to have inherited NT behaviour.
451  *
452  * Note that both Start Menu Execute and Explorer start programs with
453  * fully specified quoted app file paths, which is why probably the only case
454  * where you'll see single file names is in case of direct launch
455  * via CreateProcess or WinExec.
456  *
457  * Perhaps we should take care of Win3.1 programs here (Win32s "feature").
458  *
459  * References: MS KB article q102762.txt (special Win32s handling)
460  */
461 LPSTR WINAPI GetCommandLineA(void)
462 {
463     return current_envdb.cmd_line;
464 }
465
466 /***********************************************************************
467  *           GetCommandLineW      (KERNEL32.@)
468  */
469 LPWSTR WINAPI GetCommandLineW(void)
470 {
471     return cmdlineW;
472 }
473
474
475 /***********************************************************************
476  *           GetEnvironmentStrings    (KERNEL32.@)
477  *           GetEnvironmentStringsA   (KERNEL32.@)
478  */
479 LPSTR WINAPI GetEnvironmentStringsA(void)
480 {
481     return current_envdb.env;
482 }
483
484
485 /***********************************************************************
486  *           GetEnvironmentStringsW   (KERNEL32.@)
487  */
488 LPWSTR WINAPI GetEnvironmentStringsW(void)
489 {
490     INT size;
491     LPWSTR ret;
492
493     RtlAcquirePebLock();
494     size = HeapSize( GetProcessHeap(), 0, current_envdb.env );
495     if ((ret = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) )) != NULL)
496     {
497         LPSTR pA = current_envdb.env;
498         LPWSTR pW = ret;
499         while (size--) *pW++ = (WCHAR)(BYTE)*pA++;
500     }
501     RtlReleasePebLock();
502     return ret;
503 }
504
505
506 /***********************************************************************
507  *           FreeEnvironmentStringsA   (KERNEL32.@)
508  */
509 BOOL WINAPI FreeEnvironmentStringsA( LPSTR ptr )
510 {
511     if (ptr != current_envdb.env)
512     {
513         SetLastError( ERROR_INVALID_PARAMETER );
514         return FALSE;
515     }
516     return TRUE;
517 }
518
519
520 /***********************************************************************
521  *           FreeEnvironmentStringsW   (KERNEL32.@)
522  */
523 BOOL WINAPI FreeEnvironmentStringsW( LPWSTR ptr )
524 {
525     return HeapFree( GetProcessHeap(), 0, ptr );
526 }
527
528
529 /***********************************************************************
530  *           GetEnvironmentVariableA   (KERNEL32.@)
531  */
532 DWORD WINAPI GetEnvironmentVariableA( LPCSTR name, LPSTR value, DWORD size )
533 {
534     LPCSTR p;
535     INT ret = 0;
536
537     if (!name || !*name)
538     {
539         SetLastError( ERROR_ENVVAR_NOT_FOUND );
540         return 0;
541     }
542
543     RtlAcquirePebLock();
544     if ((p = ENV_FindVariable( current_envdb.env, name, strlen(name) )))
545     {
546         ret = strlen(p);
547         if (size <= ret)
548         {
549             /* If not enough room, include the terminating null
550              * in the returned size */
551             ret++;
552         }
553         else if (value) strcpy( value, p );
554     }
555     RtlReleasePebLock();
556     if (!ret)
557         SetLastError( ERROR_ENVVAR_NOT_FOUND );
558     return ret;
559 }
560
561
562 /***********************************************************************
563  *           GetEnvironmentVariableW   (KERNEL32.@)
564  */
565 DWORD WINAPI GetEnvironmentVariableW( LPCWSTR nameW, LPWSTR valW, DWORD size)
566 {
567     LPSTR name, val;
568     DWORD ret;
569
570     if (!nameW || !*nameW)
571     {
572         SetLastError( ERROR_ENVVAR_NOT_FOUND );
573         return 0;
574     }
575
576     name = HEAP_strdupWtoA( GetProcessHeap(), 0, nameW );
577     val  = valW ? HeapAlloc( GetProcessHeap(), 0, size ) : NULL;
578     ret  = GetEnvironmentVariableA( name, val, size );
579     if (ret && val)
580     {
581         if (size && !MultiByteToWideChar( CP_ACP, 0, val, -1, valW, size ))
582             valW[size-1] = 0;
583     }
584     HeapFree( GetProcessHeap(), 0, name );
585     if (val) HeapFree( GetProcessHeap(), 0, val );
586     return ret;
587 }
588
589
590 /***********************************************************************
591  *           SetEnvironmentVariableA   (KERNEL32.@)
592  */
593 BOOL WINAPI SetEnvironmentVariableA( LPCSTR name, LPCSTR value )
594 {
595     INT old_size, len, res;
596     LPSTR p, env, new_env;
597     BOOL ret = FALSE;
598
599     if (!name || !*name)
600     {
601         SetLastError( ERROR_INVALID_PARAMETER );
602         return FALSE;
603     }
604
605     RtlAcquirePebLock();
606     env = p = current_envdb.env;
607
608     /* Find a place to insert the string */
609
610     res = -1;
611     len = strlen(name);
612     while (*p)
613     {
614         if (!strncasecmp( name, p, len ) && (p[len] == '=')) break;
615         p += strlen(p) + 1;
616     }
617     if (!value && !*p) goto done;  /* Value to remove doesn't exist */
618
619     /* Realloc the buffer */
620
621     len = value ? strlen(name) + strlen(value) + 2 : 0;
622     if (*p) len -= strlen(p) + 1;  /* The name already exists */
623     old_size = HeapSize( GetProcessHeap(), 0, env );
624     if (len < 0)
625     {
626         LPSTR next = p + strlen(p) + 1;  /* We know there is a next one */
627         memmove( next + len, next, old_size - (next - env) );
628     }
629     if (!(new_env = HeapReAlloc( GetProcessHeap(), 0, env, old_size + len )))
630         goto done;
631     if (env_sel) env_sel = SELECTOR_ReallocBlock( env_sel, new_env, old_size + len );
632     p = new_env + (p - env);
633     if (len > 0) memmove( p + len, p, old_size - (p - new_env) );
634
635     /* Set the new string */
636
637     if (value)
638     {
639         strcpy( p, name );
640         strcat( p, "=" );
641         strcat( p, value );
642     }
643     current_envdb.env = new_env;
644     ret = TRUE;
645
646 done:
647     RtlReleasePebLock();
648     return ret;
649 }
650
651
652 /***********************************************************************
653  *           SetEnvironmentVariableW   (KERNEL32.@)
654  */
655 BOOL WINAPI SetEnvironmentVariableW( LPCWSTR name, LPCWSTR value )
656 {
657     LPSTR nameA  = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
658     LPSTR valueA = HEAP_strdupWtoA( GetProcessHeap(), 0, value );
659     BOOL ret = SetEnvironmentVariableA( nameA, valueA );
660     HeapFree( GetProcessHeap(), 0, nameA );
661     HeapFree( GetProcessHeap(), 0, valueA );
662     return ret;
663 }
664
665
666 /***********************************************************************
667  *           ExpandEnvironmentStringsA   (KERNEL32.@)
668  *
669  * Note: overlapping buffers are not supported; this is how it should be.
670  */
671 DWORD WINAPI ExpandEnvironmentStringsA( LPCSTR src, LPSTR dst, DWORD count )
672 {
673     DWORD len, total_size = 1;  /* 1 for terminating '\0' */
674     LPCSTR p, var;
675
676     if (!count) dst = NULL;
677     RtlAcquirePebLock();
678
679     while (*src)
680     {
681         if (*src != '%')
682         {
683             if ((p = strchr( src, '%' ))) len = p - src;
684             else len = strlen(src);
685             var = src;
686             src += len;
687         }
688         else  /* we are at the start of a variable */
689         {
690             if ((p = strchr( src + 1, '%' )))
691             {
692                 len = p - src - 1;  /* Length of the variable name */
693                 if ((var = ENV_FindVariable( current_envdb.env, src + 1, len )))
694                 {
695                     src += len + 2;  /* Skip the variable name */
696                     len = strlen(var);
697                 }
698                 else
699                 {
700                     var = src;  /* Copy original name instead */
701                     len += 2;
702                     src += len;
703                 }
704             }
705             else  /* unfinished variable name, ignore it */
706             {
707                 var = src;
708                 len = strlen(src);  /* Copy whole string */
709                 src += len;
710             }
711         }
712         total_size += len;
713         if (dst)
714         {
715             if (count < len) len = count;
716             memcpy( dst, var, len );
717             dst += len;
718             count -= len;
719         }
720     }
721     RtlReleasePebLock();
722
723     /* Null-terminate the string */
724     if (dst)
725     {
726         if (!count) dst--;
727         *dst = '\0';
728     }
729     return total_size;
730 }
731
732
733 /***********************************************************************
734  *           ExpandEnvironmentStringsW   (KERNEL32.@)
735  */
736 DWORD WINAPI ExpandEnvironmentStringsW( LPCWSTR src, LPWSTR dst, DWORD len )
737 {
738     LPSTR srcA = HEAP_strdupWtoA( GetProcessHeap(), 0, src );
739     LPSTR dstA = dst ? HeapAlloc( GetProcessHeap(), 0, len ) : NULL;
740     DWORD ret  = ExpandEnvironmentStringsA( srcA, dstA, len );
741     if (dstA)
742     {
743         ret = MultiByteToWideChar( CP_ACP, 0, dstA, -1, dst, len );
744         HeapFree( GetProcessHeap(), 0, dstA );
745     }
746     HeapFree( GetProcessHeap(), 0, srcA );
747     return ret;
748 }
749
750
751 /***********************************************************************
752  *           GetDOSEnvironment     (KERNEL.131)
753  */
754 SEGPTR WINAPI GetDOSEnvironment16(void)
755 {
756     return MAKESEGPTR( env_sel, 0 );
757 }
758
759
760 /***********************************************************************
761  *           GetStdHandle    (KERNEL32.@)
762  */
763 HANDLE WINAPI GetStdHandle( DWORD std_handle )
764 {
765     switch(std_handle)
766     {
767         case STD_INPUT_HANDLE:  return current_envdb.hStdin;
768         case STD_OUTPUT_HANDLE: return current_envdb.hStdout;
769         case STD_ERROR_HANDLE:  return current_envdb.hStderr;
770     }
771     SetLastError( ERROR_INVALID_PARAMETER );
772     return INVALID_HANDLE_VALUE;
773 }
774
775
776 /***********************************************************************
777  *           SetStdHandle    (KERNEL32.@)
778  */
779 BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
780 {
781     switch(std_handle)
782     {
783         case STD_INPUT_HANDLE:  current_envdb.hStdin = handle;  return TRUE;
784         case STD_OUTPUT_HANDLE: current_envdb.hStdout = handle; return TRUE;
785         case STD_ERROR_HANDLE:  current_envdb.hStderr = handle; return TRUE;
786     }
787     SetLastError( ERROR_INVALID_PARAMETER );
788     return FALSE;
789 }
790
791
792 /***********************************************************************
793  *              GetStartupInfoA         (KERNEL32.@)
794  */
795 VOID WINAPI GetStartupInfoA( LPSTARTUPINFOA info )
796 {
797     *info = current_startupinfo;
798 }
799
800
801 /***********************************************************************
802  *              GetStartupInfoW         (KERNEL32.@)
803  */
804 VOID WINAPI GetStartupInfoW( LPSTARTUPINFOW info )
805 {
806     info->cb              = sizeof(STARTUPINFOW);
807     info->dwX             = current_startupinfo.dwX;
808     info->dwY             = current_startupinfo.dwY;
809     info->dwXSize         = current_startupinfo.dwXSize;
810     info->dwXCountChars   = current_startupinfo.dwXCountChars;
811     info->dwYCountChars   = current_startupinfo.dwYCountChars;
812     info->dwFillAttribute = current_startupinfo.dwFillAttribute;
813     info->dwFlags         = current_startupinfo.dwFlags;
814     info->wShowWindow     = current_startupinfo.wShowWindow;
815     info->cbReserved2     = current_startupinfo.cbReserved2;
816     info->lpReserved2     = current_startupinfo.lpReserved2;
817     info->hStdInput       = current_startupinfo.hStdInput;
818     info->hStdOutput      = current_startupinfo.hStdOutput;
819     info->hStdError       = current_startupinfo.hStdError;
820     info->lpReserved = HEAP_strdupAtoW (GetProcessHeap(), 0, current_startupinfo.lpReserved );
821     info->lpDesktop  = HEAP_strdupAtoW (GetProcessHeap(), 0, current_startupinfo.lpDesktop );
822     info->lpTitle    = HEAP_strdupAtoW (GetProcessHeap(), 0, current_startupinfo.lpTitle );
823 }