mirror of
https://github.com/reactos/reactos.git
synced 2024-10-03 16:05:37 +00:00
[ADVAPI32]
- Reimplement RegEnumValueA on top of RegEnumValueW CORE-8582 svn path=/trunk/; revision=64475
This commit is contained in:
parent
e8810d94f4
commit
6c3b1fa623
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue