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