2 * Process environment management
4 * Copyright 1996, 1998 Alexandre Julliard
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.
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.
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
22 #include "wine/port.h"
34 #include "wine/winbase16.h"
35 #include "wine/server.h"
36 #include "wine/library.h"
39 #include "selectors.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(environ
);
46 * - 16 bit environment ??? (see generate_env_block16 for the details)
49 /* Format of an environment block:
50 * ASCIIZ string 1 (xx=yy format)
55 * ASCIIZ program name (e.g. C:\WINDOWS\SYSTEM\KRNL386.EXE)
58 * - contrary to Microsoft docs, the environment strings do not appear
59 * to be sorted on Win95 (although they are on NT); so we don't bother
60 * to sort them either.
61 * - on Win2K (and likely most of NT versions) the last part (WORD 1 and
62 * program name no longer appear in the environment block (from the 32
66 static const char ENV_program_name
[] = "C:\\WINDOWS\\SYSTEM\\KRNL386.EXE";
68 static STARTUPINFOW startup_infoW
;
69 static STARTUPINFOA startup_infoA
;
71 /* Maximum length of a Win16 environment string (including NULL) */
72 #define MAX_WIN16_LEN 128
74 static WORD env_sel
; /* selector to the 16 bit environment */
76 /******************************************************************
77 * generate_env_block16
79 * This internal function generates a suitable environment for the 16 bit
80 * subsystem and returns the value as a segmented pointer.
82 * FIXME: current implementation will allocate a private copy of the
83 * environment strings, but will not follow the modifications (if any)
84 * from the unicode env block stored in the PEB
85 * => how should this be updated from the ntdll modifications ?
86 * should we use the peb->EnvironmentUpdateCount field to
87 * know when environment has changed ???
88 * we currently regenerate this block each time an environment
89 * variable is modified from a Win32 API call, but we'll miss all
90 * direct access to the NTDLL APIs
92 static SEGPTR
generate_env_block16(void)
99 if (env16
) FreeEnvironmentStringsA( env16
);
101 env16
= GetEnvironmentStringsA();
102 size
= HeapSize(GetProcessHeap(), 0, env16
);
103 new_size
= size
+ sizeof(WORD
) + sizeof(ENV_program_name
);
104 if (!(env16
= HeapReAlloc( GetProcessHeap(), 0, env16
, new_size
))) return 0;
106 memcpy(env16
+ size
, &one
, sizeof(one
));
107 memcpy(env16
+ size
+ sizeof(WORD
), ENV_program_name
, sizeof(ENV_program_name
));
109 env_sel
= SELECTOR_ReallocBlock( env_sel
, env16
, new_size
);
111 env_sel
= SELECTOR_AllocBlock( env16
, 0x10000, WINE_LDT_FLAGS_DATA
);
113 return MAKESEGPTR( env_sel
, 0 );
116 /***********************************************************************
117 * GetCommandLineA (KERNEL32.@)
119 * WARNING: there's a Windows incompatibility lurking here !
120 * Win32s always includes the full path of the program file,
121 * whereas Windows NT only returns the full file path plus arguments
122 * in case the program has been started with a full path.
123 * Win9x seems to have inherited NT behaviour.
125 * Note that both Start Menu Execute and Explorer start programs with
126 * fully specified quoted app file paths, which is why probably the only case
127 * where you'll see single file names is in case of direct launch
128 * via CreateProcess or WinExec.
130 * Perhaps we should take care of Win3.1 programs here (Win32s "feature").
132 * References: MS KB article q102762.txt (special Win32s handling)
134 LPSTR WINAPI
GetCommandLineA(void)
136 static char *cmdlineA
; /* ASCII command line */
138 if (!cmdlineA
) /* make an ansi version if we don't have it */
143 cmdlineA
= (RtlUnicodeStringToAnsiString( &ansi
, &NtCurrentTeb()->Peb
->ProcessParameters
->CommandLine
, TRUE
) == STATUS_SUCCESS
) ?
150 /***********************************************************************
151 * GetCommandLineW (KERNEL32.@)
153 LPWSTR WINAPI
GetCommandLineW(void)
155 return NtCurrentTeb()->Peb
->ProcessParameters
->CommandLine
.Buffer
;
159 /***********************************************************************
160 * GetEnvironmentStrings (KERNEL32.@)
161 * GetEnvironmentStringsA (KERNEL32.@)
163 LPSTR WINAPI
GetEnvironmentStringsA(void)
173 ptrW
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
176 slen
= strlenW(ptrW
) + 1;
177 len
+= WideCharToMultiByte( CP_ACP
, 0, ptrW
, slen
, NULL
, 0, NULL
, NULL
);
181 if ((ret
= HeapAlloc( GetProcessHeap(), 0, len
)) != NULL
)
183 ptrW
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
187 slen
= strlenW(ptrW
) + 1;
188 WideCharToMultiByte( CP_ACP
, 0, ptrW
, slen
, ptrA
, len
, NULL
, NULL
);
190 ptrA
+= strlen(ptrA
) + 1;
200 /***********************************************************************
201 * GetEnvironmentStringsW (KERNEL32.@)
203 LPWSTR WINAPI
GetEnvironmentStringsW(void)
205 return NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
209 /***********************************************************************
210 * FreeEnvironmentStringsA (KERNEL32.@)
212 BOOL WINAPI
FreeEnvironmentStringsA( LPSTR ptr
)
214 return HeapFree( GetProcessHeap(), 0, ptr
);
218 /***********************************************************************
219 * FreeEnvironmentStringsW (KERNEL32.@)
221 BOOL WINAPI
FreeEnvironmentStringsW( LPWSTR ptr
)
227 /***********************************************************************
228 * GetEnvironmentVariableA (KERNEL32.@)
230 DWORD WINAPI
GetEnvironmentVariableA( LPCSTR name
, LPSTR value
, DWORD size
)
232 UNICODE_STRING us_name
;
238 SetLastError(ERROR_ENVVAR_NOT_FOUND
);
242 if (!(valueW
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
))))
245 RtlCreateUnicodeStringFromAsciiz( &us_name
, name
);
247 ret
= GetEnvironmentVariableW( us_name
.Buffer
, valueW
, size
);
248 if (ret
&& ret
< size
)
250 WideCharToMultiByte( CP_ACP
, 0, valueW
, ret
+ 1, value
, size
, NULL
, NULL
);
252 /* this is needed to tell, with 0 as a return value, the difference between:
253 * - an error (GetLastError() != 0)
254 * - returning an empty string (in this case, we need to update the buffer)
256 if (ret
== 0 && size
&& GetLastError() == 0)
259 RtlFreeUnicodeString( &us_name
);
260 HeapFree(GetProcessHeap(), 0, valueW
);
266 /***********************************************************************
267 * GetEnvironmentVariableW (KERNEL32.@)
269 DWORD WINAPI
GetEnvironmentVariableW( LPCWSTR name
, LPWSTR val
, DWORD size
)
271 UNICODE_STRING us_name
;
272 UNICODE_STRING us_value
;
276 TRACE("(%s %p %lu)\n", debugstr_w(name
), val
, size
);
280 SetLastError(ERROR_ENVVAR_NOT_FOUND
);
284 RtlInitUnicodeString(&us_name
, name
);
286 us_value
.MaximumLength
= (size
? size
- 1 : 0) * sizeof(WCHAR
);
287 us_value
.Buffer
= val
;
289 status
= RtlQueryEnvironmentVariable_U(NULL
, &us_name
, &us_value
);
290 len
= us_value
.Length
/ sizeof(WCHAR
);
291 if (status
!= STATUS_SUCCESS
)
293 SetLastError( RtlNtStatusToDosError(status
) );
294 return (status
== STATUS_BUFFER_TOO_SMALL
) ? len
+ 1 : 0;
296 if (size
) val
[len
] = '\0';
298 return us_value
.Length
/ sizeof(WCHAR
);
302 /***********************************************************************
303 * SetEnvironmentVariableA (KERNEL32.@)
305 BOOL WINAPI
SetEnvironmentVariableA( LPCSTR name
, LPCSTR value
)
307 UNICODE_STRING us_name
;
312 SetLastError(ERROR_ENVVAR_NOT_FOUND
);
316 RtlCreateUnicodeStringFromAsciiz( &us_name
, name
);
319 UNICODE_STRING us_value
;
321 RtlCreateUnicodeStringFromAsciiz( &us_value
, value
);
322 ret
= SetEnvironmentVariableW( us_name
.Buffer
, us_value
.Buffer
);
323 RtlFreeUnicodeString( &us_value
);
325 else ret
= SetEnvironmentVariableW( us_name
.Buffer
, NULL
);
327 RtlFreeUnicodeString( &us_name
);
333 /***********************************************************************
334 * SetEnvironmentVariableW (KERNEL32.@)
336 BOOL WINAPI
SetEnvironmentVariableW( LPCWSTR name
, LPCWSTR value
)
338 UNICODE_STRING us_name
;
341 TRACE("(%s %s)\n", debugstr_w(name
), debugstr_w(value
));
345 SetLastError(ERROR_ENVVAR_NOT_FOUND
);
349 RtlInitUnicodeString(&us_name
, name
);
352 UNICODE_STRING us_value
;
354 RtlInitUnicodeString(&us_value
, value
);
355 status
= RtlSetEnvironmentVariable(NULL
, &us_name
, &us_value
);
357 else status
= RtlSetEnvironmentVariable(NULL
, &us_name
, NULL
);
359 if (status
!= STATUS_SUCCESS
)
361 SetLastError( RtlNtStatusToDosError(status
) );
365 /* FIXME: see comments in generate_env_block16 */
366 if (env_sel
) generate_env_block16();
371 /***********************************************************************
372 * ExpandEnvironmentStringsA (KERNEL32.@)
374 * Note: overlapping buffers are not supported; this is how it should be.
375 * FIXME: return value is wrong for MBCS
377 DWORD WINAPI
ExpandEnvironmentStringsA( LPCSTR src
, LPSTR dst
, DWORD count
)
379 UNICODE_STRING us_src
;
383 RtlCreateUnicodeStringFromAsciiz( &us_src
, src
);
386 if (!(dstW
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(WCHAR
))))
388 ret
= ExpandEnvironmentStringsW( us_src
.Buffer
, dstW
, count
);
390 WideCharToMultiByte( CP_ACP
, 0, dstW
, ret
, dst
, count
, NULL
, NULL
);
392 else ret
= ExpandEnvironmentStringsW( us_src
.Buffer
, NULL
, 0);
394 RtlFreeUnicodeString( &us_src
);
395 if (dstW
) HeapFree(GetProcessHeap(), 0, dstW
);
401 /***********************************************************************
402 * ExpandEnvironmentStringsW (KERNEL32.@)
404 DWORD WINAPI
ExpandEnvironmentStringsW( LPCWSTR src
, LPWSTR dst
, DWORD len
)
406 UNICODE_STRING us_src
;
407 UNICODE_STRING us_dst
;
411 TRACE("(%s %p %lu)\n", debugstr_w(src
), dst
, len
);
413 RtlInitUnicodeString(&us_src
, src
);
415 us_dst
.MaximumLength
= len
* sizeof(WCHAR
);
419 status
= RtlExpandEnvironmentStrings_U(NULL
, &us_src
, &us_dst
, &res
);
420 res
/= sizeof(WCHAR
);
421 if (status
!= STATUS_SUCCESS
)
423 SetLastError( RtlNtStatusToDosError(status
) );
424 if (status
!= STATUS_BUFFER_TOO_SMALL
) return 0;
425 if (len
&& dst
) dst
[len
- 1] = '\0';
432 /***********************************************************************
433 * GetDOSEnvironment (KERNEL.131)
435 SEGPTR WINAPI
GetDOSEnvironment16(void)
437 return generate_env_block16();
441 /***********************************************************************
442 * GetStdHandle (KERNEL32.@)
444 HANDLE WINAPI
GetStdHandle( DWORD std_handle
)
448 case STD_INPUT_HANDLE
: return NtCurrentTeb()->Peb
->ProcessParameters
->hStdInput
;
449 case STD_OUTPUT_HANDLE
: return NtCurrentTeb()->Peb
->ProcessParameters
->hStdOutput
;
450 case STD_ERROR_HANDLE
: return NtCurrentTeb()->Peb
->ProcessParameters
->hStdError
;
452 SetLastError( ERROR_INVALID_PARAMETER
);
453 return INVALID_HANDLE_VALUE
;
457 /***********************************************************************
458 * SetStdHandle (KERNEL32.@)
460 BOOL WINAPI
SetStdHandle( DWORD std_handle
, HANDLE handle
)
464 case STD_INPUT_HANDLE
: NtCurrentTeb()->Peb
->ProcessParameters
->hStdInput
= handle
; return TRUE
;
465 case STD_OUTPUT_HANDLE
: NtCurrentTeb()->Peb
->ProcessParameters
->hStdOutput
= handle
; return TRUE
;
466 case STD_ERROR_HANDLE
: NtCurrentTeb()->Peb
->ProcessParameters
->hStdError
= handle
; return TRUE
;
468 SetLastError( ERROR_INVALID_PARAMETER
);
472 /***********************************************************************
473 * GetStartupInfoA (KERNEL32.@)
475 VOID WINAPI
GetStartupInfoA( LPSTARTUPINFOA info
)
477 assert(startup_infoA
.cb
);
478 memcpy(info
, &startup_infoA
, sizeof(startup_infoA
));
482 /***********************************************************************
483 * GetStartupInfoW (KERNEL32.@)
485 VOID WINAPI
GetStartupInfoW( LPSTARTUPINFOW info
)
487 assert(startup_infoW
.cb
);
488 memcpy(info
, &startup_infoW
, sizeof(startup_infoW
));
491 /******************************************************************
492 * ENV_CopyStartupInformation (internal)
494 * Creates the STARTUPINFO information from the ntdll information
496 void ENV_CopyStartupInformation(void)
498 RTL_USER_PROCESS_PARAMETERS
* rupp
;
503 rupp
= NtCurrentTeb()->Peb
->ProcessParameters
;
505 startup_infoW
.cb
= sizeof(startup_infoW
);
506 startup_infoW
.lpReserved
= NULL
;
507 startup_infoW
.lpDesktop
= rupp
->Desktop
.Buffer
;
508 startup_infoW
.lpTitle
= rupp
->WindowTitle
.Buffer
;
509 startup_infoW
.dwX
= rupp
->dwX
;
510 startup_infoW
.dwY
= rupp
->dwY
;
511 startup_infoW
.dwXSize
= rupp
->dwXSize
;
512 startup_infoW
.dwYSize
= rupp
->dwYSize
;
513 startup_infoW
.dwXCountChars
= rupp
->dwXCountChars
;
514 startup_infoW
.dwYCountChars
= rupp
->dwYCountChars
;
515 startup_infoW
.dwFillAttribute
= rupp
->dwFillAttribute
;
516 startup_infoW
.dwFlags
= rupp
->dwFlags
;
517 startup_infoW
.wShowWindow
= rupp
->wShowWindow
;
518 startup_infoW
.cbReserved2
= 0;
519 startup_infoW
.lpReserved2
= NULL
;
520 startup_infoW
.hStdInput
= rupp
->hStdInput
;
521 startup_infoW
.hStdOutput
= rupp
->hStdOutput
;
522 startup_infoW
.hStdError
= rupp
->hStdError
;
524 startup_infoA
.cb
= sizeof(startup_infoW
);
525 startup_infoA
.lpReserved
= NULL
;
526 startup_infoA
.lpDesktop
= (rupp
->Desktop
.Length
&&
527 RtlUnicodeStringToAnsiString( &ansi
, &rupp
->Desktop
, TRUE
) == STATUS_SUCCESS
) ?
529 startup_infoA
.lpTitle
= (rupp
->WindowTitle
.Length
&&
530 RtlUnicodeStringToAnsiString( &ansi
, &rupp
->WindowTitle
, TRUE
) == STATUS_SUCCESS
) ?
532 startup_infoA
.dwX
= rupp
->dwX
;
533 startup_infoA
.dwY
= rupp
->dwY
;
534 startup_infoA
.dwXSize
= rupp
->dwXSize
;
535 startup_infoA
.dwYSize
= rupp
->dwYSize
;
536 startup_infoA
.dwXCountChars
= rupp
->dwXCountChars
;
537 startup_infoA
.dwYCountChars
= rupp
->dwYCountChars
;
538 startup_infoA
.dwFillAttribute
= rupp
->dwFillAttribute
;
539 startup_infoA
.dwFlags
= rupp
->dwFlags
;
540 startup_infoA
.wShowWindow
= rupp
->wShowWindow
;
541 startup_infoA
.cbReserved2
= 0;
542 startup_infoA
.lpReserved2
= NULL
;
543 startup_infoA
.hStdInput
= rupp
->hStdInput
;
544 startup_infoA
.hStdOutput
= rupp
->hStdOutput
;
545 startup_infoA
.hStdError
= rupp
->hStdError
;