[ADVAPI32]

- Reimplement RegEnumValueA on top of RegEnumValueW
CORE-8582

svn path=/trunk/; revision=64475
This commit is contained in:
Jérôme Gardou 2014-10-02 22:03:58 +00:00
parent e8810d94f4
commit 6c3b1fa623

View file

@ -2697,120 +2697,139 @@ Cleanup:
* @implemented * @implemented
*/ */
LONG WINAPI LONG WINAPI
RegEnumValueA(HKEY hKey, RegEnumValueA(
DWORD index, _In_ HKEY hKey,
LPSTR value, _In_ DWORD dwIndex,
LPDWORD val_count, _Out_ LPSTR lpName,
LPDWORD reserved, _Inout_ LPDWORD lpcbName,
LPDWORD type, _Reserved_ LPDWORD lpdwReserved,
LPBYTE data, _Out_opt_ LPDWORD lpdwType,
LPDWORD count) _Out_opt_ LPBYTE lpData,
_Out_opt_ LPDWORD lpcbData)
{ {
HANDLE KeyHandle; WCHAR* NameBuffer;
NTSTATUS status; DWORD NameBufferSize, NameLength;
ULONG total_size; LONG ErrorCode;
char buffer[256], *buf_ptr = buffer; DWORD LocalType = REG_NONE;
KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer; BOOL NameOverflow = FALSE;
static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
//TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n", /* Do parameter checks now, once and for all. */
// hkey, index, value, val_count, reserved, type, data, count ); if ((lpData && !lpcbData) || lpdwReserved)
/* NT only checks count, not val_count */
if ((data && !count) || reserved)
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
status = MapDefaultKey(&KeyHandle, hKey); /* Get the size of the buffer we must use for the first call ro RegEnumValueW */
if (!NT_SUCCESS(status)) ErrorCode = RegQueryInfoKeyW(
hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &NameBufferSize, NULL, NULL, NULL);
if (ErrorCode != ERROR_SUCCESS)
return ErrorCode;
/* Allocate the buffer for the unicode name */
NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NameBufferSize * sizeof(WCHAR));
if (NameBuffer == NULL)
{ {
return RtlNtStatusToDosError(status); return ERROR_NOT_ENOUGH_MEMORY;
} }
total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR); /*
if (data) total_size += *count; * This code calls RegEnumValueW twice, because we need to know the type of the enumerated value.
total_size = min( sizeof(buffer), total_size ); * So for the first call, we check if we overflow on the name, as we have no way of knowing if this
* is an overflow on the data or on the name during the the second call. So the first time, we make the
status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation, * call with the supplied value. This is merdique, but this is how it is.
buffer, total_size, &total_size ); */
if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done; NameLength = *lpcbName;
ErrorCode = RegEnumValueW(
/* we need to fetch the contents for a string type even if not requested, hKey,
* because we need to compute the length of the ASCII string. */ dwIndex,
if (value || data || is_string(info->Type)) NameBuffer,
&NameLength,
NULL,
&LocalType,
NULL,
NULL);
if (ErrorCode != ERROR_SUCCESS)
{ {
/* retry with a dynamically allocated buffer */ if (ErrorCode == ERROR_MORE_DATA)
while ((status == STATUS_BUFFER_OVERFLOW) || (status == STATUS_BUFFER_TOO_SMALL)) NameOverflow = TRUE;
else
goto Exit;
}
if (is_string(LocalType) && lpcbData)
{
/* We must allocate a buffer to get the unicode data */
DWORD DataBufferSize = *lpcbData * sizeof(WCHAR);
WCHAR* DataBuffer = NULL;
DWORD DataLength = *lpcbData;
LPSTR DataStr = (LPSTR)lpData;
if (lpData)
DataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbData * sizeof(WCHAR));
/* Do the real call */
ErrorCode = RegEnumValueW(
hKey,
dwIndex,
NameBuffer,
&NameBufferSize,
lpdwReserved,
lpdwType,
(LPBYTE)DataBuffer,
&DataBufferSize);
*lpcbData = DataBufferSize / sizeof(WCHAR);
if (ErrorCode != ERROR_SUCCESS)
{ {
if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer);
if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) goto Exit;
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
buf_ptr, total_size, &total_size );
} }
if (status) goto done; /* Copy the data whatever the error code is */
if (lpData)
if (is_string(info->Type))
{ {
ULONG len; /* Do the data conversion */
RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset), RtlUnicodeToMultiByteN(DataStr, DataLength, 0, DataBuffer, DataBufferSize);
info->DataLength ); /* NULL-terminate if there is enough room */
if (data && len) if ((DataLength > *lpcbData) && (DataStr[*lpcbData - 1] != '\0'))
{ DataStr[*lpcbData] = '\0';
if (len > *count) status = STATUS_BUFFER_OVERFLOW;
else
{
RtlUnicodeToMultiByteN( (PCHAR)data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
info->DataLength );
/* if the type is REG_SZ and data is not 0-terminated
* and there is enough space in the buffer NT appends a \0 */
if (len < *count && data[len-1]) data[len] = 0;
}
}
info->DataLength = len;
}
else if (data)
{
if (info->DataLength > *count) status = STATUS_BUFFER_OVERFLOW;
else memcpy( data, buf_ptr + info->DataOffset, info->DataLength );
} }
if (value && !status) RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer);
{ }
ULONG len; else
{
/* No data conversion needed. Do the call with provided buffers */
ErrorCode = RegEnumValueW(
hKey,
dwIndex,
NameBuffer,
&NameBufferSize,
lpdwReserved,
lpdwType,
lpData,
lpcbData);
RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength ); if (ErrorCode != ERROR_SUCCESS)
if (len >= *val_count) {
{ goto Exit;
status = STATUS_BUFFER_OVERFLOW;
if (*val_count)
{
len = *val_count - 1;
RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
value[len] = 0;
}
}
else
{
RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
value[len] = 0;
*val_count = len;
}
} }
} }
else status = STATUS_SUCCESS;
if (type) *type = info->Type; if (NameOverflow)
if (count) *count = info->DataLength; {
ErrorCode = ERROR_MORE_DATA;
goto Exit;
}
done: /* Convert the name string */
if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); RtlUnicodeToMultiByteN(lpName, *lpcbName, lpcbName, NameBuffer, NameBufferSize * sizeof(WCHAR));
ClosePredefKey(KeyHandle); ((PSTR)lpName)[*lpcbName] = '\0';
return RtlNtStatusToDosError(status);
Exit:
if (NameBuffer)
RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
return ErrorCode;
} }