[KERNEL32]: Rewrite (in some cases, simply clean-up) environment handling functions for better string handling, error codes, and performance. Part of ongoing kernel32 work.

svn path=/trunk/; revision=54274
This commit is contained in:
Alex Ionescu 2011-10-30 01:07:09 +00:00
parent bfc68fc3a1
commit 0bf4287f08

View file

@ -24,489 +24,506 @@
*/ */
DWORD DWORD
WINAPI WINAPI
GetEnvironmentVariableA ( GetEnvironmentVariableA(IN LPCSTR lpName,
LPCSTR lpName, IN LPSTR lpBuffer,
LPSTR lpBuffer, IN DWORD nSize)
DWORD nSize
)
{ {
ANSI_STRING VarName; ANSI_STRING VarName, VarValue;
ANSI_STRING VarValue; UNICODE_STRING VarNameU, VarValueU;
UNICODE_STRING VarNameU; PWSTR Buffer;
UNICODE_STRING VarValueU; ULONG Result = 0, UniSize = 0;
NTSTATUS Status; NTSTATUS Status;
/* initialize unicode variable name string */ /* Initialize all the strings */
RtlInitAnsiString (&VarName, RtlInitAnsiString(&VarName, lpName);
(LPSTR)lpName); RtlInitUnicodeString(&VarNameU, NULL);
RtlAnsiStringToUnicodeString (&VarNameU, RtlInitUnicodeString(&VarValueU, NULL);
&VarName, Status = RtlAnsiStringToUnicodeString(&VarNameU, &VarName, TRUE);
TRUE); if (!NT_SUCCESS(Status)) goto Quickie;
/* initialize ansi variable value string */ /* Check if the size is too big to fit */
VarValue.Length = 0; if (nSize <= UNICODE_STRING_MAX_BYTES)
VarValue.MaximumLength = (USHORT)nSize; {
VarValue.Buffer = lpBuffer; /* Keep the given size, minus a NULL-char */
if (nSize) UniSize = nSize * sizeof(WCHAR) - sizeof(UNICODE_NULL);
}
else
{
/* Set the maximum possible */
UniSize = UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL);
}
/* initialize unicode variable value string and allocate buffer */ /* Allocate the value string buffer */
VarValueU.Length = 0; Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UniSize);
if (nSize != 0) if (!Buffer)
{ {
VarValueU.MaximumLength = (USHORT)(nSize - 1) * sizeof(WCHAR); Status = STATUS_NO_MEMORY;
VarValueU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (), goto Quickie;
0, }
nSize * sizeof(WCHAR));
if (VarValueU.Buffer != NULL)
{
/* NULL-terminate the buffer in any case! RtlQueryEnvironmentVariable_U
only terminates it if MaximumLength < Length! */
VarValueU.Buffer[nSize - 1] = L'\0';
}
}
else
{
VarValueU.MaximumLength = 0;
VarValueU.Buffer = NULL;
}
if (VarValueU.Buffer != NULL || nSize == 0) /* And initialize its string */
RtlInitEmptyUnicodeString(&VarValueU, Buffer, UniSize);
/* Acquire the PEB lock since we'll be querying variables now */
RtlAcquirePebLock();
/* Query the variable */
Status = RtlQueryEnvironmentVariable_U(NULL, &VarNameU, &VarValueU);
if ((NT_SUCCESS(Status)) && !(nSize)) Status = STATUS_BUFFER_TOO_SMALL;
/* Check if we didn't have enough space */
if (Status == STATUS_BUFFER_TOO_SMALL)
{
/* Fixup the length that the API returned */
VarValueU.MaximumLength = VarValueU.Length + 2;
/* Free old Unicode buffer */
RtlFreeHeap(RtlGetProcessHeap(), 0, VarValueU.Buffer);
/* Allocate new one */
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, VarValueU.MaximumLength);
if (Buffer)
{ {
/* get unicode environment variable */ /* Query the variable so we can know its size */
Status = RtlQueryEnvironmentVariable_U (NULL, VarValueU.Buffer = Buffer;
&VarNameU, Status = RtlQueryEnvironmentVariable_U(NULL, &VarNameU, &VarValueU);
&VarValueU); if (NT_SUCCESS(Status))
if (!NT_SUCCESS(Status))
{
/* free unicode buffer */
RtlFreeHeap (RtlGetProcessHeap (),
0,
VarValueU.Buffer);
/* free unicode variable name string */
RtlFreeUnicodeString (&VarNameU);
BaseSetLastNTError (Status);
if (Status == STATUS_BUFFER_TOO_SMALL)
{
return (VarValueU.Length / sizeof(WCHAR)) + 1;
}
else
{
return 0;
}
}
/* convert unicode value string to ansi */
RtlUnicodeStringToAnsiString (&VarValue,
&VarValueU,
FALSE);
if (VarValueU.Buffer != NULL)
{ {
/* free unicode buffer */ /* Get the ASCII length of the variable */
RtlFreeHeap (RtlGetProcessHeap (), Result = RtlUnicodeStringToAnsiSize(&VarValueU);
0,
VarValueU.Buffer);
} }
/* free unicode variable name string */
RtlFreeUnicodeString (&VarNameU);
return (VarValueU.Length / sizeof(WCHAR));
} }
else else
{ {
SetLastError (ERROR_NOT_ENOUGH_MEMORY); /* Set failure status */
return 0; Status = STATUS_NO_MEMORY;
}
}
else
{
/* Check if the size is too big to fit */
if (nSize <= MAXULONG)
{
/* Keep the given size, minus a NULL-char */
if (nSize) nSize = nSize - sizeof(ANSI_NULL);
}
else
{
/* Set the maximum possible */
nSize = MAXULONG - sizeof(ANSI_NULL);
} }
}
/* Check the size */
Result = RtlUnicodeStringToAnsiSize(&VarValueU);
if (Result <= nSize)
{
/* Convert the string */
RtlInitEmptyAnsiString(&VarValue, lpBuffer, nSize);
Status = RtlUnicodeStringToAnsiString(&VarValue, &VarValueU, FALSE);
if (NT_SUCCESS(Status))
{
/* NULL-terminate and set the final length */
lpBuffer[VarValue.Length] = ANSI_NULL;
Result = VarValue.Length;
}
}
}
/* Release the lock */
RtlReleasePebLock();
Quickie:
/* Free the strings */
RtlFreeUnicodeString(&VarNameU);
if (VarValueU.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, VarValueU.Buffer);
/* Check if we suceeded */
if (!NT_SUCCESS(Status))
{
/* We did not, clear the result and set the error code */
BaseSetLastNTError(Status);
Result = 0;
}
/* Return the result */
return Result;
}
/* /*
* @implemented * @implemented
*/ */
DWORD DWORD
WINAPI WINAPI
GetEnvironmentVariableW ( GetEnvironmentVariableW(IN LPCWSTR lpName,
LPCWSTR lpName, IN LPWSTR lpBuffer,
LPWSTR lpBuffer, IN DWORD nSize)
DWORD nSize
)
{ {
UNICODE_STRING VarName; UNICODE_STRING VarName, VarValue;
UNICODE_STRING VarValue; NTSTATUS Status;
NTSTATUS Status;
RtlInitUnicodeString (&VarName, if (nSize <= UNICODE_STRING_MAX_BYTES)
lpName); {
if (nSize) nSize = nSize * sizeof(WCHAR) - sizeof(UNICODE_NULL);
}
else
{
nSize = UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL);
}
VarValue.Length = 0; Status = RtlInitUnicodeStringEx(&VarName, lpName);
VarValue.MaximumLength = (USHORT) (nSize ? nSize - 1 : 0) * sizeof(WCHAR); if (NT_SUCCESS(Status))
VarValue.Buffer = lpBuffer; {
RtlInitEmptyUnicodeString(&VarValue, lpBuffer, nSize);
Status = RtlQueryEnvironmentVariable_U (NULL, Status = RtlQueryEnvironmentVariable_U(NULL, &VarName, &VarValue);
&VarName, if (!NT_SUCCESS(Status))
&VarValue);
if (!NT_SUCCESS(Status))
{
if (Status == STATUS_BUFFER_TOO_SMALL)
{
return (VarValue.Length / sizeof(WCHAR)) + 1;
}
else
{
BaseSetLastNTError (Status);
return 0;
}
}
if (nSize != 0)
{ {
/* make sure the string is NULL-terminated! RtlQueryEnvironmentVariable_U if (Status == STATUS_BUFFER_TOO_SMALL)
only terminates it if MaximumLength < Length */ {
lpBuffer[VarValue.Length / sizeof(WCHAR)] = L'\0'; return (VarValue.Length / sizeof(WCHAR)) + sizeof(ANSI_NULL);
} }
BaseSetLastNTError (Status);
return 0;
}
return (VarValue.Length / sizeof(WCHAR)); lpBuffer[VarValue.Length / sizeof(WCHAR)] = UNICODE_NULL;
}
return (VarValue.Length / sizeof(WCHAR));
} }
/* /*
* @implemented * @implemented
*/ */
BOOL BOOL
WINAPI WINAPI
SetEnvironmentVariableA ( SetEnvironmentVariableA(IN LPCSTR lpName,
LPCSTR lpName, IN LPCSTR lpValue)
LPCSTR lpValue
)
{ {
ANSI_STRING VarName; ANSI_STRING VarName, VarValue;
ANSI_STRING VarValue; UNICODE_STRING VarNameU, VarValueU;
UNICODE_STRING VarNameU; NTSTATUS Status;
UNICODE_STRING VarValueU;
NTSTATUS Status;
DPRINT("SetEnvironmentVariableA(Name '%s', Value '%s')\n", lpName, lpValue); RtlInitAnsiString(&VarName, (LPSTR)lpName);
Status = RtlAnsiStringToUnicodeString(&VarNameU, &VarName, TRUE);
if (NT_SUCCESS(Status))
{
if (lpValue)
{
RtlInitAnsiString(&VarValue, (LPSTR)lpValue);
Status = RtlAnsiStringToUnicodeString(&VarValueU, &VarValue, TRUE);
if (NT_SUCCESS(Status))
{
Status = RtlSetEnvironmentVariable(NULL, &VarNameU, &VarValueU);
RtlFreeUnicodeString(&VarValueU);
}
}
else
{
Status = RtlSetEnvironmentVariable(NULL, &VarNameU, NULL);
}
RtlInitAnsiString (&VarName, RtlFreeUnicodeString(&VarNameU);
(LPSTR)lpName);
RtlAnsiStringToUnicodeString (&VarNameU,
&VarName,
TRUE);
if (lpValue) if (NT_SUCCESS(Status)) return TRUE;
{ }
RtlInitAnsiString (&VarValue,
(LPSTR)lpValue);
RtlAnsiStringToUnicodeString (&VarValueU,
&VarValue,
TRUE);
Status = RtlSetEnvironmentVariable (NULL, BaseSetLastNTError(Status);
&VarNameU, return FALSE;
&VarValueU);
RtlFreeUnicodeString (&VarValueU);
}
else
{
Status = RtlSetEnvironmentVariable (NULL,
&VarNameU,
NULL);
}
RtlFreeUnicodeString (&VarNameU);
if (!NT_SUCCESS(Status))
{
BaseSetLastNTError (Status);
return FALSE;
}
return TRUE;
} }
/* /*
* @implemented * @implemented
*/ */
BOOL BOOL
WINAPI WINAPI
SetEnvironmentVariableW ( SetEnvironmentVariableW(IN LPCWSTR lpName,
LPCWSTR lpName, IN LPCWSTR lpValue)
LPCWSTR lpValue
)
{ {
UNICODE_STRING VarName; UNICODE_STRING VarName, VarValue;
UNICODE_STRING VarValue; NTSTATUS Status;
NTSTATUS Status;
DPRINT("SetEnvironmentVariableW(Name '%S', Value '%S')\n", lpName, lpValue); Status = RtlInitUnicodeStringEx(&VarName, lpName);
if (NT_SUCCESS(Status))
{
if (lpValue)
{
Status = RtlInitUnicodeStringEx(&VarValue, lpValue);
if (NT_SUCCESS(Status))
{
Status = RtlSetEnvironmentVariable(NULL, &VarName, &VarValue);
}
}
else
{
Status = RtlSetEnvironmentVariable(NULL, &VarName, NULL);
}
RtlInitUnicodeString (&VarName, if (NT_SUCCESS(Status)) return TRUE;
lpName); }
RtlInitUnicodeString (&VarValue, BaseSetLastNTError(Status);
lpValue); return FALSE;
Status = RtlSetEnvironmentVariable (NULL,
&VarName,
&VarValue);
if (!NT_SUCCESS(Status))
{
BaseSetLastNTError (Status);
return FALSE;
}
return TRUE;
} }
/* /*
* @implemented * @implemented
*/ */
LPSTR LPSTR
WINAPI WINAPI
GetEnvironmentStringsA ( GetEnvironmentStringsA(VOID)
VOID
)
{ {
UNICODE_STRING UnicodeString; ULONG Length, Size;
ANSI_STRING AnsiString; NTSTATUS Status;
PWCHAR EnvU; PWCHAR Environment, p;
PWCHAR PtrU; PCHAR Buffer = NULL;
ULONG Length;
PCHAR EnvPtr = NULL;
EnvU = (PWCHAR)(NtCurrentPeb ()->ProcessParameters->Environment); RtlAcquirePebLock();
p = Environment = NtCurrentPeb()->ProcessParameters->Environment;
if (EnvU == NULL) do
return NULL; {
p += wcslen(Environment) + 1;
} while (*p);
if (*EnvU == 0) Length = p - Environment + sizeof(UNICODE_NULL);
return NULL;
/* get environment size */ Status = RtlUnicodeToMultiByteSize(&Size, Environment, Length);
PtrU = EnvU; if (NT_SUCCESS(Status))
while (*PtrU) {
{ Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
while (*PtrU) if (Buffer)
PtrU++;
PtrU++;
}
Length = (ULONG)(PtrU - EnvU);
DPRINT("Length %lu\n", Length);
/* allocate environment buffer */
EnvPtr = RtlAllocateHeap (RtlGetProcessHeap (),
0,
Length + 1);
if (EnvPtr == NULL)
{ {
SetLastError(ERROR_NOT_ENOUGH_MEMORY); Status = RtlUnicodeToOemN(Buffer, Size, 0, Environment, Length);
return NULL; if (!NT_SUCCESS(Status))
{
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
Buffer = NULL;
BaseSetLastNTError(Status);
}
} }
DPRINT("EnvPtr %p\n", EnvPtr); else
{
BaseSetLastNTError(STATUS_NO_MEMORY);
}
}
else
{
BaseSetLastNTError(Status);
}
/* convert unicode environment to ansi */ RtlReleasePebLock();
UnicodeString.MaximumLength = (USHORT)Length * sizeof(WCHAR) + sizeof(WCHAR); return Buffer;
UnicodeString.Buffer = EnvU;
AnsiString.MaximumLength = (USHORT)Length + 1;
AnsiString.Length = 0;
AnsiString.Buffer = EnvPtr;
DPRINT ("UnicodeString.Buffer \'%S\'\n", UnicodeString.Buffer);
while (*(UnicodeString.Buffer))
{
UnicodeString.Length = wcslen (UnicodeString.Buffer) * sizeof(WCHAR);
UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
if (UnicodeString.Length > 0)
{
AnsiString.Length = 0;
AnsiString.MaximumLength = (USHORT)Length + 1 - (AnsiString.Buffer - EnvPtr);
RtlUnicodeStringToAnsiString (&AnsiString,
&UnicodeString,
FALSE);
AnsiString.Buffer += (AnsiString.Length + 1);
UnicodeString.Buffer += ((UnicodeString.Length / sizeof(WCHAR)) + 1);
}
}
*(AnsiString.Buffer) = 0;
return EnvPtr;
} }
/* /*
* @implemented * @implemented
*/ */
LPWSTR LPWSTR
WINAPI WINAPI
GetEnvironmentStringsW ( GetEnvironmentStringsW(VOID)
VOID
)
{ {
return (LPWSTR)(NtCurrentPeb ()->ProcessParameters->Environment); PWCHAR Environment, p;
} ULONG Length;
RtlAcquirePebLock();
p = Environment = NtCurrentPeb()->ProcessParameters->Environment;
do
{
p += wcslen(Environment) + 1;
} while (*p);
Length = p - Environment + sizeof(UNICODE_NULL);
p = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
if (p)
{
RtlCopyMemory(p, Environment, Length);
}
else
{
BaseSetLastNTError(STATUS_NO_MEMORY);
}
RtlReleasePebLock();
return p;
}
/* /*
* @implemented * @implemented
*/ */
BOOL BOOL
WINAPI WINAPI
FreeEnvironmentStringsA ( FreeEnvironmentStringsA(IN LPSTR EnvironmentStrings)
LPSTR EnvironmentStrings
)
{ {
if (EnvironmentStrings == NULL) return (BOOL)RtlFreeHeap(RtlGetProcessHeap(), 0, EnvironmentStrings);
return FALSE;
RtlFreeHeap (RtlGetProcessHeap (),
0,
EnvironmentStrings);
return TRUE;
} }
/* /*
* @implemented * @implemented
*/ */
BOOL BOOL
WINAPI WINAPI
FreeEnvironmentStringsW ( FreeEnvironmentStringsW(IN LPWSTR EnvironmentStrings)
LPWSTR EnvironmentStrings
)
{ {
return TRUE; return (BOOL)RtlFreeHeap(RtlGetProcessHeap(), 0, EnvironmentStrings);
} }
/* /*
* @implemented * @implemented
*/ */
DWORD DWORD
WINAPI WINAPI
ExpandEnvironmentStringsA ( ExpandEnvironmentStringsA(IN LPCSTR lpSrc,
LPCSTR lpSrc, IN LPSTR lpDst,
LPSTR lpDst, IN DWORD nSize)
DWORD nSize
)
{ {
ANSI_STRING Source; ANSI_STRING Source, Dest;
ANSI_STRING Destination; UNICODE_STRING SourceU, DestU;
UNICODE_STRING SourceU; PWSTR Buffer;
UNICODE_STRING DestinationU; ULONG Result = 0, UniSize = 0, Length;
NTSTATUS Status; NTSTATUS Status;
ULONG Length = 0;
RtlInitAnsiString (&Source, /* Initialize all the strings */
(LPSTR)lpSrc); RtlInitAnsiString(&Source, lpSrc);
Status = RtlAnsiStringToUnicodeString (&SourceU, RtlInitUnicodeString(&SourceU, NULL);
&Source, RtlInitUnicodeString(&DestU, NULL);
TRUE); Status = RtlAnsiStringToUnicodeString(&SourceU, &Source, TRUE);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status)) goto Quickie;
/* Check if the size is too big to fit */
if (nSize <= UNICODE_STRING_MAX_BYTES)
{
/* Keep the given size, minus a NULL-char */
if (nSize) UniSize = nSize * sizeof(WCHAR) - sizeof(UNICODE_NULL);
}
else
{
/* Set the maximum possible */
UniSize = UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL);
}
/* Allocate the value string buffer */
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UniSize);
if (!Buffer)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* And initialize its string */
RtlInitEmptyUnicodeString(&DestU, Buffer, UniSize);
/* Query the variable */
Length = 0;
Status = RtlExpandEnvironmentStrings_U(NULL, &SourceU, &DestU, &Length);
/* Check if we didn't have enough space */
if (Status == STATUS_BUFFER_TOO_SMALL)
{
/* Fixup the length that the API returned */
DestU.MaximumLength = Length;
/* Free old Unicode buffer */
RtlFreeHeap(RtlGetProcessHeap(), 0, DestU.Buffer);
/* Allocate new one */
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
if (Buffer)
{ {
BaseSetLastNTError (Status); /* Query the variable so we can know its size */
return 0; DestU.Buffer = Buffer;
Status = RtlExpandEnvironmentStrings_U(NULL, &SourceU, &DestU, &Length);
if (NT_SUCCESS(Status))
{
/* Get the ASCII length of the variable */
Result = RtlUnicodeStringToAnsiSize(&DestU);
}
}
else
{
/* Set failure status */
Status = STATUS_NO_MEMORY;
}
}
else
{
/* Check if the size is too big to fit */
if (nSize <= MAXULONG)
{
/* Keep the given size, minus a NULL-char */
if (nSize) nSize = nSize - sizeof(ANSI_NULL);
}
else
{
/* Set the maximum possible */
nSize = MAXULONG - sizeof(ANSI_NULL);
} }
/* make sure we don't overflow the maximum ANSI_STRING size */ /* Check the size */
if (nSize > 0x7fff) Result = RtlUnicodeStringToAnsiSize(&DestU);
nSize = 0x7fff; if (Result <= nSize)
Destination.Length = 0;
Destination.MaximumLength = (USHORT)nSize;
Destination.Buffer = lpDst;
DestinationU.Length = 0;
DestinationU.MaximumLength = (USHORT)nSize * sizeof(WCHAR);
DestinationU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
0,
DestinationU.MaximumLength);
if (DestinationU.Buffer == NULL)
{ {
RtlFreeUnicodeString(&SourceU); /* Convert the string */
SetLastError(ERROR_NOT_ENOUGH_MEMORY); RtlInitEmptyAnsiString(&Dest, lpDst, nSize);
return 0; Status = RtlUnicodeStringToAnsiString(&Dest, &DestU, FALSE);
if (!NT_SUCCESS(Status))
{
/* Clear the destination */
*lpDst = ANSI_NULL;
}
} }
}
Quickie:
/* Free the strings */
RtlFreeUnicodeString(&SourceU);
if (DestU.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, DestU.Buffer);
Status = RtlExpandEnvironmentStrings_U (NULL, /* Check if we suceeded */
&SourceU, if (!NT_SUCCESS(Status))
&DestinationU, {
&Length); /* We did not, clear the result and set the error code */
BaseSetLastNTError(Status);
Result = 0;
}
RtlFreeUnicodeString (&SourceU); /* Return the result */
return Result;
if (!NT_SUCCESS(Status))
{
BaseSetLastNTError (Status);
if (Status != STATUS_BUFFER_TOO_SMALL)
{
RtlFreeHeap (RtlGetProcessHeap (),
0,
DestinationU.Buffer);
return 0;
}
}
RtlUnicodeStringToAnsiString (&Destination,
&DestinationU,
FALSE);
RtlFreeHeap (RtlGetProcessHeap (),
0,
DestinationU.Buffer);
return (Length / sizeof(WCHAR));
} }
/* /*
* @implemented * @implemented
*/ */
DWORD DWORD
WINAPI WINAPI
ExpandEnvironmentStringsW ( ExpandEnvironmentStringsW(IN LPCWSTR lpSrc,
LPCWSTR lpSrc, IN LPWSTR lpDst,
LPWSTR lpDst, IN DWORD nSize)
DWORD nSize
)
{ {
UNICODE_STRING Source; UNICODE_STRING Source, Destination;
UNICODE_STRING Destination; NTSTATUS Status;;
NTSTATUS Status;
ULONG Length = 0;
RtlInitUnicodeString (&Source, RtlInitUnicodeString(&Source, (LPWSTR)lpSrc);
(LPWSTR)lpSrc);
/* make sure we don't overflow the maximum UNICODE_STRING size */ /* make sure we don't overflow the maximum UNICODE_STRING size */
if (nSize > 0x7fff) if (nSize > UNICODE_STRING_MAX_BYTES) nSize = UNICODE_STRING_MAX_BYTES;
nSize = 0x7fff;
Destination.Length = 0; RtlInitEmptyUnicodeString(&Destination, lpDst, nSize * sizeof(WCHAR));
Destination.MaximumLength = (USHORT)nSize * sizeof(WCHAR); Status = RtlExpandEnvironmentStrings_U(NULL,
Destination.Buffer = lpDst; &Source,
&Destination,
&nSize);
if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL))
{
return nSize / sizeof(WCHAR);
}
Status = RtlExpandEnvironmentStrings_U (NULL, BaseSetLastNTError (Status);
&Source, return 0;
&Destination,
&Length);
if (!NT_SUCCESS(Status))
{
BaseSetLastNTError (Status);
if (Status != STATUS_BUFFER_TOO_SMALL)
return 0;
}
return (Length / sizeof(WCHAR));
} }
/* /*