ReactOS 0.4.17-dev-243-g1369312
env.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/rtl/env.c
5 * PURPOSE: Environment functions
6 * PROGRAMMER: Eric Kohl
7 */
8
9/* INCLUDES ******************************************************************/
10
11#include <rtl.h>
12
13#define NDEBUG
14#include <debug.h>
15
16/* FUNCTIONS *****************************************************************/
17
20RtlSetEnvironmentStrings(_In_ PWCHAR NewEnvironment, _In_ ULONG NewEnvironmentSize)
21{
24}
25
26/*
27 * @implemented
28 */
32 _In_ BOOLEAN Inherit,
33 _Out_ PWSTR *OutEnvironment)
34{
36 PVOID CurrentEnvironment, NewEnvironment = NULL;
39
40 /* Check if we should inherit the current environment */
41 if (Inherit)
42 {
43 /* In this case we need to lock the PEB */
45
46 /* Get a pointer to the current Environment and check if it's not NULL */
47 CurrentEnvironment = NtCurrentPeb()->ProcessParameters->Environment;
48 if (CurrentEnvironment != NULL)
49 {
50 /* Query the size of the current environment allocation */
52 CurrentEnvironment,
54 &MemInfo,
56 NULL);
57 if (!NT_SUCCESS(Status))
58 {
60 *OutEnvironment = NULL;
61 return Status;
62 }
63
64 /* Allocate a new region of the same size */
65 RegionSize = MemInfo.RegionSize;
67 &NewEnvironment,
68 0,
72 if (!NT_SUCCESS(Status))
73 {
75 *OutEnvironment = NULL;
76 return Status;
77 }
78
79 /* Copy the current environment */
80 RtlCopyMemory(NewEnvironment,
81 CurrentEnvironment,
82 MemInfo.RegionSize);
83 }
84
85 /* We are done with the PEB, release the lock */
87 }
88
89 /* Check if we still need an environment */
90 if (NewEnvironment == NULL)
91 {
92 /* Allocate a new environment */
94 &NewEnvironment,
95 0,
99 if (NT_SUCCESS(Status))
100 {
101 RtlZeroMemory(NewEnvironment, RegionSize);
102 }
103 }
104
105 *OutEnvironment = NewEnvironment;
106
107 return Status;
108}
109
110
111/*
112 * @implemented
113 */
114VOID
115NTAPI
117{
118 SIZE_T Size = 0;
119
122 &Size,
124}
125
126
127/*
128 * @implemented
129 */
131NTAPI
134 _In_reads_(SourceLength) PCWSTR SourceBuffer,
135 _In_ SIZE_T SourceLength,
137 _In_ SIZE_T DestMax,
139{
140 UNICODE_STRING Variable;
142 NTSTATUS ReturnStatus = STATUS_SUCCESS;
144 PWSTR DestBuffer;
145 PCWSTR CopyBuffer;
146 PCWSTR VariableEnd;
147 SIZE_T CopyLength;
148 SIZE_T Tail;
149 SIZE_T TotalLength = 1; /* for terminating NULL */
150
151 DPRINT("RtlExpandEnvironmentStrings(%p, %S, %Iu, %p, %Iu, %p)\n",
152 Environment, SourceBuffer, SourceLength, Destination, DestMax, Length);
153
154 DestBuffer = Destination;
155
156 while (SourceLength)
157 {
158 if (*SourceBuffer != L'%')
159 {
160 CopyBuffer = SourceBuffer;
161 CopyLength = 0;
162 while (SourceLength != 0 && *SourceBuffer != L'%')
163 {
164 SourceBuffer++;
165 CopyLength++;
166 SourceLength--;
167 }
168 }
169 else
170 {
171 /* Process environment variable. */
172
173 VariableEnd = SourceBuffer + 1;
174 Tail = SourceLength - 1;
175 while (*VariableEnd != L'%' && Tail != 0)
176 {
177 VariableEnd++;
178 Tail--;
179 }
180
181 if (Tail != 0)
182 {
183 Variable.MaximumLength =
184 Variable.Length = (USHORT)(VariableEnd - (SourceBuffer + 1)) * sizeof(WCHAR);
185 Variable.Buffer = (PWSTR)SourceBuffer + 1;
186
187 Value.Length = 0;
188 Value.MaximumLength = (USHORT)DestMax * sizeof(WCHAR);
189 Value.Buffer = DestBuffer;
190
192 &Value);
194 {
195 SourceBuffer = VariableEnd + 1;
196 SourceLength = Tail - 1;
197 TotalLength += Value.Length / sizeof(WCHAR);
199 {
200 DestBuffer += Value.Length / sizeof(WCHAR);
201 DestMax -= Value.Length / sizeof(WCHAR);
202 }
203 else
204 {
205 DestMax = 0;
206 ReturnStatus = STATUS_BUFFER_TOO_SMALL;
207 }
208 continue;
209 }
210 else
211 {
212 /* Variable not found. */
213 CopyBuffer = SourceBuffer;
214 CopyLength = SourceLength - Tail + 1;
215 SourceLength -= CopyLength;
216 SourceBuffer += CopyLength;
217 }
218 }
219 else
220 {
221 /* Unfinished variable name. */
222 CopyBuffer = SourceBuffer;
223 CopyLength = SourceLength;
224 SourceLength = 0;
225 }
226 }
227
228 TotalLength += CopyLength;
229 if (DestMax)
230 {
231 if (DestMax < CopyLength)
232 {
233 CopyLength = DestMax;
234 ReturnStatus = STATUS_BUFFER_TOO_SMALL;
235 }
236 RtlCopyMemory(DestBuffer, CopyBuffer, CopyLength * sizeof(WCHAR));
237 DestMax -= CopyLength;
238 DestBuffer += CopyLength;
239 }
240 }
241
242 /* NULL-terminate the buffer. */
243 if (DestMax)
244 *DestBuffer = 0;
245 else
246 ReturnStatus = STATUS_BUFFER_TOO_SMALL;
247
248 if (NT_SUCCESS(ReturnStatus))
249 {
250 ASSERT(TotalLength == (DestBuffer - Destination) + 1);
251 //ASSERT(Destination[TotalLength - 1] == UNICODE_NULL);
252 }
253
254 if (Length != NULL)
256
257 DPRINT("Destination %wZ\n", Destination);
258
259 return ReturnStatus;
260}
261
263NTAPI
269{
272
273 DPRINT("RtlExpandEnvironmentStrings_U %p %wZ %p %p\n",
275
276 /* Call the buffer version */
280 SourceString->Length / sizeof(WCHAR),
283 &ResultLength);
284
285 /* Make sure the result length does not exceed the maximum */
287 {
288 DPRINT("ReturnLength %lu exceeds maximum\n", ResultLength);
290 ResultLength = 0;
291 }
292
293 if (NT_SUCCESS(Status))
294 {
296 ((USHORT)ResultLength * sizeof(WCHAR)) - sizeof(UNICODE_NULL);
297 }
298
299 if (ReturnLength != NULL)
300 {
301 *ReturnLength = (ULONG)ResultLength * sizeof(WCHAR);
302 }
303
304 return Status;
305}
306
307/*
308 * @implemented
309 */
310VOID
311NTAPI
313 _In_ PWSTR NewEnvironment,
314 _Out_opt_ PWSTR *OldEnvironment)
315{
316 PVOID EnvPtr;
317
318 DPRINT("NewEnvironment 0x%p OldEnvironment 0x%p\n",
319 NewEnvironment, OldEnvironment);
320
322
323 EnvPtr = NtCurrentPeb()->ProcessParameters->Environment;
324 NtCurrentPeb()->ProcessParameters->Environment = NewEnvironment;
325
326 if (OldEnvironment != NULL)
327 *OldEnvironment = EnvPtr;
328
330}
331
332
333/*
334 * @implemented
335 */
337NTAPI
342{
345 size_t hole_len, new_len, env_len = 0;
346 WCHAR *new_env = 0, *env_end = 0, *wcs, *env, *val = 0, *tail = 0, *hole = 0;
347 PWSTR head = NULL;
348 SIZE_T size = 0, new_size;
349 LONG f = 1;
351
352 DPRINT("RtlSetEnvironmentVariable(Environment %p Name %wZ Value %wZ)\n",
354
355 /* Variable name must not be empty */
356 if (Name->Length < sizeof(WCHAR))
358
359 /* Variable names can't contain a '=' except as a first character. */
360 for (wcs = Name->Buffer + 1;
361 wcs < Name->Buffer + (Name->Length / sizeof(WCHAR));
362 wcs++)
363 {
364 if (*wcs == L'=')
366 }
367
368 if (Environment)
369 {
370 env = *Environment;
371 }
372 else
373 {
375 env = NtCurrentPeb()->ProcessParameters->Environment;
376 }
377
378 if (env)
379 {
380 /* get environment length */
381 wcs = env_end = env;
382 do
383 {
384 env_end += wcslen(env_end) + 1;
385 } while (*env_end);
386 env_end++;
387 env_len = env_end - env;
388 DPRINT("environment length %lu characters\n", env_len);
389
390 /* find where to insert */
391 while (*wcs)
392 {
393 var.Buffer = wcs++;
394 wcs = wcschr(wcs, L'=');
395 if (wcs == NULL)
396 {
397 wcs = var.Buffer + wcslen(var.Buffer);
398 }
399 if (*wcs)
400 {
401 var.Length = (USHORT)(wcs - var.Buffer) * sizeof(WCHAR);
402 var.MaximumLength = var.Length;
403 val = ++wcs;
404 wcs += wcslen(wcs);
406 if (f >= 0)
407 {
408 if (f) /* Insert before found */
409 {
410 hole = tail = var.Buffer;
411 }
412 else /* Exact match */
413 {
414 head = var.Buffer;
415 tail = ++wcs;
416 hole = val;
417 }
418 goto found;
419 }
420 }
421 wcs++;
422 }
423 hole = tail = wcs; /* Append to environment */
424 }
425
426found:
427 if (Value != NULL && Value->Buffer != NULL)
428 {
429 hole_len = tail - hole;
430 /* calculate new environment size */
431 new_size = Value->Length + sizeof(WCHAR);
432 /* adding new variable */
433 if (f)
434 new_size += Name->Length + sizeof(WCHAR);
435 new_len = new_size / sizeof(WCHAR);
436 if (hole_len < new_len)
437 {
438 /* enlarge environment size */
439 /* check the size of available memory */
440 new_size += (env_len - hole_len) * sizeof(WCHAR);
442 mbi.RegionSize = 0;
443 DPRINT("new_size %lu\n", new_size);
444
445 if (env)
446 {
448 env,
450 &mbi,
452 NULL);
453 if (!NT_SUCCESS(Status))
454 {
455 if (Environment == NULL)
456 {
458 }
459 return(Status);
460 }
461 }
462
463 if (new_size > mbi.RegionSize)
464 {
465 /* reallocate memory area */
467 (PVOID)&new_env,
468 0,
469 &new_size,
472 if (!NT_SUCCESS(Status))
473 {
474 if (Environment == NULL)
475 {
477 }
478 return(Status);
479 }
480
481 if (env)
482 {
483 memmove(new_env,
484 env,
485 (hole - env) * sizeof(WCHAR));
486 hole = new_env + (hole - env);
487 }
488 else
489 {
490 /* absolutely new environment */
491 tail = hole = new_env;
492 *hole = 0;
493 env_end = hole + 1;
494 }
495 }
496 }
497
498 /* move tail */
499 memmove (hole + new_len, tail, (env_end - tail) * sizeof(WCHAR));
500
501 if (new_env)
502 {
503 /* we reallocated environment, let's free the old one */
504 if (Environment)
505 *Environment = new_env;
506 else
507 NtCurrentPeb()->ProcessParameters->Environment = new_env;
508
509 if (env)
510 {
511 size = 0;
513 (PVOID)&env,
514 &size,
516 }
517 }
518
519 /* and now copy given stuff */
520 if (f)
521 {
522 /* copy variable name and '=' character */
523 memmove(hole,
524 Name->Buffer,
525 Name->Length);
526 hole += Name->Length / sizeof(WCHAR);
527 *hole++ = L'=';
528 }
529
530 /* copy value */
531 memmove(hole,
532 Value->Buffer,
533 Value->Length);
534 hole += Value->Length / sizeof(WCHAR);
535 *hole = 0;
536 }
537 else
538 {
539 /* remove the environment variable */
540 if (f == 0)
541 {
543 tail,
544 (env_end - tail) * sizeof(WCHAR));
545 }
546 }
547
548 if (Environment == NULL)
549 {
551 }
552
553 return(Status);
554}
555
556
557/*
558 * @implemented
559 */
561NTAPI
564 _In_reads_(NameLength) PWSTR Name,
565 _In_ SIZE_T NameLength,
569{
571 PWSTR wcs;
572 PWSTR varName;
573 SIZE_T varNameLen;
574 PWSTR val;
575 BOOLEAN SysEnvUsed = FALSE;
576
577 DPRINT("RtlQueryEnvironmentVariable_U Environment %p Variable %wZ Value %p\n",
579
580 if (Environment == NULL)
581 {
583 if (Peb)
584 {
587 SysEnvUsed = TRUE;
588 }
589 }
590
591 if (Environment == NULL)
592 {
593 if (SysEnvUsed)
596 }
597
598 *ReturnLength = 0;
599
601 DPRINT("Starting search at :%p\n", wcs);
602 while (*wcs)
603 {
604 varName = wcs++;
605 wcs = wcschr(wcs, L'=');
606 if (wcs == NULL)
607 {
608 wcs = varName + wcslen(varName);
609 DPRINT("Search at :%S\n", wcs);
610 }
611 if (*wcs)
612 {
613 varNameLen = (wcs - varName);
614 val = ++wcs;
615 wcs += wcslen(wcs);
616 DPRINT("Search at :%S\n", wcs);
617
618 if ((varNameLen == NameLength) && _wcsnicmp(varName, Name, NameLength) == 0)
619 {
620 *ReturnLength = (wcs - val);
622 {
623 memcpy(Value, val, (*ReturnLength + 1) * sizeof(WCHAR));
624 DPRINT("Value %S\n", val);
625 DPRINT("Return STATUS_SUCCESS\n");
627 }
628 else
629 {
630 if (ValueLength > 0)
631 Value[0] = UNICODE_NULL;
632 DPRINT("Return STATUS_BUFFER_TOO_SMALL\n");
633 *ReturnLength += 1;
635 }
636
637 if (SysEnvUsed)
639
640 return Status;
641 }
642 }
643
644 wcs++;
645 }
646
647 if (SysEnvUsed)
649
650 DPRINT("Return STATUS_VARIABLE_NOT_FOUND: %wZ\n", Name);
652}
653
654/*
655 * @implemented
656 */
658NTAPI
663{
666
668 Name->Buffer,
669 Name->Length / sizeof(WCHAR),
670 Value->Buffer,
671 Value->MaximumLength / sizeof(WCHAR),
672 &ReturnLength);
673
675 {
676 return STATUS_UNSUCCESSFUL;
677 }
678
679 /* Correct for extra length returned by RtlQueryEnvironmentVariable */
681 {
682 ReturnLength -= 1;
683 }
684
685 Value->Length = (USHORT)ReturnLength * sizeof(WCHAR);
686 return Status;
687}
688
689/* EOF */
#define NtCurrentPeb()
Definition: FLS.c:22
_In_ PVOID _In_ ULONG _Out_ PVOID _In_ ULONG _Inout_ PULONG ReturnLength
unsigned char BOOLEAN
Definition: actypes.h:127
struct outqueuenode * tail
Definition: adnsresfilter.c:66
struct outqueuenode * head
Definition: adnsresfilter.c:66
LONG NTSTATUS
Definition: precomp.h:26
#define UNIMPLEMENTED
Definition: ntoskrnl.c:15
Definition: bufpool.h:45
#define STATUS_NOT_IMPLEMENTED
Definition: d3dkmdt.h:42
static LPCWSTR LPCWSTR LPCWSTR env
Definition: db.cpp:171
LPWSTR Name
Definition: desk.c:124
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define wcschr
Definition: compat.h:17
PPEB Peb
Definition: dllmain.c:27
_ACRTIMP size_t __cdecl wcslen(const wchar_t *)
Definition: wcs.c:2983
_ACRTIMP int __cdecl _wcsnicmp(const wchar_t *, const wchar_t *, size_t)
Definition: wcs.c:195
#define L(x)
Definition: resources.c:13
ULONG RtlCompareUnicodeString(PUNICODE_STRING s1, PUNICODE_STRING s2, BOOLEAN UpCase)
Definition: string_lib.cpp:31
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
size_t const new_size
Definition: expand.cpp:66
Status
Definition: gdiplustypes.h:24
GLsizeiptr size
Definition: glext.h:5919
GLfloat f
Definition: glext.h:7540
GLuint GLfloat * val
Definition: glext.h:7180
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define ASSERT(a)
Definition: mode.c:44
PVOID PVOID PWCHAR PVOID Environment
Definition: env.c:47
const char * var
Definition: shader.c:5666
static const UNICODE_STRING const UNICODE_STRING const UNICODE_STRING const UNICODE_STRING PWSTR
Definition: env.c:38
__kernel_entry _Inout_ _Inout_ PSIZE_T RegionSize
Definition: mmfuncs.h:172
@ MemoryBasicInformation
Definition: mmtypes.h:183
_Out_ _Inout_ POEM_STRING _In_ PCUNICODE_STRING SourceString
Definition: rtlfuncs.h:1957
NTSYSAPI NTSTATUS NTAPI RtlSetEnvironmentVariable(_In_z_ PWSTR *Environment, _In_ PUNICODE_STRING Name, _In_ PUNICODE_STRING Value)
Definition: env.c:338
NTSYSAPI NTSTATUS NTAPI RtlCreateEnvironment(_In_ BOOLEAN Inherit, _Out_ PWSTR *Environment)
Definition: env.c:31
NTSYSAPI VOID NTAPI RtlDestroyEnvironment(_In_ PWSTR Environment)
Definition: env.c:116
_In_ PUNICODE_STRING _Inout_ PUNICODE_STRING Destination
Definition: rtlfuncs.h:3051
_Out_ _Inout_ POEM_STRING DestinationString
Definition: rtlfuncs.h:1956
NTSYSAPI NTSTATUS NTAPI RtlQueryEnvironmentVariable_U(_In_opt_ PWSTR Environment, _In_ PCUNICODE_STRING Name, _Out_ PUNICODE_STRING Value)
Definition: env.c:659
#define _In_reads_(s)
Definition: no_sal2.h:168
#define _Out_opt_
Definition: no_sal2.h:214
#define _Inout_
Definition: no_sal2.h:162
#define _In_z_
Definition: no_sal2.h:164
#define _Out_writes_(s)
Definition: no_sal2.h:176
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
#define PAGE_READWRITE
Definition: nt_native.h:1307
#define NtCurrentProcess()
Definition: nt_native.h:1660
#define MEM_RESERVE
Definition: nt_native.h:1317
#define MEM_RELEASE
Definition: nt_native.h:1319
#define MEM_COMMIT
Definition: nt_native.h:1316
#define UNICODE_NULL
#define UNICODE_STRING_MAX_CHARS
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
NTSTATUS NTAPI NtFreeVirtualMemory(IN HANDLE ProcessHandle, IN PVOID *UBaseAddress, IN PSIZE_T URegionSize, IN ULONG FreeType)
Definition: virtual.c:5192
NTSTATUS NTAPI NtQueryVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN MEMORY_INFORMATION_CLASS MemoryInformationClass, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength)
Definition: virtual.c:4374
NTSTATUS NTAPI NtAllocateVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID *UBaseAddress, IN ULONG_PTR ZeroBits, IN OUT PSIZE_T URegionSize, IN ULONG AllocationType, IN ULONG Protect)
Definition: virtual.c:4457
#define STATUS_VARIABLE_NOT_FOUND
Definition: ntstatus.h:586
short WCHAR
Definition: pedump.c:58
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
NTSTATUS NTAPI RtlQueryEnvironmentVariable(_In_opt_ PVOID Environment, _In_reads_(NameLength) PWSTR Name, _In_ SIZE_T NameLength, _Out_writes_(ValueLength) PWSTR Value, _In_ SIZE_T ValueLength, _Out_ PSIZE_T ReturnLength)
Definition: env.c:562
NTSTATUS NTAPI RtlSetEnvironmentStrings(_In_ PWCHAR NewEnvironment, _In_ ULONG NewEnvironmentSize)
Definition: env.c:20
NTSTATUS NTAPI RtlExpandEnvironmentStrings(_In_opt_ PVOID Environment, _In_reads_(SourceLength) PCWSTR SourceBuffer, _In_ SIZE_T SourceLength, _Out_writes_(DestMax) PWSTR Destination, _In_ SIZE_T DestMax, _Out_opt_ PSIZE_T Length)
Definition: env.c:132
NTSTATUS NTAPI RtlExpandEnvironmentStrings_U(_In_opt_ PWSTR Environment, _In_ PUNICODE_STRING SourceString, _Inout_ PUNICODE_STRING DestinationString, _In_ PULONG ReturnLength)
Definition: env.c:264
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define DPRINT
Definition: sndvol32.h:73
PRTL_USER_PROCESS_PARAMETERS ProcessParameters
Definition: btrfs_drv.h:1913
unsigned short Length
Definition: sprintf.c:451
void * Buffer
Definition: sprintf.c:453
unsigned short MaximumLength
Definition: sprintf.c:452
USHORT MaximumLength
Definition: env_spec_w32.h:370
ULONG_PTR * PSIZE_T
Definition: typedefs.h:80
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t * PULONG
Definition: typedefs.h:59
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define NTAPI
Definition: typedefs.h:36
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint16_t * PWCHAR
Definition: typedefs.h:56
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
_In_ ULONG TotalLength
Definition: usbdlib.h:158
wchar_t wcs[5]
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG _Out_ PULONG ResultLength
Definition: wdfdevice.h:3782
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4539
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG ValueLength
Definition: wdfregistry.h:275
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
NTSYSAPI void WINAPI RtlReleasePebLock(void)
Definition: libsupp.c:84
NTSYSAPI void WINAPI RtlAcquirePebLock(void)
Definition: libsupp.c:74
NTSYSAPI PEB *WINAPI RtlGetCurrentPeb(void)
Definition: libsupp.c:65
NTSYSAPI void WINAPI RtlSetCurrentEnvironment(PWSTR, PWSTR *)