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