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"
30 #define WIN32_NO_STATUS
34 #include "wine/server.h"
35 #include "wine/library.h"
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
40 #include "kernel_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(environ);
45 * - contrary to Microsoft docs, the environment strings do not appear
46 * to be sorted on Win95 (although they are on NT); so we don't bother
47 * to sort them either.
50 static STARTUPINFOW startup_infoW;
51 static STARTUPINFOA startup_infoA;
54 /***********************************************************************
55 * GetCommandLineA (KERNEL32.@)
57 * WARNING: there's a Windows incompatibility lurking here !
58 * Win32s always includes the full path of the program file,
59 * whereas Windows NT only returns the full file path plus arguments
60 * in case the program has been started with a full path.
61 * Win9x seems to have inherited NT behaviour.
63 * Note that both Start Menu Execute and Explorer start programs with
64 * fully specified quoted app file paths, which is why probably the only case
65 * where you'll see single file names is in case of direct launch
66 * via CreateProcess or WinExec.
68 * Perhaps we should take care of Win3.1 programs here (Win32s "feature").
70 * References: MS KB article q102762.txt (special Win32s handling)
72 LPSTR WINAPI GetCommandLineA(void)
74 static char *cmdlineA; /* ASCII command line */
76 if (!cmdlineA) /* make an ansi version if we don't have it */
81 cmdlineA = (RtlUnicodeStringToAnsiString( &ansi, &NtCurrentTeb()->Peb->ProcessParameters->CommandLine, TRUE) == STATUS_SUCCESS) ?
88 /***********************************************************************
89 * GetCommandLineW (KERNEL32.@)
91 LPWSTR WINAPI GetCommandLineW(void)
93 return NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer;
97 /***********************************************************************
98 * GetEnvironmentStringsA (KERNEL32.@)
99 * GetEnvironmentStrings (KERNEL32.@)
101 LPSTR WINAPI GetEnvironmentStringsA(void)
111 ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment;
114 slen = strlenW(ptrW) + 1;
115 len += WideCharToMultiByte( CP_ACP, 0, ptrW, slen, NULL, 0, NULL, NULL );
119 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )) != NULL)
121 ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment;
125 slen = strlenW(ptrW) + 1;
126 WideCharToMultiByte( CP_ACP, 0, ptrW, slen, ptrA, len, NULL, NULL );
128 ptrA += strlen(ptrA) + 1;
138 /***********************************************************************
139 * GetEnvironmentStringsW (KERNEL32.@)
141 LPWSTR WINAPI GetEnvironmentStringsW(void)
143 return NtCurrentTeb()->Peb->ProcessParameters->Environment;
147 /***********************************************************************
148 * FreeEnvironmentStringsA (KERNEL32.@)
150 BOOL WINAPI FreeEnvironmentStringsA( LPSTR ptr )
152 return HeapFree( GetProcessHeap(), 0, ptr );
156 /***********************************************************************
157 * FreeEnvironmentStringsW (KERNEL32.@)
159 BOOL WINAPI FreeEnvironmentStringsW( LPWSTR ptr )
165 /***********************************************************************
166 * GetEnvironmentVariableA (KERNEL32.@)
168 DWORD WINAPI GetEnvironmentVariableA( LPCSTR name, LPSTR value, DWORD size )
170 UNICODE_STRING us_name;
176 SetLastError(ERROR_ENVVAR_NOT_FOUND);
180 if (!(valueW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
183 RtlCreateUnicodeStringFromAsciiz( &us_name, name );
185 ret = GetEnvironmentVariableW( us_name.Buffer, valueW, size);
186 if (ret && ret < size)
188 WideCharToMultiByte( CP_ACP, 0, valueW, ret + 1, value, size, NULL, NULL );
190 /* this is needed to tell, with 0 as a return value, the difference between:
191 * - an error (GetLastError() != 0)
192 * - returning an empty string (in this case, we need to update the buffer)
194 if (ret == 0 && size && GetLastError() == 0)
197 RtlFreeUnicodeString( &us_name );
198 HeapFree(GetProcessHeap(), 0, valueW);
204 /***********************************************************************
205 * GetEnvironmentVariableW (KERNEL32.@)
207 DWORD WINAPI GetEnvironmentVariableW( LPCWSTR name, LPWSTR val, DWORD size )
209 UNICODE_STRING us_name;
210 UNICODE_STRING us_value;
214 TRACE("(%s %p %lu)\n", debugstr_w(name), val, size);
218 SetLastError(ERROR_ENVVAR_NOT_FOUND);
222 RtlInitUnicodeString(&us_name, name);
224 us_value.MaximumLength = (size ? size - 1 : 0) * sizeof(WCHAR);
225 us_value.Buffer = val;
227 status = RtlQueryEnvironmentVariable_U(NULL, &us_name, &us_value);
228 len = us_value.Length / sizeof(WCHAR);
229 if (status != STATUS_SUCCESS)
231 SetLastError( RtlNtStatusToDosError(status) );
232 return (status == STATUS_BUFFER_TOO_SMALL) ? len + 1 : 0;
234 if (size) val[len] = '\0';
236 return us_value.Length / sizeof(WCHAR);
240 /***********************************************************************
241 * SetEnvironmentVariableA (KERNEL32.@)
243 BOOL WINAPI SetEnvironmentVariableA( LPCSTR name, LPCSTR value )
245 UNICODE_STRING us_name;
250 SetLastError(ERROR_ENVVAR_NOT_FOUND);
254 RtlCreateUnicodeStringFromAsciiz( &us_name, name );
257 UNICODE_STRING us_value;
259 RtlCreateUnicodeStringFromAsciiz( &us_value, value );
260 ret = SetEnvironmentVariableW( us_name.Buffer, us_value.Buffer );
261 RtlFreeUnicodeString( &us_value );
263 else ret = SetEnvironmentVariableW( us_name.Buffer, NULL );
265 RtlFreeUnicodeString( &us_name );
271 /***********************************************************************
272 * SetEnvironmentVariableW (KERNEL32.@)
274 BOOL WINAPI SetEnvironmentVariableW( LPCWSTR name, LPCWSTR value )
276 UNICODE_STRING us_name;
279 TRACE("(%s %s)\n", debugstr_w(name), debugstr_w(value));
283 SetLastError(ERROR_ENVVAR_NOT_FOUND);
287 RtlInitUnicodeString(&us_name, name);
290 UNICODE_STRING us_value;
292 RtlInitUnicodeString(&us_value, value);
293 status = RtlSetEnvironmentVariable(NULL, &us_name, &us_value);
295 else status = RtlSetEnvironmentVariable(NULL, &us_name, NULL);
297 if (status != STATUS_SUCCESS)
299 SetLastError( RtlNtStatusToDosError(status) );
306 /***********************************************************************
307 * ExpandEnvironmentStringsA (KERNEL32.@)
309 * Note: overlapping buffers are not supported; this is how it should be.
310 * FIXME: return value is wrong for MBCS
312 DWORD WINAPI ExpandEnvironmentStringsA( LPCSTR src, LPSTR dst, DWORD count )
314 UNICODE_STRING us_src;
318 RtlCreateUnicodeStringFromAsciiz( &us_src, src );
321 if (!(dstW = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR))))
323 ret = ExpandEnvironmentStringsW( us_src.Buffer, dstW, count);
325 WideCharToMultiByte( CP_ACP, 0, dstW, ret, dst, count, NULL, NULL );
327 else ret = ExpandEnvironmentStringsW( us_src.Buffer, NULL, 0);
329 RtlFreeUnicodeString( &us_src );
330 HeapFree(GetProcessHeap(), 0, dstW);
336 /***********************************************************************
337 * ExpandEnvironmentStringsW (KERNEL32.@)
339 DWORD WINAPI ExpandEnvironmentStringsW( LPCWSTR src, LPWSTR dst, DWORD len )
341 UNICODE_STRING us_src;
342 UNICODE_STRING us_dst;
346 TRACE("(%s %p %lu)\n", debugstr_w(src), dst, len);
348 RtlInitUnicodeString(&us_src, src);
350 us_dst.MaximumLength = len * sizeof(WCHAR);
354 status = RtlExpandEnvironmentStrings_U(NULL, &us_src, &us_dst, &res);
355 res /= sizeof(WCHAR);
356 if (status != STATUS_SUCCESS)
358 SetLastError( RtlNtStatusToDosError(status) );
359 if (status != STATUS_BUFFER_TOO_SMALL) return 0;
360 if (len && dst) dst[len - 1] = '\0';
367 /***********************************************************************
368 * GetStdHandle (KERNEL32.@)
370 HANDLE WINAPI GetStdHandle( DWORD std_handle )
374 case STD_INPUT_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdInput;
375 case STD_OUTPUT_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdOutput;
376 case STD_ERROR_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdError;
378 SetLastError( ERROR_INVALID_PARAMETER );
379 return INVALID_HANDLE_VALUE;
383 /***********************************************************************
384 * SetStdHandle (KERNEL32.@)
386 BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
390 case STD_INPUT_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdInput = handle; return TRUE;
391 case STD_OUTPUT_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdOutput = handle; return TRUE;
392 case STD_ERROR_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdError = handle; return TRUE;
394 SetLastError( ERROR_INVALID_PARAMETER );
398 /***********************************************************************
399 * GetStartupInfoA (KERNEL32.@)
401 VOID WINAPI GetStartupInfoA( LPSTARTUPINFOA info )
403 assert(startup_infoA.cb);
404 memcpy(info, &startup_infoA, sizeof(startup_infoA));
408 /***********************************************************************
409 * GetStartupInfoW (KERNEL32.@)
411 VOID WINAPI GetStartupInfoW( LPSTARTUPINFOW info )
413 assert(startup_infoW.cb);
414 memcpy(info, &startup_infoW, sizeof(startup_infoW));
417 /******************************************************************
418 * ENV_CopyStartupInformation (internal)
420 * Creates the STARTUPINFO information from the ntdll information
422 void ENV_CopyStartupInformation(void)
424 RTL_USER_PROCESS_PARAMETERS* rupp;
429 rupp = NtCurrentTeb()->Peb->ProcessParameters;
431 startup_infoW.cb = sizeof(startup_infoW);
432 startup_infoW.lpReserved = NULL;
433 startup_infoW.lpDesktop = rupp->Desktop.Buffer;
434 startup_infoW.lpTitle = rupp->WindowTitle.Buffer;
435 startup_infoW.dwX = rupp->dwX;
436 startup_infoW.dwY = rupp->dwY;
437 startup_infoW.dwXSize = rupp->dwXSize;
438 startup_infoW.dwYSize = rupp->dwYSize;
439 startup_infoW.dwXCountChars = rupp->dwXCountChars;
440 startup_infoW.dwYCountChars = rupp->dwYCountChars;
441 startup_infoW.dwFillAttribute = rupp->dwFillAttribute;
442 startup_infoW.dwFlags = rupp->dwFlags;
443 startup_infoW.wShowWindow = rupp->wShowWindow;
444 startup_infoW.cbReserved2 = rupp->RuntimeInfo.MaximumLength;
445 startup_infoW.lpReserved2 = rupp->RuntimeInfo.MaximumLength ? (void*)rupp->RuntimeInfo.Buffer : NULL;
446 startup_infoW.hStdInput = rupp->hStdInput;
447 startup_infoW.hStdOutput = rupp->hStdOutput;
448 startup_infoW.hStdError = rupp->hStdError;
450 startup_infoA.cb = sizeof(startup_infoA);
451 startup_infoA.lpReserved = NULL;
452 startup_infoA.lpDesktop = (rupp->Desktop.Length &&
453 RtlUnicodeStringToAnsiString( &ansi, &rupp->Desktop, TRUE) == STATUS_SUCCESS) ?
455 startup_infoA.lpTitle = (rupp->WindowTitle.Length &&
456 RtlUnicodeStringToAnsiString( &ansi, &rupp->WindowTitle, TRUE) == STATUS_SUCCESS) ?
458 startup_infoA.dwX = rupp->dwX;
459 startup_infoA.dwY = rupp->dwY;
460 startup_infoA.dwXSize = rupp->dwXSize;
461 startup_infoA.dwYSize = rupp->dwYSize;
462 startup_infoA.dwXCountChars = rupp->dwXCountChars;
463 startup_infoA.dwYCountChars = rupp->dwYCountChars;
464 startup_infoA.dwFillAttribute = rupp->dwFillAttribute;
465 startup_infoA.dwFlags = rupp->dwFlags;
466 startup_infoA.wShowWindow = rupp->wShowWindow;
467 startup_infoA.cbReserved2 = rupp->RuntimeInfo.MaximumLength;
468 startup_infoA.lpReserved2 = rupp->RuntimeInfo.MaximumLength ? (void*)rupp->RuntimeInfo.Buffer : NULL;
469 startup_infoA.hStdInput = rupp->hStdInput;
470 startup_infoA.hStdOutput = rupp->hStdOutput;
471 startup_infoA.hStdError = rupp->hStdError;