2 * Ntdll environment functions
4 * Copyright 1996, 1998 Alexandre Julliard
5 * Copyright 2003 Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #define WIN32_NO_STATUS
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
32 #include "ntdll_misc.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(environ
);
37 /******************************************************************************
38 * NtQuerySystemEnvironmentValue [NTDLL.@]
40 NTSYSAPI NTSTATUS WINAPI
NtQuerySystemEnvironmentValue(PUNICODE_STRING VariableName
,
42 ULONG ValueBufferLength
,
43 PULONG RequiredLength
)
45 FIXME("(%s, %p, %u, %p), stub\n", debugstr_us(VariableName
), Value
, ValueBufferLength
, RequiredLength
);
46 return STATUS_NOT_IMPLEMENTED
;
49 /******************************************************************************
50 * NtQuerySystemEnvironmentValueEx [NTDLL.@]
52 NTSYSAPI NTSTATUS WINAPI
NtQuerySystemEnvironmentValueEx(PUNICODE_STRING name
, LPGUID vendor
,
53 PVOID value
, PULONG retlength
, PULONG attrib
)
55 FIXME("(%s, %s, %p, %p, %p), stub\n", debugstr_us(name
), debugstr_guid(vendor
), value
, retlength
, attrib
);
56 return STATUS_NOT_IMPLEMENTED
;
59 /******************************************************************************
60 * RtlCreateEnvironment [NTDLL.@]
62 NTSTATUS WINAPI
RtlCreateEnvironment(BOOLEAN inherit
, PWSTR
* env
)
66 TRACE("(%u,%p)!\n", inherit
, env
);
70 MEMORY_BASIC_INFORMATION mbi
;
74 nts
= NtQueryVirtualMemory(NtCurrentProcess(),
75 NtCurrentTeb()->Peb
->ProcessParameters
->Environment
,
76 0, &mbi
, sizeof(mbi
), NULL
);
77 if (nts
== STATUS_SUCCESS
)
80 nts
= NtAllocateVirtualMemory(NtCurrentProcess(), (void**)env
, 0, &mbi
.RegionSize
,
81 MEM_RESERVE
| MEM_COMMIT
, PAGE_READWRITE
);
82 if (nts
== STATUS_SUCCESS
)
83 memcpy(*env
, NtCurrentTeb()->Peb
->ProcessParameters
->Environment
, mbi
.RegionSize
);
92 nts
= NtAllocateVirtualMemory(NtCurrentProcess(), &addr
, 0, &size
,
93 MEM_RESERVE
| MEM_COMMIT
, PAGE_READWRITE
);
94 if (nts
== STATUS_SUCCESS
) *env
= addr
;
100 /******************************************************************************
101 * RtlDestroyEnvironment [NTDLL.@]
103 NTSTATUS WINAPI
RtlDestroyEnvironment(PWSTR env
)
107 TRACE("(%p)!\n", env
);
109 return NtFreeVirtualMemory(NtCurrentProcess(), (void**)&env
, &size
, MEM_RELEASE
);
112 static LPCWSTR
ENV_FindVariable(PCWSTR var
, PCWSTR name
, unsigned namelen
)
114 for (; *var
; var
+= strlenW(var
) + 1)
116 /* match var names, but avoid setting a var with a name including a '='
117 * (a starting '=' is valid though)
119 if (strncmpiW(var
, name
, namelen
) == 0 && var
[namelen
] == '=' &&
120 strchrW(var
+ 1, '=') == var
+ namelen
)
122 return var
+ namelen
+ 1;
128 /******************************************************************
129 * RtlQueryEnvironmentVariable_U [NTDLL.@]
131 * NOTES: when the buffer is too small, the string is not written, but if the
132 * terminating null char is the only char that cannot be written, then
133 * all chars (except the null) are written and success is returned
134 * (behavior of Win2k at least)
136 NTSTATUS WINAPI
RtlQueryEnvironmentVariable_U(PWSTR env
,
137 PUNICODE_STRING name
,
138 PUNICODE_STRING value
)
140 NTSTATUS nts
= STATUS_VARIABLE_NOT_FOUND
;
144 TRACE("%p %s %p\n", env
, debugstr_us(name
), value
);
147 namelen
= name
->Length
/ sizeof(WCHAR
);
148 if (!namelen
) return nts
;
153 var
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
157 var
= ENV_FindVariable(var
, name
->Buffer
, namelen
);
160 value
->Length
= strlenW(var
) * sizeof(WCHAR
);
162 if (value
->Length
<= value
->MaximumLength
)
164 memmove(value
->Buffer
, var
, min(value
->Length
+ sizeof(WCHAR
), value
->MaximumLength
));
165 nts
= STATUS_SUCCESS
;
167 else nts
= STATUS_BUFFER_TOO_SMALL
;
170 if (!env
) RtlReleasePebLock();
175 /******************************************************************
176 * RtlSetCurrentEnvironment [NTDLL.@]
179 void WINAPI
RtlSetCurrentEnvironment(PWSTR new_env
, PWSTR
* old_env
)
181 TRACE("(%p %p)\n", new_env
, old_env
);
185 if (old_env
) *old_env
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
186 NtCurrentTeb()->Peb
->ProcessParameters
->Environment
= new_env
;
192 /******************************************************************************
193 * RtlSetEnvironmentVariable [NTDLL.@]
195 NTSTATUS WINAPI
RtlSetEnvironmentVariable(PWSTR
* penv
, PUNICODE_STRING name
,
196 PUNICODE_STRING value
)
200 NTSTATUS nts
= STATUS_VARIABLE_NOT_FOUND
;
201 MEMORY_BASIC_INFORMATION mbi
;
203 TRACE("(%p, %s, %s)\n", penv
, debugstr_us(name
), debugstr_us(value
));
205 if (!name
|| !name
->Buffer
|| !name
->Length
)
206 return STATUS_INVALID_PARAMETER_1
;
208 len
= name
->Length
/ sizeof(WCHAR
);
210 /* variable names can't contain a '=' except as a first character */
211 for (p
= name
->Buffer
+ 1; p
< name
->Buffer
+ len
; p
++)
212 if (*p
== '=') return STATUS_INVALID_PARAMETER
;
217 env
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
220 /* compute current size of environment */
221 for (p
= env
; *p
; p
+= strlenW(p
) + 1);
222 old_size
= p
+ 1 - env
;
224 /* Find a place to insert the string */
225 for (p
= env
; *p
; p
+= strlenW(p
) + 1)
227 if (!strncmpiW(name
->Buffer
, p
, len
) && (p
[len
] == '=')) break;
229 if (!value
&& !*p
) goto done
; /* Value to remove doesn't exist */
231 /* Realloc the buffer */
232 len
= value
? len
+ value
->Length
/ sizeof(WCHAR
) + 2 : 0;
233 if (*p
) len
-= strlenW(p
) + 1; /* The name already exists */
237 LPWSTR next
= p
+ strlenW(p
) + 1; /* We know there is a next one */
238 memmove(next
+ len
, next
, (old_size
- (next
- env
)) * sizeof(WCHAR
));
241 nts
= NtQueryVirtualMemory(NtCurrentProcess(), env
, 0,
242 &mbi
, sizeof(mbi
), NULL
);
243 if (nts
!= STATUS_SUCCESS
) goto done
;
245 if ((old_size
+ len
) * sizeof(WCHAR
) > mbi
.RegionSize
)
248 SIZE_T new_size
= (old_size
+ len
) * sizeof(WCHAR
);
251 nts
= NtAllocateVirtualMemory(NtCurrentProcess(), (void**)&new_env
, 0,
252 &new_size
, MEM_RESERVE
| MEM_COMMIT
, PAGE_READWRITE
);
253 if (nts
!= STATUS_SUCCESS
) goto done
;
255 memmove(new_env
, env
, (p
- env
) * sizeof(WCHAR
));
257 memmove(new_env
+ (p
- env
) + len
, p
, (old_size
- (p
- env
)) * sizeof(WCHAR
));
258 p
= new_env
+ (p
- env
);
260 RtlDestroyEnvironment(env
);
261 if (!penv
) NtCurrentTeb()->Peb
->ProcessParameters
->Environment
= new_env
;
262 else *penv
= new_env
;
266 if (len
> 0) memmove(p
+ len
, p
, (old_size
- (p
- env
)) * sizeof(WCHAR
));
269 /* Set the new string */
272 memcpy( p
, name
->Buffer
, name
->Length
);
273 p
+= name
->Length
/ sizeof(WCHAR
);
275 memcpy( p
, value
->Buffer
, value
->Length
);
276 p
[value
->Length
/ sizeof(WCHAR
)] = 0;
279 if (!penv
) RtlReleasePebLock();
284 /******************************************************************************
285 * RtlExpandEnvironmentStrings (NTDLL.@)
287 NTSTATUS WINAPI
RtlExpandEnvironmentStrings( const WCHAR
*renv
, WCHAR
*src
, SIZE_T src_len
,
288 WCHAR
*dst
, SIZE_T count
, SIZE_T
*plen
)
290 SIZE_T len
, total_size
= 1; /* 1 for terminating '\0' */
296 env
= NtCurrentTeb()->Peb
->ProcessParameters
->Environment
;
304 if ((p
= memchrW( src
, '%', src_len
))) len
= p
- src
;
310 else /* we are at the start of a variable */
312 if ((p
= memchrW( src
+ 1, '%', src_len
- 1 )))
314 len
= p
- src
- 1; /* Length of the variable name */
315 if ((var
= ENV_FindVariable( env
, src
+ 1, len
)))
317 src
+= len
+ 2; /* Skip the variable name */
323 var
= src
; /* Copy original name instead */
329 else /* unfinished variable name, ignore it */
332 len
= src_len
; /* Copy whole string */
340 if (count
< len
) len
= count
;
341 memcpy(dst
, var
, len
* sizeof(WCHAR
));
347 if (!renv
) RtlReleasePebLock();
349 if (dst
&& count
) *dst
= '\0';
350 if (plen
) *plen
= total_size
;
352 return (count
) ? STATUS_SUCCESS
: STATUS_BUFFER_TOO_SMALL
;
355 /******************************************************************
356 * RtlExpandEnvironmentStrings_U (NTDLL.@)
358 NTSTATUS WINAPI
RtlExpandEnvironmentStrings_U( const WCHAR
*env
, const UNICODE_STRING
*src
,
359 UNICODE_STRING
*dst
, ULONG
*plen
)
364 ret
= RtlExpandEnvironmentStrings( env
, src
->Buffer
, src
->Length
/ sizeof(WCHAR
),
365 dst
->Buffer
, dst
->MaximumLength
/ sizeof(WCHAR
), &len
);
366 if (plen
) *plen
= len
* sizeof(WCHAR
); /* FIXME: check for overflow? */
367 if (len
> UNICODE_STRING_MAX_CHARS
) ret
= STATUS_BUFFER_TOO_SMALL
;
368 if (!ret
) dst
->Length
= (len
- 1) * sizeof(WCHAR
);
372 static inline void normalize( void *base
, WCHAR
**ptr
)
374 if (*ptr
) *ptr
= (WCHAR
*)((char *)base
+ (UINT_PTR
)*ptr
);
377 /******************************************************************************
378 * RtlNormalizeProcessParams [NTDLL.@]
380 PRTL_USER_PROCESS_PARAMETERS WINAPI
RtlNormalizeProcessParams( RTL_USER_PROCESS_PARAMETERS
*params
)
382 if (params
&& !(params
->Flags
& PROCESS_PARAMS_FLAG_NORMALIZED
))
384 normalize( params
, ¶ms
->CurrentDirectory
.DosPath
.Buffer
);
385 normalize( params
, ¶ms
->DllPath
.Buffer
);
386 normalize( params
, ¶ms
->ImagePathName
.Buffer
);
387 normalize( params
, ¶ms
->CommandLine
.Buffer
);
388 normalize( params
, ¶ms
->WindowTitle
.Buffer
);
389 normalize( params
, ¶ms
->Desktop
.Buffer
);
390 normalize( params
, ¶ms
->ShellInfo
.Buffer
);
391 normalize( params
, ¶ms
->RuntimeInfo
.Buffer
);
392 params
->Flags
|= PROCESS_PARAMS_FLAG_NORMALIZED
;
398 static inline void denormalize( const void *base
, WCHAR
**ptr
)
400 if (*ptr
) *ptr
= (WCHAR
*)(UINT_PTR
)((char *)*ptr
- (const char *)base
);
403 /******************************************************************************
404 * RtlDeNormalizeProcessParams [NTDLL.@]
406 PRTL_USER_PROCESS_PARAMETERS WINAPI
RtlDeNormalizeProcessParams( RTL_USER_PROCESS_PARAMETERS
*params
)
408 if (params
&& (params
->Flags
& PROCESS_PARAMS_FLAG_NORMALIZED
))
410 denormalize( params
, ¶ms
->CurrentDirectory
.DosPath
.Buffer
);
411 denormalize( params
, ¶ms
->DllPath
.Buffer
);
412 denormalize( params
, ¶ms
->ImagePathName
.Buffer
);
413 denormalize( params
, ¶ms
->CommandLine
.Buffer
);
414 denormalize( params
, ¶ms
->WindowTitle
.Buffer
);
415 denormalize( params
, ¶ms
->Desktop
.Buffer
);
416 denormalize( params
, ¶ms
->ShellInfo
.Buffer
);
417 denormalize( params
, ¶ms
->RuntimeInfo
.Buffer
);
418 params
->Flags
&= ~PROCESS_PARAMS_FLAG_NORMALIZED
;
424 #define ROUND_SIZE(size) (((size) + sizeof(void *) - 1) & ~(sizeof(void *) - 1))
426 /* append a unicode string to the process params data; helper for RtlCreateProcessParameters */
427 static void append_unicode_string( void **data
, const UNICODE_STRING
*src
,
428 UNICODE_STRING
*dst
)
430 dst
->Length
= src
->Length
;
431 dst
->MaximumLength
= src
->MaximumLength
;
432 if (dst
->MaximumLength
)
435 memcpy( dst
->Buffer
, src
->Buffer
, dst
->Length
);
436 *data
= (char *)dst
->Buffer
+ ROUND_SIZE( dst
->MaximumLength
);
438 else dst
->Buffer
= NULL
;
442 /******************************************************************************
443 * RtlCreateProcessParametersEx [NTDLL.@]
445 NTSTATUS WINAPI
RtlCreateProcessParametersEx( RTL_USER_PROCESS_PARAMETERS
**result
,
446 const UNICODE_STRING
*ImagePathName
,
447 const UNICODE_STRING
*DllPath
,
448 const UNICODE_STRING
*CurrentDirectoryName
,
449 const UNICODE_STRING
*CommandLine
,
451 const UNICODE_STRING
*WindowTitle
,
452 const UNICODE_STRING
*Desktop
,
453 const UNICODE_STRING
*ShellInfo
,
454 const UNICODE_STRING
*RuntimeInfo
,
457 static WCHAR empty
[] = {0};
458 static const UNICODE_STRING empty_str
= { 0, sizeof(empty
), empty
};
459 static const UNICODE_STRING null_str
= { 0, 0, NULL
};
461 UNICODE_STRING curdir
;
462 const RTL_USER_PROCESS_PARAMETERS
*cur_params
;
463 SIZE_T size
, env_size
;
466 NTSTATUS status
= STATUS_SUCCESS
;
469 cur_params
= NtCurrentTeb()->Peb
->ProcessParameters
;
470 if (!DllPath
) DllPath
= &cur_params
->DllPath
;
471 if (!CurrentDirectoryName
)
473 if (NtCurrentTeb()->Tib
.SubSystemTib
) /* FIXME: hack */
474 curdir
= ((WIN16_SUBSYSTEM_TIB
*)NtCurrentTeb()->Tib
.SubSystemTib
)->curdir
.DosPath
;
476 curdir
= cur_params
->CurrentDirectory
.DosPath
;
478 else curdir
= *CurrentDirectoryName
;
479 curdir
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
481 if (!CommandLine
) CommandLine
= ImagePathName
;
482 if (!Environment
) Environment
= cur_params
->Environment
;
483 if (!WindowTitle
) WindowTitle
= &empty_str
;
484 if (!Desktop
) Desktop
= &empty_str
;
485 if (!ShellInfo
) ShellInfo
= &empty_str
;
486 if (!RuntimeInfo
) RuntimeInfo
= &null_str
;
489 while (*env
) env
+= strlenW(env
) + 1;
491 env_size
= ROUND_SIZE( (env
- Environment
) * sizeof(WCHAR
) );
493 size
= (sizeof(RTL_USER_PROCESS_PARAMETERS
)
494 + ROUND_SIZE( ImagePathName
->MaximumLength
)
495 + ROUND_SIZE( DllPath
->MaximumLength
)
496 + ROUND_SIZE( curdir
.MaximumLength
)
497 + ROUND_SIZE( CommandLine
->MaximumLength
)
498 + ROUND_SIZE( WindowTitle
->MaximumLength
)
499 + ROUND_SIZE( Desktop
->MaximumLength
)
500 + ROUND_SIZE( ShellInfo
->MaximumLength
)
501 + ROUND_SIZE( RuntimeInfo
->MaximumLength
));
503 if ((ptr
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ env_size
)))
505 RTL_USER_PROCESS_PARAMETERS
*params
= ptr
;
506 params
->AllocationSize
= size
;
508 params
->Flags
= PROCESS_PARAMS_FLAG_NORMALIZED
;
509 params
->ConsoleFlags
= cur_params
->ConsoleFlags
;
510 /* all other fields are zero */
513 append_unicode_string( &ptr
, &curdir
, ¶ms
->CurrentDirectory
.DosPath
);
514 append_unicode_string( &ptr
, DllPath
, ¶ms
->DllPath
);
515 append_unicode_string( &ptr
, ImagePathName
, ¶ms
->ImagePathName
);
516 append_unicode_string( &ptr
, CommandLine
, ¶ms
->CommandLine
);
517 append_unicode_string( &ptr
, WindowTitle
, ¶ms
->WindowTitle
);
518 append_unicode_string( &ptr
, Desktop
, ¶ms
->Desktop
);
519 append_unicode_string( &ptr
, ShellInfo
, ¶ms
->ShellInfo
);
520 append_unicode_string( &ptr
, RuntimeInfo
, ¶ms
->RuntimeInfo
);
521 params
->Environment
= ptr
;
522 memcpy( ptr
, Environment
, (env
- Environment
) * sizeof(WCHAR
) );
524 if (!(flags
& PROCESS_PARAMS_FLAG_NORMALIZED
)) RtlDeNormalizeProcessParams( params
);
526 else status
= STATUS_NO_MEMORY
;
533 /******************************************************************************
534 * RtlCreateProcessParameters [NTDLL.@]
536 NTSTATUS WINAPI
RtlCreateProcessParameters( RTL_USER_PROCESS_PARAMETERS
**result
,
537 const UNICODE_STRING
*image
,
538 const UNICODE_STRING
*dllpath
,
539 const UNICODE_STRING
*curdir
,
540 const UNICODE_STRING
*cmdline
,
542 const UNICODE_STRING
*title
,
543 const UNICODE_STRING
*desktop
,
544 const UNICODE_STRING
*shellinfo
,
545 const UNICODE_STRING
*runtime
)
547 return RtlCreateProcessParametersEx( result
, image
, dllpath
, curdir
, cmdline
,
548 env
, title
, desktop
, shellinfo
, runtime
, 0 );
552 /******************************************************************************
553 * RtlDestroyProcessParameters [NTDLL.@]
555 void WINAPI
RtlDestroyProcessParameters( RTL_USER_PROCESS_PARAMETERS
*params
)
557 RtlFreeHeap( GetProcessHeap(), 0, params
);