xref: /reactos/dll/win32/userenv/environment.c (revision 13a145b6)
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
SetUserEnvironmentVariable(PWSTR * Environment,LPWSTR lpName,LPWSTR lpValue,BOOL bExpand)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
AppendUserEnvironmentVariable(PWSTR * Environment,LPWSTR lpName,LPWSTR lpValue)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
GetCurrentUserKey(HANDLE hToken)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
GetUserAndDomainName(IN HANDLE hToken,OUT LPWSTR * UserName,OUT LPWSTR * DomainName)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
SetUserEnvironment(PWSTR * Environment,HKEY hKey,LPWSTR lpSubKeyName)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
SetSystemEnvironment(PWSTR * Environment)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
CreateEnvironmentBlock(OUT LPVOID * lpEnvironment,IN HANDLE hToken,IN BOOL bInherit)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
DestroyEnvironmentBlock(IN LPVOID lpEnvironment)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
ExpandEnvironmentStringsForUserW(IN HANDLE hToken,IN LPCWSTR lpSrc,OUT LPWSTR lpDest,IN DWORD dwSize)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
ExpandEnvironmentStringsForUserA(IN HANDLE hToken,IN LPCSTR lpSrc,OUT LPSTR lpDest,IN DWORD dwSize)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