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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
30 #define WIN32_NO_STATUS
34 #include "wine/library.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 #include "kernel_private.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(environ
);
44 * - contrary to Microsoft docs, the environment strings do not appear
45 * to be sorted on Win95 (although they are on NT); so we don't bother
46 * to sort them either.
49 static STARTUPINFOW startup_infoW
;
50 static STARTUPINFOA startup_infoA
;
53 /***********************************************************************
54 * GetCommandLineA (KERNEL32.@)
56 * WARNING: there's a Windows incompatibility lurking here !
57 * Win32s always includes the full path of the program file,
58 * whereas Windows NT only returns the full file path plus arguments
59 * in case the program has been started with a full path.
60 * Win9x seems to have inherited NT behaviour.
62 * Note that both Start Menu Execute and Explorer start programs with
63 * fully specified quoted app file paths, which is why probably the only case
64 * where you'll see single file names is in case of direct launch
65 * via CreateProcess or WinExec.
67 * Perhaps we should take care of Win3.1 programs here (Win32s "feature").
69 * References: MS KB article q102762.txt (special Win32s handling)
71 LPSTR WINAPI
GetCommandLineA(void)
73 static char *cmdlineA
; /* ASCII command line */
75 if (!cmdlineA
) /* make an ansi version if we don't have it */
80 cmdlineA
= (RtlUnicodeStringToAnsiString( &ansi
, &NtCurrentTeb()->Peb
->ProcessParameters
->CommandLine
, TRUE
) == STATUS_SUCCESS
) ?
87 /***********************************************************************
88 * GetCommandLineW (KERNEL32.@)
90 LPWSTR WINAPI
GetCommandLineW(void)
92 return NtCurrentTeb()->Peb
->ProcessParameters
->CommandLine
.Buffer
;
96 /***********************************************************************
97 * GetEnvironmentStringsA (KERNEL32.@)
98 * GetEnvironmentStrings (KERNEL32.@)
100 LPSTR WINAPI
GetEnvironmentStringsA(void)
110 ptrW
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
113 slen
= strlenW(ptrW
) + 1;
114 len
+= WideCharToMultiByte( CP_ACP
, 0, ptrW
, slen
, NULL
, 0, NULL
, NULL
);
118 if ((ret
= HeapAlloc( GetProcessHeap(), 0, len
)) != NULL
)
120 ptrW
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
124 slen
= strlenW(ptrW
) + 1;
125 WideCharToMultiByte( CP_ACP
, 0, ptrW
, slen
, ptrA
, len
, NULL
, NULL
);
127 ptrA
+= strlen(ptrA
) + 1;
137 /***********************************************************************
138 * GetEnvironmentStringsW (KERNEL32.@)
140 LPWSTR WINAPI
GetEnvironmentStringsW(void)
142 return NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
146 /***********************************************************************
147 * FreeEnvironmentStringsA (KERNEL32.@)
149 BOOL WINAPI
FreeEnvironmentStringsA( LPSTR ptr
)
151 return HeapFree( GetProcessHeap(), 0, ptr
);
155 /***********************************************************************
156 * FreeEnvironmentStringsW (KERNEL32.@)
158 BOOL WINAPI
FreeEnvironmentStringsW( LPWSTR ptr
)
164 /***********************************************************************
165 * GetEnvironmentVariableA (KERNEL32.@)
167 DWORD WINAPI
GetEnvironmentVariableA( LPCSTR name
, LPSTR value
, DWORD size
)
169 UNICODE_STRING us_name
;
175 SetLastError(ERROR_ENVVAR_NOT_FOUND
);
179 /* limit the size to sane values */
180 size
= min(size
, 32767);
181 if (!(valueW
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
))))
184 RtlCreateUnicodeStringFromAsciiz( &us_name
, name
);
186 ret
= GetEnvironmentVariableW( us_name
.Buffer
, valueW
, size
);
187 if (ret
&& ret
< size
)
189 WideCharToMultiByte( CP_ACP
, 0, valueW
, ret
+ 1, value
, size
, NULL
, NULL
);
191 /* this is needed to tell, with 0 as a return value, the difference between:
192 * - an error (GetLastError() != 0)
193 * - returning an empty string (in this case, we need to update the buffer)
195 if (ret
== 0 && size
&& GetLastError() == 0)
198 RtlFreeUnicodeString( &us_name
);
199 HeapFree(GetProcessHeap(), 0, valueW
);
205 /***********************************************************************
206 * GetEnvironmentVariableW (KERNEL32.@)
208 DWORD WINAPI
GetEnvironmentVariableW( LPCWSTR name
, LPWSTR val
, DWORD size
)
210 UNICODE_STRING us_name
;
211 UNICODE_STRING us_value
;
215 TRACE("(%s %p %u)\n", debugstr_w(name
), val
, size
);
219 SetLastError(ERROR_ENVVAR_NOT_FOUND
);
223 RtlInitUnicodeString(&us_name
, name
);
225 us_value
.MaximumLength
= (size
? size
- 1 : 0) * sizeof(WCHAR
);
226 us_value
.Buffer
= val
;
228 status
= RtlQueryEnvironmentVariable_U(NULL
, &us_name
, &us_value
);
229 len
= us_value
.Length
/ sizeof(WCHAR
);
230 if (status
!= STATUS_SUCCESS
)
232 SetLastError( RtlNtStatusToDosError(status
) );
233 return (status
== STATUS_BUFFER_TOO_SMALL
) ? len
+ 1 : 0;
235 if (size
) val
[len
] = '\0';
237 return us_value
.Length
/ sizeof(WCHAR
);
241 /***********************************************************************
242 * SetEnvironmentVariableA (KERNEL32.@)
244 BOOL WINAPI
SetEnvironmentVariableA( LPCSTR name
, LPCSTR value
)
246 UNICODE_STRING us_name
;
251 SetLastError(ERROR_ENVVAR_NOT_FOUND
);
255 RtlCreateUnicodeStringFromAsciiz( &us_name
, name
);
258 UNICODE_STRING us_value
;
260 RtlCreateUnicodeStringFromAsciiz( &us_value
, value
);
261 ret
= SetEnvironmentVariableW( us_name
.Buffer
, us_value
.Buffer
);
262 RtlFreeUnicodeString( &us_value
);
264 else ret
= SetEnvironmentVariableW( us_name
.Buffer
, NULL
);
266 RtlFreeUnicodeString( &us_name
);
272 /***********************************************************************
273 * SetEnvironmentVariableW (KERNEL32.@)
275 BOOL WINAPI
SetEnvironmentVariableW( LPCWSTR name
, LPCWSTR value
)
277 UNICODE_STRING us_name
;
280 TRACE("(%s %s)\n", debugstr_w(name
), debugstr_w(value
));
284 SetLastError(ERROR_ENVVAR_NOT_FOUND
);
288 RtlInitUnicodeString(&us_name
, name
);
291 UNICODE_STRING us_value
;
293 RtlInitUnicodeString(&us_value
, value
);
294 status
= RtlSetEnvironmentVariable(NULL
, &us_name
, &us_value
);
296 else status
= RtlSetEnvironmentVariable(NULL
, &us_name
, NULL
);
298 if (status
!= STATUS_SUCCESS
)
300 SetLastError( RtlNtStatusToDosError(status
) );
307 /***********************************************************************
308 * ExpandEnvironmentStringsA (KERNEL32.@)
310 * See ExpandEnvironmentStringsW.
312 * Note: overlapping buffers are not supported; this is how it should be.
313 * FIXME: return value is wrong for MBCS
315 DWORD WINAPI
ExpandEnvironmentStringsA( LPCSTR src
, LPSTR dst
, DWORD count
)
317 UNICODE_STRING us_src
;
321 RtlCreateUnicodeStringFromAsciiz( &us_src
, src
);
324 if (!(dstW
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(WCHAR
))))
326 ret
= ExpandEnvironmentStringsW( us_src
.Buffer
, dstW
, count
);
328 WideCharToMultiByte( CP_ACP
, 0, dstW
, ret
, dst
, count
, NULL
, NULL
);
330 else ret
= ExpandEnvironmentStringsW( us_src
.Buffer
, NULL
, 0);
332 RtlFreeUnicodeString( &us_src
);
333 HeapFree(GetProcessHeap(), 0, dstW
);
339 /***********************************************************************
340 * ExpandEnvironmentStringsW (KERNEL32.@)
342 * Replaces references to environment variables of the form '%EnvVar%'
343 * by their value. If the environment variable does not exist, then the
344 * reference is left as is.
347 * src [I] The string to be expanded.
348 * dst [O] The buffer in which to put the expanded string.
349 * len [I] The buffer size, in characters.
352 * The number of characters copied into the buffer. If the buffer is
353 * too small, then the required buffer size, in characters including the
354 * trailing '\0', is returned.
355 * If the function fails for some other reason, then it returns 0.
357 DWORD WINAPI
ExpandEnvironmentStringsW( LPCWSTR src
, LPWSTR dst
, DWORD len
)
359 UNICODE_STRING us_src
;
360 UNICODE_STRING us_dst
;
364 TRACE("(%s %p %u)\n", debugstr_w(src
), dst
, len
);
366 RtlInitUnicodeString(&us_src
, src
);
368 /* make sure we don't overflow the maximum UNICODE_STRING size */
369 if (len
> UNICODE_STRING_MAX_CHARS
)
370 len
= UNICODE_STRING_MAX_CHARS
;
373 us_dst
.MaximumLength
= len
* sizeof(WCHAR
);
377 status
= RtlExpandEnvironmentStrings_U(NULL
, &us_src
, &us_dst
, &res
);
378 res
/= sizeof(WCHAR
);
379 if (status
!= STATUS_SUCCESS
)
381 SetLastError( RtlNtStatusToDosError(status
) );
382 if (status
!= STATUS_BUFFER_TOO_SMALL
) return 0;
383 if (len
&& dst
) dst
[len
- 1] = '\0';
390 /***********************************************************************
391 * GetStdHandle (KERNEL32.@)
393 HANDLE WINAPI
GetStdHandle( DWORD std_handle
)
397 case STD_INPUT_HANDLE
: return NtCurrentTeb()->Peb
->ProcessParameters
->hStdInput
;
398 case STD_OUTPUT_HANDLE
: return NtCurrentTeb()->Peb
->ProcessParameters
->hStdOutput
;
399 case STD_ERROR_HANDLE
: return NtCurrentTeb()->Peb
->ProcessParameters
->hStdError
;
401 SetLastError( ERROR_INVALID_HANDLE
);
402 return INVALID_HANDLE_VALUE
;
406 /***********************************************************************
407 * SetStdHandle (KERNEL32.@)
409 BOOL WINAPI
SetStdHandle( DWORD std_handle
, HANDLE handle
)
413 case STD_INPUT_HANDLE
: NtCurrentTeb()->Peb
->ProcessParameters
->hStdInput
= handle
; return TRUE
;
414 case STD_OUTPUT_HANDLE
: NtCurrentTeb()->Peb
->ProcessParameters
->hStdOutput
= handle
; return TRUE
;
415 case STD_ERROR_HANDLE
: NtCurrentTeb()->Peb
->ProcessParameters
->hStdError
= handle
; return TRUE
;
417 SetLastError( ERROR_INVALID_HANDLE
);
421 /***********************************************************************
422 * GetStartupInfoA (KERNEL32.@)
424 VOID WINAPI
GetStartupInfoA( LPSTARTUPINFOA info
)
426 *info
= startup_infoA
;
430 /***********************************************************************
431 * GetStartupInfoW (KERNEL32.@)
433 VOID WINAPI
GetStartupInfoW( LPSTARTUPINFOW info
)
435 *info
= startup_infoW
;
438 /******************************************************************
439 * ENV_CopyStartupInformation (internal)
441 * Creates the STARTUPINFO information from the ntdll information
443 void ENV_CopyStartupInformation(void)
445 RTL_USER_PROCESS_PARAMETERS
* rupp
;
450 rupp
= NtCurrentTeb()->Peb
->ProcessParameters
;
452 startup_infoW
.cb
= sizeof(startup_infoW
);
453 startup_infoW
.lpReserved
= NULL
;
454 startup_infoW
.lpDesktop
= rupp
->Desktop
.Buffer
;
455 startup_infoW
.lpTitle
= rupp
->WindowTitle
.Buffer
;
456 startup_infoW
.dwX
= rupp
->dwX
;
457 startup_infoW
.dwY
= rupp
->dwY
;
458 startup_infoW
.dwXSize
= rupp
->dwXSize
;
459 startup_infoW
.dwYSize
= rupp
->dwYSize
;
460 startup_infoW
.dwXCountChars
= rupp
->dwXCountChars
;
461 startup_infoW
.dwYCountChars
= rupp
->dwYCountChars
;
462 startup_infoW
.dwFillAttribute
= rupp
->dwFillAttribute
;
463 startup_infoW
.dwFlags
= rupp
->dwFlags
;
464 startup_infoW
.wShowWindow
= rupp
->wShowWindow
;
465 startup_infoW
.cbReserved2
= rupp
->RuntimeInfo
.MaximumLength
;
466 startup_infoW
.lpReserved2
= rupp
->RuntimeInfo
.MaximumLength
? (void*)rupp
->RuntimeInfo
.Buffer
: NULL
;
467 startup_infoW
.hStdInput
= rupp
->hStdInput
? rupp
->hStdInput
: INVALID_HANDLE_VALUE
;
468 startup_infoW
.hStdOutput
= rupp
->hStdOutput
? rupp
->hStdOutput
: INVALID_HANDLE_VALUE
;
469 startup_infoW
.hStdError
= rupp
->hStdError
? rupp
->hStdError
: INVALID_HANDLE_VALUE
;
471 startup_infoA
.cb
= sizeof(startup_infoA
);
472 startup_infoA
.lpReserved
= NULL
;
473 startup_infoA
.lpDesktop
= RtlUnicodeStringToAnsiString( &ansi
, &rupp
->Desktop
, TRUE
) == STATUS_SUCCESS
?
475 startup_infoA
.lpTitle
= RtlUnicodeStringToAnsiString( &ansi
, &rupp
->WindowTitle
, TRUE
) == STATUS_SUCCESS
?
477 startup_infoA
.dwX
= rupp
->dwX
;
478 startup_infoA
.dwY
= rupp
->dwY
;
479 startup_infoA
.dwXSize
= rupp
->dwXSize
;
480 startup_infoA
.dwYSize
= rupp
->dwYSize
;
481 startup_infoA
.dwXCountChars
= rupp
->dwXCountChars
;
482 startup_infoA
.dwYCountChars
= rupp
->dwYCountChars
;
483 startup_infoA
.dwFillAttribute
= rupp
->dwFillAttribute
;
484 startup_infoA
.dwFlags
= rupp
->dwFlags
;
485 startup_infoA
.wShowWindow
= rupp
->wShowWindow
;
486 startup_infoA
.cbReserved2
= rupp
->RuntimeInfo
.MaximumLength
;
487 startup_infoA
.lpReserved2
= rupp
->RuntimeInfo
.MaximumLength
? (void*)rupp
->RuntimeInfo
.Buffer
: NULL
;
488 startup_infoA
.hStdInput
= rupp
->hStdInput
? rupp
->hStdInput
: INVALID_HANDLE_VALUE
;
489 startup_infoA
.hStdOutput
= rupp
->hStdOutput
? rupp
->hStdOutput
: INVALID_HANDLE_VALUE
;
490 startup_infoA
.hStdError
= rupp
->hStdError
? rupp
->hStdError
: INVALID_HANDLE_VALUE
;
495 /***********************************************************************
496 * GetFirmwareEnvironmentVariableA (KERNEL32.@)
498 DWORD WINAPI
GetFirmwareEnvironmentVariableA(LPCSTR name
, LPCSTR guid
, PVOID buffer
, DWORD size
)
500 FIXME("stub: %s %s %p %u\n", debugstr_a(name
), debugstr_a(guid
), buffer
, size
);
501 SetLastError(ERROR_INVALID_FUNCTION
);
505 /***********************************************************************
506 * GetFirmwareEnvironmentVariableW (KERNEL32.@)
508 DWORD WINAPI
GetFirmwareEnvironmentVariableW(LPCWSTR name
, LPCWSTR guid
, PVOID buffer
, DWORD size
)
510 FIXME("stub: %s %s %p %u\n", debugstr_w(name
), debugstr_w(guid
), buffer
, size
);
511 SetLastError(ERROR_INVALID_FUNCTION
);