[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;
/* initialize unicode variable value string and allocate buffer */
VarValueU.Length = 0;
if (nSize != 0)
{ {
VarValueU.MaximumLength = (USHORT)(nSize - 1) * sizeof(WCHAR); /* Keep the given size, minus a NULL-char */
VarValueU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (), if (nSize) UniSize = nSize * sizeof(WCHAR) - sizeof(UNICODE_NULL);
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 else
{ {
VarValueU.MaximumLength = 0; /* Set the maximum possible */
VarValueU.Buffer = NULL; UniSize = UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL);
} }
if (VarValueU.Buffer != NULL || nSize == 0) /* Allocate the value string buffer */
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UniSize);
if (!Buffer)
{ {
/* get unicode environment variable */ Status = STATUS_NO_MEMORY;
Status = RtlQueryEnvironmentVariable_U (NULL, goto Quickie;
&VarNameU, }
&VarValueU);
if (!NT_SUCCESS(Status))
{
/* free unicode buffer */
RtlFreeHeap (RtlGetProcessHeap (),
0,
VarValueU.Buffer);
/* free unicode variable name string */ /* And initialize its string */
RtlFreeUnicodeString (&VarNameU); RtlInitEmptyUnicodeString(&VarValueU, Buffer, UniSize);
BaseSetLastNTError (Status); /* 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) if (Status == STATUS_BUFFER_TOO_SMALL)
{ {
return (VarValueU.Length / sizeof(WCHAR)) + 1; /* 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)
{
/* Query the variable so we can know its size */
VarValueU.Buffer = Buffer;
Status = RtlQueryEnvironmentVariable_U(NULL, &VarNameU, &VarValueU);
if (NT_SUCCESS(Status))
{
/* Get the ASCII length of the variable */
Result = RtlUnicodeStringToAnsiSize(&VarValueU);
}
} }
else else
{ {
return 0; /* Set failure status */
Status = STATUS_NO_MEMORY;
} }
} }
else
/* convert unicode value string to ansi */
RtlUnicodeStringToAnsiString (&VarValue,
&VarValueU,
FALSE);
if (VarValueU.Buffer != NULL)
{ {
/* free unicode buffer */ /* Check if the size is too big to fit */
RtlFreeHeap (RtlGetProcessHeap (), if (nSize <= MAXULONG)
0, {
VarValueU.Buffer); /* 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);
} }
/* free unicode variable name string */ /* 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); RtlFreeUnicodeString(&VarNameU);
if (VarValueU.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, VarValueU.Buffer);
return (VarValueU.Length / sizeof(WCHAR)); /* Check if we suceeded */
} if (!NT_SUCCESS(Status))
else
{ {
SetLastError (ERROR_NOT_ENOUGH_MEMORY); /* We did not, clear the result and set the error code */
return 0; 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,
&VarValue);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
if (Status == STATUS_BUFFER_TOO_SMALL) if (Status == STATUS_BUFFER_TOO_SMALL)
{ {
return (VarValue.Length / sizeof(WCHAR)) + 1; return (VarValue.Length / sizeof(WCHAR)) + sizeof(ANSI_NULL);
} }
else
{
BaseSetLastNTError (Status); BaseSetLastNTError (Status);
return 0; return 0;
} }
}
if (nSize != 0) lpBuffer[VarValue.Length / sizeof(WCHAR)] = UNICODE_NULL;
{
/* make sure the string is NULL-terminated! RtlQueryEnvironmentVariable_U
only terminates it if MaximumLength < Length */
lpBuffer[VarValue.Length / sizeof(WCHAR)] = L'\0';
} }
return (VarValue.Length / sizeof(WCHAR)); 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;
UNICODE_STRING VarValueU;
NTSTATUS Status; NTSTATUS Status;
DPRINT("SetEnvironmentVariableA(Name '%s', Value '%s')\n", lpName, lpValue); RtlInitAnsiString(&VarName, (LPSTR)lpName);
Status = RtlAnsiStringToUnicodeString(&VarNameU, &VarName, TRUE);
RtlInitAnsiString (&VarName, if (NT_SUCCESS(Status))
(LPSTR)lpName); {
RtlAnsiStringToUnicodeString (&VarNameU,
&VarName,
TRUE);
if (lpValue) if (lpValue)
{ {
RtlInitAnsiString (&VarValue, RtlInitAnsiString(&VarValue, (LPSTR)lpValue);
(LPSTR)lpValue); Status = RtlAnsiStringToUnicodeString(&VarValueU, &VarValue, TRUE);
RtlAnsiStringToUnicodeString (&VarValueU, if (NT_SUCCESS(Status))
&VarValue, {
TRUE); Status = RtlSetEnvironmentVariable(NULL, &VarNameU, &VarValueU);
Status = RtlSetEnvironmentVariable (NULL,
&VarNameU,
&VarValueU);
RtlFreeUnicodeString(&VarValueU); RtlFreeUnicodeString(&VarValueU);
} }
}
else else
{ {
Status = RtlSetEnvironmentVariable (NULL, Status = RtlSetEnvironmentVariable(NULL, &VarNameU, NULL);
&VarNameU,
NULL);
} }
RtlFreeUnicodeString(&VarNameU); RtlFreeUnicodeString(&VarNameU);
if (!NT_SUCCESS(Status)) if (NT_SUCCESS(Status)) return TRUE;
{ }
BaseSetLastNTError(Status); BaseSetLastNTError(Status);
return FALSE; 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))
RtlInitUnicodeString (&VarName,
lpName);
RtlInitUnicodeString (&VarValue,
lpValue);
Status = RtlSetEnvironmentVariable (NULL,
&VarName,
&VarValue);
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);
}
if (NT_SUCCESS(Status)) return TRUE;
}
BaseSetLastNTError(Status); BaseSetLastNTError(Status);
return FALSE; 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;
if (*EnvU == 0)
return NULL;
/* get environment size */
PtrU = EnvU;
while (*PtrU)
{ {
while (*PtrU) p += wcslen(Environment) + 1;
PtrU++; } while (*p);
PtrU++;
}
Length = (ULONG)(PtrU - EnvU);
DPRINT("Length %lu\n", Length);
/* allocate environment buffer */ Length = p - Environment + sizeof(UNICODE_NULL);
EnvPtr = RtlAllocateHeap (RtlGetProcessHeap (),
0, Status = RtlUnicodeToMultiByteSize(&Size, Environment, Length);
Length + 1); if (NT_SUCCESS(Status))
if (EnvPtr == NULL)
{ {
SetLastError(ERROR_NOT_ENOUGH_MEMORY); Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
return NULL; if (Buffer)
}
DPRINT("EnvPtr %p\n", EnvPtr);
/* convert unicode environment to ansi */
UnicodeString.MaximumLength = (USHORT)Length * sizeof(WCHAR) + sizeof(WCHAR);
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); Status = RtlUnicodeToOemN(Buffer, Size, 0, Environment, Length);
UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR); if (!NT_SUCCESS(Status))
if (UnicodeString.Length > 0)
{ {
AnsiString.Length = 0; RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
AnsiString.MaximumLength = (USHORT)Length + 1 - (AnsiString.Buffer - EnvPtr); Buffer = NULL;
RtlUnicodeStringToAnsiString (&AnsiString, BaseSetLastNTError(Status);
&UnicodeString,
FALSE);
AnsiString.Buffer += (AnsiString.Length + 1);
UnicodeString.Buffer += ((UnicodeString.Length / sizeof(WCHAR)) + 1);
} }
} }
*(AnsiString.Buffer) = 0; else
{
return EnvPtr; BaseSetLastNTError(STATUS_NO_MEMORY);
}
}
else
{
BaseSetLastNTError(Status);
} }
RtlReleasePebLock();
return Buffer;
}
/* /*
* @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)) 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)
{
/* Query the variable so we can know its size */
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);
}
/* Check the size */
Result = RtlUnicodeStringToAnsiSize(&DestU);
if (Result <= nSize)
{
/* Convert the string */
RtlInitEmptyAnsiString(&Dest, lpDst, nSize);
Status = RtlUnicodeStringToAnsiString(&Dest, &DestU, FALSE);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
BaseSetLastNTError (Status); /* Clear the destination */
return 0; *lpDst = ANSI_NULL;
} }
/* make sure we don't overflow the maximum ANSI_STRING size */
if (nSize > 0x7fff)
nSize = 0x7fff;
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);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
} }
}
Status = RtlExpandEnvironmentStrings_U (NULL, Quickie:
&SourceU, /* Free the strings */
&DestinationU,
&Length);
RtlFreeUnicodeString(&SourceU); RtlFreeUnicodeString(&SourceU);
if (DestU.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, DestU.Buffer);
/* Check if we suceeded */
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
/* We did not, clear the result and set the error code */
BaseSetLastNTError(Status); BaseSetLastNTError(Status);
if (Status != STATUS_BUFFER_TOO_SMALL) Result = 0;
{
RtlFreeHeap (RtlGetProcessHeap (),
0,
DestinationU.Buffer);
return 0;
}
} }
RtlUnicodeStringToAnsiString (&Destination, /* Return the result */
&DestinationU, return Result;
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;
Destination.MaximumLength = (USHORT)nSize * sizeof(WCHAR);
Destination.Buffer = lpDst;
RtlInitEmptyUnicodeString(&Destination, lpDst, nSize * sizeof(WCHAR));
Status = RtlExpandEnvironmentStrings_U(NULL, Status = RtlExpandEnvironmentStrings_U(NULL,
&Source, &Source,
&Destination, &Destination,
&Length); &nSize);
if (!NT_SUCCESS(Status)) if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL))
{ {
BaseSetLastNTError (Status); return nSize / sizeof(WCHAR);
if (Status != STATUS_BUFFER_TOO_SMALL)
return 0;
} }
return (Length / sizeof(WCHAR)); BaseSetLastNTError (Status);
return 0;
} }
/* /*