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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #include "ntstatus.h"
30 #define WIN32_NO_STATUS
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winerror.h"
34 #include "wine/library.h"
35 #include "winternl.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38
39 #include "kernel_private.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(environ);
42
43 /* Notes:
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.
47 */
48
49 static STARTUPINFOW startup_infoW;
50 static STARTUPINFOA startup_infoA;
51
52
53 /***********************************************************************
54 * GetCommandLineA (KERNEL32.@)
55 *
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.
61 *
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.
66 *
67 * Perhaps we should take care of Win3.1 programs here (Win32s "feature").
68 *
69 * References: MS KB article q102762.txt (special Win32s handling)
70 */
71 LPSTR WINAPI GetCommandLineA(void)
72 {
73 static char *cmdlineA; /* ASCII command line */
74
75 if (!cmdlineA) /* make an ansi version if we don't have it */
76 {
77 ANSI_STRING ansi;
78 RtlAcquirePebLock();
79
80 cmdlineA = (RtlUnicodeStringToAnsiString( &ansi, &NtCurrentTeb()->Peb->ProcessParameters->CommandLine, TRUE) == STATUS_SUCCESS) ?
81 ansi.Buffer : NULL;
82 RtlReleasePebLock();
83 }
84 return cmdlineA;
85 }
86
87 /***********************************************************************
88 * GetCommandLineW (KERNEL32.@)
89 */
90 LPWSTR WINAPI GetCommandLineW(void)
91 {
92 return NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer;
93 }
94
95
96 /***********************************************************************
97 * GetEnvironmentStringsA (KERNEL32.@)
98 * GetEnvironmentStrings (KERNEL32.@)
99 */
100 LPSTR WINAPI GetEnvironmentStringsA(void)
101 {
102 LPWSTR ptrW;
103 unsigned len, slen;
104 LPSTR ret, ptrA;
105
106 RtlAcquirePebLock();
107
108 len = 1;
109
110 ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment;
111 while (*ptrW)
112 {
113 slen = strlenW(ptrW) + 1;
114 len += WideCharToMultiByte( CP_ACP, 0, ptrW, slen, NULL, 0, NULL, NULL );
115 ptrW += slen;
116 }
117
118 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )) != NULL)
119 {
120 ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment;
121 ptrA = ret;
122 while (*ptrW)
123 {
124 slen = strlenW(ptrW) + 1;
125 WideCharToMultiByte( CP_ACP, 0, ptrW, slen, ptrA, len, NULL, NULL );
126 ptrW += slen;
127 ptrA += strlen(ptrA) + 1;
128 }
129 *ptrA = 0;
130 }
131
132 RtlReleasePebLock();
133 return ret;
134 }
135
136
137 /***********************************************************************
138 * GetEnvironmentStringsW (KERNEL32.@)
139 */
140 LPWSTR WINAPI GetEnvironmentStringsW(void)
141 {
142 return NtCurrentTeb()->Peb->ProcessParameters->Environment;
143 }
144
145
146 /***********************************************************************
147 * FreeEnvironmentStringsA (KERNEL32.@)
148 */
149 BOOL WINAPI FreeEnvironmentStringsA( LPSTR ptr )
150 {
151 return HeapFree( GetProcessHeap(), 0, ptr );
152 }
153
154
155 /***********************************************************************
156 * FreeEnvironmentStringsW (KERNEL32.@)
157 */
158 BOOL WINAPI FreeEnvironmentStringsW( LPWSTR ptr )
159 {
160 return TRUE;
161 }
162
163
164 /***********************************************************************
165 * GetEnvironmentVariableA (KERNEL32.@)
166 */
167 DWORD WINAPI GetEnvironmentVariableA( LPCSTR name, LPSTR value, DWORD size )
168 {
169 UNICODE_STRING us_name;
170 PWSTR valueW;
171 DWORD ret;
172
173 if (!name || !*name)
174 {
175 SetLastError(ERROR_ENVVAR_NOT_FOUND);
176 return 0;
177 }
178
179 if (!(valueW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
180 return 0;
181
182 RtlCreateUnicodeStringFromAsciiz( &us_name, name );
183 SetLastError(0);
184 ret = GetEnvironmentVariableW( us_name.Buffer, valueW, size);
185 if (ret && ret < size)
186 {
187 WideCharToMultiByte( CP_ACP, 0, valueW, ret + 1, value, size, NULL, NULL );
188 }
189 /* this is needed to tell, with 0 as a return value, the difference between:
190 * - an error (GetLastError() != 0)
191 * - returning an empty string (in this case, we need to update the buffer)
192 */
193 if (ret == 0 && size && GetLastError() == 0)
194 value[0] = '\0';
195
196 RtlFreeUnicodeString( &us_name );
197 HeapFree(GetProcessHeap(), 0, valueW);
198
199 return ret;
200 }
201
202
203 /***********************************************************************
204 * GetEnvironmentVariableW (KERNEL32.@)
205 */
206 DWORD WINAPI GetEnvironmentVariableW( LPCWSTR name, LPWSTR val, DWORD size )
207 {
208 UNICODE_STRING us_name;
209 UNICODE_STRING us_value;
210 NTSTATUS status;
211 unsigned len;
212
213 TRACE("(%s %p %u)\n", debugstr_w(name), val, size);
214
215 if (!name || !*name)
216 {
217 SetLastError(ERROR_ENVVAR_NOT_FOUND);
218 return 0;
219 }
220
221 RtlInitUnicodeString(&us_name, name);
222 us_value.Length = 0;
223 us_value.MaximumLength = (size ? size - 1 : 0) * sizeof(WCHAR);
224 us_value.Buffer = val;
225
226 status = RtlQueryEnvironmentVariable_U(NULL, &us_name, &us_value);
227 len = us_value.Length / sizeof(WCHAR);
228 if (status != STATUS_SUCCESS)
229 {
230 SetLastError( RtlNtStatusToDosError(status) );
231 return (status == STATUS_BUFFER_TOO_SMALL) ? len + 1 : 0;
232 }
233 if (size) val[len] = '\0';
234
235 return us_value.Length / sizeof(WCHAR);
236 }
237
238
239 /***********************************************************************
240 * SetEnvironmentVariableA (KERNEL32.@)
241 */
242 BOOL WINAPI SetEnvironmentVariableA( LPCSTR name, LPCSTR value )
243 {
244 UNICODE_STRING us_name;
245 BOOL ret;
246
247 if (!name)
248 {
249 SetLastError(ERROR_ENVVAR_NOT_FOUND);
250 return 0;
251 }
252
253 RtlCreateUnicodeStringFromAsciiz( &us_name, name );
254 if (value)
255 {
256 UNICODE_STRING us_value;
257
258 RtlCreateUnicodeStringFromAsciiz( &us_value, value );
259 ret = SetEnvironmentVariableW( us_name.Buffer, us_value.Buffer );
260 RtlFreeUnicodeString( &us_value );
261 }
262 else ret = SetEnvironmentVariableW( us_name.Buffer, NULL );
263
264 RtlFreeUnicodeString( &us_name );
265
266 return ret;
267 }
268
269
270 /***********************************************************************
271 * SetEnvironmentVariableW (KERNEL32.@)
272 */
273 BOOL WINAPI SetEnvironmentVariableW( LPCWSTR name, LPCWSTR value )
274 {
275 UNICODE_STRING us_name;
276 NTSTATUS status;
277
278 TRACE("(%s %s)\n", debugstr_w(name), debugstr_w(value));
279
280 if (!name)
281 {
282 SetLastError(ERROR_ENVVAR_NOT_FOUND);
283 return 0;
284 }
285
286 RtlInitUnicodeString(&us_name, name);
287 if (value)
288 {
289 UNICODE_STRING us_value;
290
291 RtlInitUnicodeString(&us_value, value);
292 status = RtlSetEnvironmentVariable(NULL, &us_name, &us_value);
293 }
294 else status = RtlSetEnvironmentVariable(NULL, &us_name, NULL);
295
296 if (status != STATUS_SUCCESS)
297 {
298 SetLastError( RtlNtStatusToDosError(status) );
299 return FALSE;
300 }
301 return TRUE;
302 }
303
304
305 /***********************************************************************
306 * ExpandEnvironmentStringsA (KERNEL32.@)
307 *
308 * See ExpandEnvironmentStringsW.
309 *
310 * Note: overlapping buffers are not supported; this is how it should be.
311 * FIXME: return value is wrong for MBCS
312 */
313 DWORD WINAPI ExpandEnvironmentStringsA( LPCSTR src, LPSTR dst, DWORD count )
314 {
315 UNICODE_STRING us_src;
316 PWSTR dstW = NULL;
317 DWORD ret;
318
319 RtlCreateUnicodeStringFromAsciiz( &us_src, src );
320 if (count)
321 {
322 if (!(dstW = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR))))
323 return 0;
324 ret = ExpandEnvironmentStringsW( us_src.Buffer, dstW, count);
325 if (ret)
326 WideCharToMultiByte( CP_ACP, 0, dstW, ret, dst, count, NULL, NULL );
327 }
328 else ret = ExpandEnvironmentStringsW( us_src.Buffer, NULL, 0);
329
330 RtlFreeUnicodeString( &us_src );
331 HeapFree(GetProcessHeap(), 0, dstW);
332
333 return ret;
334 }
335
336
337 /***********************************************************************
338 * ExpandEnvironmentStringsW (KERNEL32.@)
339 *
340 * Replaces references to environment variables of the form '%EnvVar%'
341 * by their value. If the environment variable does not exist, then the
342 * reference is left as is.
343 *
344 * PARAMS
345 * src [I] The string to be expanded.
346 * dst [O] The buffer in which to put the expanded string.
347 * len [I] The buffer size, in characters.
348 *
349 * RETURNS
350 * The number of characters copied into the buffer. If the buffer is
351 * too small, then the required buffer size, in characters including the
352 * trailing '\0', is returned.
353 * If the function fails for some other reason, then it returns 0.
354 */
355 DWORD WINAPI ExpandEnvironmentStringsW( LPCWSTR src, LPWSTR dst, DWORD len )
356 {
357 UNICODE_STRING us_src;
358 UNICODE_STRING us_dst;
359 NTSTATUS status;
360 DWORD res;
361
362 TRACE("(%s %p %u)\n", debugstr_w(src), dst, len);
363
364 RtlInitUnicodeString(&us_src, src);
365
366 /* make sure we don't overflow the maximum UNICODE_STRING size */
367 if (len > 0x7fff)
368 len = 0x7fff;
369
370 us_dst.Length = 0;
371 us_dst.MaximumLength = len * sizeof(WCHAR);
372 us_dst.Buffer = dst;
373
374 res = 0;
375 status = RtlExpandEnvironmentStrings_U(NULL, &us_src, &us_dst, &res);
376 res /= sizeof(WCHAR);
377 if (status != STATUS_SUCCESS)
378 {
379 SetLastError( RtlNtStatusToDosError(status) );
380 if (status != STATUS_BUFFER_TOO_SMALL) return 0;
381 if (len && dst) dst[len - 1] = '\0';
382 }
383
384 return res;
385 }
386
387
388 /***********************************************************************
389 * GetStdHandle (KERNEL32.@)
390 */
391 HANDLE WINAPI GetStdHandle( DWORD std_handle )
392 {
393 switch (std_handle)
394 {
395 case STD_INPUT_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdInput;
396 case STD_OUTPUT_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdOutput;
397 case STD_ERROR_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdError;
398 }
399 SetLastError( ERROR_INVALID_PARAMETER );
400 return INVALID_HANDLE_VALUE;
401 }
402
403
404 /***********************************************************************
405 * SetStdHandle (KERNEL32.@)
406 */
407 BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
408 {
409 switch (std_handle)
410 {
411 case STD_INPUT_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdInput = handle; return TRUE;
412 case STD_OUTPUT_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdOutput = handle; return TRUE;
413 case STD_ERROR_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdError = handle; return TRUE;
414 }
415 SetLastError( ERROR_INVALID_PARAMETER );
416 return FALSE;
417 }
418
419 /***********************************************************************
420 * GetStartupInfoA (KERNEL32.@)
421 */
422 VOID WINAPI GetStartupInfoA( LPSTARTUPINFOA info )
423 {
424 *info = startup_infoA;
425 }
426
427
428 /***********************************************************************
429 * GetStartupInfoW (KERNEL32.@)
430 */
431 VOID WINAPI GetStartupInfoW( LPSTARTUPINFOW info )
432 {
433 *info = startup_infoW;
434 }
435
436 /******************************************************************
437 * ENV_CopyStartupInformation (internal)
438 *
439 * Creates the STARTUPINFO information from the ntdll information
440 */
441 void ENV_CopyStartupInformation(void)
442 {
443 RTL_USER_PROCESS_PARAMETERS* rupp;
444 ANSI_STRING ansi;
445
446 RtlAcquirePebLock();
447
448 rupp = NtCurrentTeb()->Peb->ProcessParameters;
449
450 startup_infoW.cb = sizeof(startup_infoW);
451 startup_infoW.lpReserved = NULL;
452 startup_infoW.lpDesktop = rupp->Desktop.Buffer;
453 startup_infoW.lpTitle = rupp->WindowTitle.Buffer;
454 startup_infoW.dwX = rupp->dwX;
455 startup_infoW.dwY = rupp->dwY;
456 startup_infoW.dwXSize = rupp->dwXSize;
457 startup_infoW.dwYSize = rupp->dwYSize;
458 startup_infoW.dwXCountChars = rupp->dwXCountChars;
459 startup_infoW.dwYCountChars = rupp->dwYCountChars;
460 startup_infoW.dwFillAttribute = rupp->dwFillAttribute;
461 startup_infoW.dwFlags = rupp->dwFlags;
462 startup_infoW.wShowWindow = rupp->wShowWindow;
463 startup_infoW.cbReserved2 = rupp->RuntimeInfo.MaximumLength;
464 startup_infoW.lpReserved2 = rupp->RuntimeInfo.MaximumLength ? (void*)rupp->RuntimeInfo.Buffer : NULL;
465 startup_infoW.hStdInput = rupp->hStdInput;
466 startup_infoW.hStdOutput = rupp->hStdOutput;
467 startup_infoW.hStdError = rupp->hStdError;
468
469 startup_infoA.cb = sizeof(startup_infoA);
470 startup_infoA.lpReserved = NULL;
471 startup_infoA.lpDesktop = (rupp->Desktop.Length &&
472 RtlUnicodeStringToAnsiString( &ansi, &rupp->Desktop, TRUE) == STATUS_SUCCESS) ?
473 ansi.Buffer : NULL;
474 startup_infoA.lpTitle = (rupp->WindowTitle.Length &&
475 RtlUnicodeStringToAnsiString( &ansi, &rupp->WindowTitle, TRUE) == STATUS_SUCCESS) ?
476 ansi.Buffer : NULL;
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;
489 startup_infoA.hStdOutput = rupp->hStdOutput;
490 startup_infoA.hStdError = rupp->hStdError;
491
492 RtlReleasePebLock();
493 }
494
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.