xref: /reactos/dll/win32/userenv/environment.c (revision 2b7246fd)
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2004 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * COPYRIGHT:       See COPYING in the top level directory
21  * PROJECT:         ReactOS system libraries
22  * FILE:            dll/win32/userenv/environment.c
23  * PURPOSE:         User environment functions
24  * PROGRAMMER:      Eric Kohl
25  */
26 
27 #include "precomp.h"
28 
29 #define NDEBUG
30 #include <debug.h>
31 
32 static
33 BOOL
34 SetUserEnvironmentVariable(PWSTR* Environment,
35                            LPWSTR lpName,
36                            LPWSTR lpValue,
37                            BOOL bExpand)
38 {
39     NTSTATUS Status;
40     UNICODE_STRING Name;
41     UNICODE_STRING SrcValue, DstValue;
42     ULONG Length;
43     PVOID Buffer = NULL;
44     WCHAR ShortName[MAX_PATH];
45 
46     if (bExpand)
47     {
48         RtlInitUnicodeString(&SrcValue, lpValue);
49 
50         Length = 2 * MAX_PATH * sizeof(WCHAR);
51 
52         DstValue.Length = 0;
53         DstValue.MaximumLength = Length;
54         DstValue.Buffer = Buffer = LocalAlloc(LPTR, Length);
55         if (DstValue.Buffer == NULL)
56         {
57             DPRINT1("LocalAlloc() failed\n");
58             return FALSE;
59         }
60 
61         Status = RtlExpandEnvironmentStrings_U(*Environment,
62                                                &SrcValue,
63                                                &DstValue,
64                                                &Length);
65         if (!NT_SUCCESS(Status))
66         {
67             DPRINT1("RtlExpandEnvironmentStrings_U() failed (Status %lx)\n", Status);
68             DPRINT1("Length %lu\n", Length);
69 
70             if (Buffer)
71                 LocalFree(Buffer);
72 
73             return FALSE;
74         }
75     }
76     else
77     {
78         RtlInitUnicodeString(&DstValue, lpValue);
79     }
80 
81     if (!_wcsicmp(lpName, L"TEMP") || !_wcsicmp(lpName, L"TMP"))
82     {
83         if (GetShortPathNameW(DstValue.Buffer, ShortName, ARRAYSIZE(ShortName)))
84         {
85             RtlInitUnicodeString(&DstValue, ShortName);
86         }
87         else
88         {
89             DPRINT("GetShortPathNameW() failed for %S (Error %lu)\n", DstValue.Buffer, GetLastError());
90         }
91     }
92 
93     RtlInitUnicodeString(&Name, lpName);
94 
95     DPRINT("Value: %wZ\n", &DstValue);
96 
97     Status = RtlSetEnvironmentVariable(Environment,
98                                        &Name,
99                                        &DstValue);
100 
101     if (Buffer)
102         LocalFree(Buffer);
103 
104     if (!NT_SUCCESS(Status))
105     {
106         DPRINT1("RtlSetEnvironmentVariable() failed (Status %lx)\n", Status);
107         return FALSE;
108     }
109 
110     return TRUE;
111 }
112 
113 
114 static
115 BOOL
116 AppendUserEnvironmentVariable(PWSTR* Environment,
117                               LPWSTR lpName,
118                               LPWSTR lpValue)
119 {
120     NTSTATUS Status;
121     UNICODE_STRING Name, Value;
122 
123     RtlInitUnicodeString(&Name, lpName);
124 
125     Value.Length = 0;
126     Value.MaximumLength = 1024 * sizeof(WCHAR);
127     Value.Buffer = LocalAlloc(LPTR, Value.MaximumLength);
128     if (Value.Buffer == NULL)
129         return FALSE;
130 
131     Value.Buffer[0] = UNICODE_NULL;
132 
133     Status = RtlQueryEnvironmentVariable_U(*Environment,
134                                            &Name,
135                                            &Value);
136     if (NT_SUCCESS(Status))
137         RtlAppendUnicodeToString(&Value, L";");
138 
139     RtlAppendUnicodeToString(&Value, lpValue);
140 
141     Status = RtlSetEnvironmentVariable(Environment,
142                                        &Name,
143                                        &Value);
144     LocalFree(Value.Buffer);
145     if (!NT_SUCCESS(Status))
146     {
147         DPRINT1("RtlSetEnvironmentVariable() failed (Status %lx)\n", Status);
148         return FALSE;
149     }
150 
151     return TRUE;
152 }
153 
154 
155 static
156 HKEY
157 GetCurrentUserKey(HANDLE hToken)
158 {
159     LONG Error;
160     UNICODE_STRING SidString;
161     HKEY hKey;
162 
163     if (!GetUserSidStringFromToken(hToken, &SidString))
164     {
165         DPRINT1("GetUserSidFromToken() failed\n");
166         return NULL;
167     }
168 
169     Error = RegOpenKeyExW(HKEY_USERS,
170                           SidString.Buffer,
171                           0,
172                           MAXIMUM_ALLOWED,
173                           &hKey);
174     if (Error != ERROR_SUCCESS)
175     {
176         DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
177         RtlFreeUnicodeString(&SidString);
178         SetLastError((DWORD)Error);
179         return NULL;
180     }
181 
182     RtlFreeUnicodeString(&SidString);
183 
184     return hKey;
185 }
186 
187 
188 static
189 BOOL
190 GetUserAndDomainName(IN HANDLE hToken,
191                      OUT LPWSTR *UserName,
192                      OUT LPWSTR *DomainName)
193 {
194     BOOL bRet = TRUE;
195     PSID Sid = NULL;
196     LPWSTR lpUserName = NULL;
197     LPWSTR lpDomainName = NULL;
198     DWORD cbUserName = 0;
199     DWORD cbDomainName = 0;
200     SID_NAME_USE SidNameUse;
201 
202     Sid = GetUserSid(hToken);
203     if (Sid == NULL)
204     {
205         DPRINT1("GetUserSid() failed\n");
206         return FALSE;
207     }
208 
209     if (!LookupAccountSidW(NULL,
210                            Sid,
211                            NULL,
212                            &cbUserName,
213                            NULL,
214                            &cbDomainName,
215                            &SidNameUse))
216     {
217         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
218         {
219             bRet = FALSE;
220             goto done;
221         }
222     }
223 
224     lpUserName = LocalAlloc(LPTR, cbUserName * sizeof(WCHAR));
225     if (lpUserName == NULL)
226     {
227         bRet = FALSE;
228         goto done;
229     }
230 
231     lpDomainName = LocalAlloc(LPTR, cbDomainName * sizeof(WCHAR));
232     if (lpDomainName == NULL)
233     {
234         bRet = FALSE;
235         goto done;
236     }
237 
238     if (!LookupAccountSidW(NULL,
239                            Sid,
240                            lpUserName,
241                            &cbUserName,
242                            lpDomainName,
243                            &cbDomainName,
244                            &SidNameUse))
245     {
246         bRet = FALSE;
247         goto done;
248     }
249 
250     *UserName = lpUserName;
251     *DomainName = lpDomainName;
252 
253 done:
254     if (bRet == FALSE)
255     {
256         if (lpUserName != NULL)
257             LocalFree(lpUserName);
258 
259         if (lpDomainName != NULL)
260             LocalFree(lpDomainName);
261     }
262 
263     LocalFree(Sid);
264 
265     return bRet;
266 }
267 
268 
269 static
270 BOOL
271 SetUserEnvironment(PWSTR* Environment,
272                    HKEY hKey,
273                    LPWSTR lpSubKeyName)
274 {
275     LONG Error;
276     HKEY hEnvKey;
277     DWORD dwValues;
278     DWORD dwMaxValueNameLength;
279     DWORD dwMaxValueDataLength;
280     DWORD dwValueNameLength;
281     DWORD dwValueDataLength;
282     DWORD dwType;
283     DWORD i;
284     LPWSTR lpValueName;
285     LPWSTR lpValueData;
286 
287     Error = RegOpenKeyExW(hKey,
288                           lpSubKeyName,
289                           0,
290                           KEY_QUERY_VALUE,
291                           &hEnvKey);
292     if (Error != ERROR_SUCCESS)
293     {
294         DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
295         SetLastError((DWORD)Error);
296         return FALSE;
297     }
298 
299     Error = RegQueryInfoKey(hEnvKey,
300                             NULL,
301                             NULL,
302                             NULL,
303                             NULL,
304                             NULL,
305                             NULL,
306                             &dwValues,
307                             &dwMaxValueNameLength,
308                             &dwMaxValueDataLength,
309                             NULL,
310                             NULL);
311     if (Error != ERROR_SUCCESS)
312     {
313         DPRINT1("RegQueryInforKey() failed (Error %ld)\n", Error);
314         RegCloseKey(hEnvKey);
315         SetLastError((DWORD)Error);
316         return FALSE;
317     }
318 
319     if (dwValues == 0)
320     {
321         RegCloseKey(hEnvKey);
322         return TRUE;
323     }
324 
325     /* Allocate buffers */
326     dwMaxValueNameLength++;
327     lpValueName = LocalAlloc(LPTR, dwMaxValueNameLength * sizeof(WCHAR));
328     if (lpValueName == NULL)
329     {
330         RegCloseKey(hEnvKey);
331         return FALSE;
332     }
333 
334     lpValueData = LocalAlloc(LPTR, dwMaxValueDataLength);
335     if (lpValueData == NULL)
336     {
337         LocalFree(lpValueName);
338         RegCloseKey(hEnvKey);
339         return FALSE;
340     }
341 
342     /* Enumerate values */
343     for (i = 0; i < dwValues; i++)
344     {
345         dwValueNameLength = dwMaxValueNameLength;
346         dwValueDataLength = dwMaxValueDataLength;
347 
348         Error = RegEnumValueW(hEnvKey,
349                               i,
350                               lpValueName,
351                               &dwValueNameLength,
352                               NULL,
353                               &dwType,
354                               (LPBYTE)lpValueData,
355                               &dwValueDataLength);
356         if (Error == ERROR_SUCCESS)
357         {
358             if (!_wcsicmp(lpValueName, L"PATH"))
359             {
360                 /* Append 'Path' environment variable */
361                 AppendUserEnvironmentVariable(Environment,
362                                               lpValueName,
363                                               lpValueData);
364             }
365             else
366             {
367                 /* Set environment variable */
368                 SetUserEnvironmentVariable(Environment,
369                                            lpValueName,
370                                            lpValueData,
371                                            (dwType == REG_EXPAND_SZ));
372             }
373         }
374         else
375         {
376             LocalFree(lpValueData);
377             LocalFree(lpValueName);
378             RegCloseKey(hEnvKey);
379 
380             return FALSE;
381         }
382     }
383 
384     LocalFree(lpValueData);
385     LocalFree(lpValueName);
386     RegCloseKey(hEnvKey);
387 
388     return TRUE;
389 }
390 
391 
392 static
393 BOOL
394 SetSystemEnvironment(PWSTR* Environment)
395 {
396     LONG Error;
397     HKEY hEnvKey;
398     DWORD dwValues;
399     DWORD dwMaxValueNameLength;
400     DWORD dwMaxValueDataLength;
401     DWORD dwValueNameLength;
402     DWORD dwValueDataLength;
403     DWORD dwType;
404     DWORD i;
405     LPWSTR lpValueName;
406     LPWSTR lpValueData;
407 
408     Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
409                           L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",
410                           0,
411                           KEY_QUERY_VALUE,
412                           &hEnvKey);
413     if (Error != ERROR_SUCCESS)
414     {
415         DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
416         return FALSE;
417     }
418 
419     Error = RegQueryInfoKey(hEnvKey,
420                             NULL,
421                             NULL,
422                             NULL,
423                             NULL,
424                             NULL,
425                             NULL,
426                             &dwValues,
427                             &dwMaxValueNameLength,
428                             &dwMaxValueDataLength,
429                             NULL,
430                             NULL);
431     if (Error != ERROR_SUCCESS)
432     {
433         DPRINT1("RegQueryInforKey() failed (Error %ld)\n", Error);
434         RegCloseKey(hEnvKey);
435         return FALSE;
436     }
437 
438     if (dwValues == 0)
439     {
440         RegCloseKey(hEnvKey);
441         return TRUE;
442     }
443 
444     /* Allocate buffers */
445     dwMaxValueNameLength++;
446     lpValueName = LocalAlloc(LPTR, dwMaxValueNameLength * sizeof(WCHAR));
447     if (lpValueName == NULL)
448     {
449         RegCloseKey(hEnvKey);
450         return FALSE;
451     }
452 
453     lpValueData = LocalAlloc(LPTR, dwMaxValueDataLength);
454     if (lpValueData == NULL)
455     {
456         LocalFree(lpValueName);
457         RegCloseKey(hEnvKey);
458         return FALSE;
459     }
460 
461     /* Enumerate values */
462     for (i = 0; i < dwValues; i++)
463     {
464         dwValueNameLength = dwMaxValueNameLength;
465         dwValueDataLength = dwMaxValueDataLength;
466 
467         Error = RegEnumValueW(hEnvKey,
468                               i,
469                               lpValueName,
470                               &dwValueNameLength,
471                               NULL,
472                               &dwType,
473                               (LPBYTE)lpValueData,
474                               &dwValueDataLength);
475         if (Error == ERROR_SUCCESS)
476         {
477             /* Set environment variable */
478             SetUserEnvironmentVariable(Environment,
479                                        lpValueName,
480                                        lpValueData,
481                                        (dwType == REG_EXPAND_SZ));
482         }
483         else
484         {
485             LocalFree(lpValueData);
486             LocalFree(lpValueName);
487             RegCloseKey(hEnvKey);
488 
489             return FALSE;
490         }
491     }
492 
493     LocalFree(lpValueData);
494     LocalFree(lpValueName);
495     RegCloseKey(hEnvKey);
496 
497     return TRUE;
498 }
499 
500 
501 BOOL
502 WINAPI
503 CreateEnvironmentBlock(OUT LPVOID *lpEnvironment,
504                        IN HANDLE hToken,
505                        IN BOOL bInherit)
506 {
507     NTSTATUS Status;
508     LONG lError;
509     PWSTR* Environment = (PWSTR*)lpEnvironment;
510     DWORD Length;
511     DWORD dwType;
512     HKEY hKey;
513     HKEY hKeyUser;
514     LPWSTR lpUserName = NULL;
515     LPWSTR lpDomainName = NULL;
516     WCHAR Buffer[MAX_PATH];
517     WCHAR szValue[1024];
518 
519     DPRINT("CreateEnvironmentBlock() called\n");
520 
521     if (lpEnvironment == NULL)
522     {
523         SetLastError(ERROR_INVALID_PARAMETER);
524         return FALSE;
525     }
526 
527     Status = RtlCreateEnvironment((BOOLEAN)bInherit, Environment);
528     if (!NT_SUCCESS(Status))
529     {
530         DPRINT1("RtlCreateEnvironment() failed (Status %lx)\n", Status);
531         SetLastError(RtlNtStatusToDosError(Status));
532         return FALSE;
533     }
534 
535     /* Set 'SystemRoot' variable */
536     Length = ARRAYSIZE(Buffer);
537     if (GetEnvironmentVariableW(L"SystemRoot", Buffer, Length))
538     {
539         SetUserEnvironmentVariable(Environment,
540                                    L"SystemRoot",
541                                    Buffer,
542                                    FALSE);
543     }
544 
545     /* Set 'SystemDrive' variable */
546     if (GetEnvironmentVariableW(L"SystemDrive", Buffer, Length))
547     {
548         SetUserEnvironmentVariable(Environment,
549                                    L"SystemDrive",
550                                    Buffer,
551                                    FALSE);
552     }
553 
554     /* Set variables from Session Manager */
555     if (!SetSystemEnvironment(Environment))
556     {
557         RtlDestroyEnvironment(*Environment);
558         return FALSE;
559     }
560 
561     /* Set 'COMPUTERNAME' variable */
562     Length = ARRAYSIZE(Buffer);
563     if (GetComputerNameW(Buffer, &Length))
564     {
565         SetUserEnvironmentVariable(Environment,
566                                    L"COMPUTERNAME",
567                                    Buffer,
568                                    FALSE);
569     }
570 
571     /* Set 'ALLUSERSPROFILE' variable */
572     Length = ARRAYSIZE(Buffer);
573     if (GetAllUsersProfileDirectoryW(Buffer, &Length))
574     {
575         SetUserEnvironmentVariable(Environment,
576                                    L"ALLUSERSPROFILE",
577                                    Buffer,
578                                    FALSE);
579     }
580 
581     /* Set 'USERPROFILE' variable to the default users profile */
582     Length = ARRAYSIZE(Buffer);
583     if (GetDefaultUserProfileDirectoryW(Buffer, &Length))
584     {
585         SetUserEnvironmentVariable(Environment,
586                                    L"USERPROFILE",
587                                    Buffer,
588                                    TRUE);
589     }
590 
591     lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
592                            L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
593                            0,
594                            KEY_READ,
595                            &hKey);
596     if (lError == ERROR_SUCCESS)
597     {
598         Length = sizeof(szValue);
599         lError = RegQueryValueExW(hKey,
600                                   L"ProgramFilesDir",
601                                   NULL,
602                                   &dwType,
603                                   (LPBYTE)szValue,
604                                   &Length);
605         if (lError == ERROR_SUCCESS)
606         {
607             SetUserEnvironmentVariable(Environment,
608                                        L"ProgramFiles",
609                                        szValue,
610                                        FALSE);
611         }
612 
613         Length = sizeof(szValue);
614         lError = RegQueryValueExW(hKey,
615                                   L"CommonFilesDir",
616                                   NULL,
617                                   &dwType,
618                                   (LPBYTE)szValue,
619                                   &Length);
620         if (lError == ERROR_SUCCESS)
621         {
622             SetUserEnvironmentVariable(Environment,
623                                        L"CommonProgramFiles",
624                                        szValue,
625                                        FALSE);
626         }
627 
628         RegCloseKey(hKey);
629     }
630 
631     /*
632      * If no user token is specified, the system environment variables are set
633      * and we stop here, otherwise continue setting the user-specific variables.
634      */
635     if (hToken == NULL)
636         return TRUE;
637 
638     hKeyUser = GetCurrentUserKey(hToken);
639     if (hKeyUser == NULL)
640     {
641         DPRINT1("GetCurrentUserKey() failed\n");
642         RtlDestroyEnvironment(*Environment);
643         return FALSE;
644     }
645 
646     /* Set 'USERPROFILE' variable */
647     Length = ARRAYSIZE(Buffer);
648     if (GetUserProfileDirectoryW(hToken, Buffer, &Length))
649     {
650         DWORD MinLen = 2;
651 
652         SetUserEnvironmentVariable(Environment,
653                                    L"USERPROFILE",
654                                    Buffer,
655                                    FALSE);
656 
657         // FIXME: Strangely enough the following two environment variables
658         // are not set by userenv.dll in Windows... See r68284 / CORE-9875
659         // FIXME2: This is done by msgina.dll !!
660 
661         /* At least <drive letter>:<path> */
662         if (Length > MinLen)
663         {
664             /* Set 'HOMEDRIVE' variable */
665             StringCchCopyNW(szValue, ARRAYSIZE(Buffer), Buffer, MinLen);
666             SetUserEnvironmentVariable(Environment,
667                                        L"HOMEDRIVE",
668                                        szValue,
669                                        FALSE);
670 
671             /* Set 'HOMEPATH' variable */
672             StringCchCopyNW(szValue, ARRAYSIZE(Buffer), Buffer + MinLen, Length - MinLen);
673             SetUserEnvironmentVariable(Environment,
674                                        L"HOMEPATH",
675                                        szValue,
676                                        FALSE);
677         }
678     }
679     else
680     {
681         DPRINT1("GetUserProfileDirectoryW failed with error %lu\n", GetLastError());
682     }
683 
684     if (GetUserAndDomainName(hToken,
685                              &lpUserName,
686                              &lpDomainName))
687     {
688         /* Set 'USERNAME' variable */
689         SetUserEnvironmentVariable(Environment,
690                                    L"USERNAME",
691                                    lpUserName,
692                                    FALSE);
693 
694         /* Set 'USERDOMAIN' variable */
695         SetUserEnvironmentVariable(Environment,
696                                    L"USERDOMAIN",
697                                    lpDomainName,
698                                    FALSE);
699 
700         if (lpUserName != NULL)
701             LocalFree(lpUserName);
702 
703         if (lpDomainName != NULL)
704             LocalFree(lpDomainName);
705     }
706 
707     /* Set user environment variables */
708     SetUserEnvironment(Environment,
709                        hKeyUser,
710                        L"Environment");
711 
712     /* Set user volatile environment variables */
713     SetUserEnvironment(Environment,
714                        hKeyUser,
715                        L"Volatile Environment");
716 
717     RegCloseKey(hKeyUser);
718 
719     return TRUE;
720 }
721 
722 
723 BOOL
724 WINAPI
725 DestroyEnvironmentBlock(IN LPVOID lpEnvironment)
726 {
727     DPRINT("DestroyEnvironmentBlock() called\n");
728 
729     if (lpEnvironment == NULL)
730     {
731         SetLastError(ERROR_INVALID_PARAMETER);
732         return FALSE;
733     }
734 
735     RtlDestroyEnvironment(lpEnvironment);
736 
737     return TRUE;
738 }
739 
740 
741 BOOL
742 WINAPI
743 ExpandEnvironmentStringsForUserW(IN HANDLE hToken,
744                                  IN LPCWSTR lpSrc,
745                                  OUT LPWSTR lpDest,
746                                  IN DWORD dwSize)
747 {
748     BOOL Ret = FALSE;
749     PVOID lpEnvironment;
750 
751     if (lpSrc == NULL || lpDest == NULL || dwSize == 0)
752     {
753         SetLastError(ERROR_INVALID_PARAMETER);
754         return FALSE;
755     }
756 
757     if (CreateEnvironmentBlock(&lpEnvironment,
758                                hToken,
759                                FALSE))
760     {
761         UNICODE_STRING SrcU, DestU;
762         NTSTATUS Status;
763 
764         /* Initialize the strings */
765         RtlInitUnicodeString(&SrcU, lpSrc);
766         DestU.Length = 0;
767         DestU.MaximumLength = dwSize * sizeof(WCHAR);
768         DestU.Buffer = lpDest;
769 
770         /* Expand the strings */
771         Status = RtlExpandEnvironmentStrings_U((PWSTR)lpEnvironment,
772                                                &SrcU,
773                                                &DestU,
774                                                NULL);
775 
776         DestroyEnvironmentBlock(lpEnvironment);
777 
778         if (NT_SUCCESS(Status))
779         {
780             Ret = TRUE;
781         }
782         else
783         {
784             SetLastError(RtlNtStatusToDosError(Status));
785         }
786     }
787 
788     return Ret;
789 }
790 
791 
792 BOOL
793 WINAPI
794 ExpandEnvironmentStringsForUserA(IN HANDLE hToken,
795                                  IN LPCSTR lpSrc,
796                                  OUT LPSTR lpDest,
797                                  IN DWORD dwSize)
798 {
799     BOOL Ret = FALSE;
800     DWORD dwSrcLen;
801     LPWSTR lpSrcW = NULL, lpDestW = NULL;
802 
803     if (lpSrc == NULL || lpDest == NULL || dwSize == 0)
804     {
805         SetLastError(ERROR_INVALID_PARAMETER);
806         return FALSE;
807     }
808 
809     dwSrcLen = strlen(lpSrc);
810     lpSrcW = (LPWSTR)GlobalAlloc(GMEM_FIXED,
811                                  (dwSrcLen + 1) * sizeof(WCHAR));
812     if (lpSrcW == NULL ||
813         MultiByteToWideChar(CP_ACP,
814                             0,
815                             lpSrc,
816                             -1,
817                             lpSrcW,
818                             dwSrcLen + 1) == 0)
819     {
820         goto Cleanup;
821     }
822 
823     lpDestW = (LPWSTR)GlobalAlloc(GMEM_FIXED,
824                                   dwSize * sizeof(WCHAR));
825     if (lpDestW == NULL)
826         goto Cleanup;
827 
828     Ret = ExpandEnvironmentStringsForUserW(hToken,
829                                            lpSrcW,
830                                            lpDestW,
831                                            dwSize);
832     if (Ret)
833     {
834         if (WideCharToMultiByte(CP_ACP,
835                                 0,
836                                 lpDestW,
837                                 -1,
838                                 lpDest,
839                                 dwSize,
840                                 NULL,
841                                 NULL) == 0)
842         {
843             Ret = FALSE;
844         }
845     }
846 
847 Cleanup:
848     if (lpSrcW != NULL)
849         GlobalFree((HGLOBAL)lpSrcW);
850 
851     if (lpDestW != NULL)
852         GlobalFree((HGLOBAL)lpDestW);
853 
854     return Ret;
855 }
856 
857 /* EOF */
858