Fixed RegEnumValueA/W behaviour when output buffers are too small. This fixes 20+ tests from "advapi32_test registry" (now it has only 2 failures - but that's a reduced tests set!).
I beg my pardon for reformatting these two funcs and fixing bugs in one commit, I will do it in different commits in the future.
Modified: trunk/reactos/lib/advapi32/reg/reg.c

Modified: trunk/reactos/lib/advapi32/reg/reg.c
--- trunk/reactos/lib/advapi32/reg/reg.c	2005-04-30 21:07:32 UTC (rev 14890)
+++ trunk/reactos/lib/advapi32/reg/reg.c	2005-04-30 21:11:34 UTC (rev 14891)
@@ -850,166 +850,163 @@
 	       LPDWORD lpcbClass,
 	       PFILETIME lpftLastWriteTime)
 {
-  union
-  {
-    KEY_NODE_INFORMATION Node;
-    KEY_BASIC_INFORMATION Basic;
-  } *KeyInfo;
+	union
+	{
+		KEY_NODE_INFORMATION Node;
+		KEY_BASIC_INFORMATION Basic;
+	} *KeyInfo;
 
-  UNICODE_STRING StringU;
-  ANSI_STRING StringA;
-  LONG ErrorCode = ERROR_SUCCESS;
-  DWORD NameLength;
-  DWORD ClassLength = 0;
-  DWORD BufferSize;
-  DWORD ResultSize;
-  HANDLE KeyHandle;
-  NTSTATUS Status;
+	UNICODE_STRING StringU;
+	ANSI_STRING StringA;
+	LONG ErrorCode = ERROR_SUCCESS;
+	DWORD NameLength;
+	DWORD ClassLength = 0;
+	DWORD BufferSize;
+	DWORD ResultSize;
+	HANDLE KeyHandle;
+	NTSTATUS Status;
 
-  DPRINT("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
-         hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0);
+	DPRINT("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n",
+		hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0);
 
-  if ((lpClass) && (!lpcbClass))
-    {
-      SetLastError (ERROR_INVALID_PARAMETER);
-      return ERROR_INVALID_PARAMETER;
-    }
+	if ((lpClass) && (!lpcbClass))
+	{
+		SetLastError (ERROR_INVALID_PARAMETER);
+		return ERROR_INVALID_PARAMETER;
+	}
 
-  Status = MapDefaultKey(&KeyHandle,
-			 hKey);
-  if (!NT_SUCCESS(Status))
-    {
-      ErrorCode = RtlNtStatusToDosError (Status);
-      SetLastError (ErrorCode);
-      return ErrorCode;
-    }
+	Status = MapDefaultKey(&KeyHandle, hKey);
+	if (!NT_SUCCESS(Status))
+	{
+		ErrorCode = RtlNtStatusToDosError (Status);
+		SetLastError (ErrorCode);
+		return ErrorCode;
+	}
 
-  if (*lpcbName > 0)
-    {
-      NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
-    }
-  else
-    {
-      NameLength = 0;
-    }
-
-  if (lpClass)
-    {
-      if (*lpcbClass > 0)
+	if (*lpcbName > 0)
 	{
-	  ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
+		NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
 	}
-      else
+	else
 	{
-	  ClassLength = 0;
+		NameLength = 0;
 	}
 
-      /* The class name should start at a dword boundary */
-      BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
-    }
-  else
-    {
-      BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
-    }
+	if (lpClass)
+	{
+		if (*lpcbClass > 0)
+		{
+			ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
+		}
+		else
+		{
+			ClassLength = 0;
+		}
 
-  KeyInfo = RtlAllocateHeap (ProcessHeap,
-			     0,
-			     BufferSize);
-  if (KeyInfo == NULL)
-    {
-      SetLastError (ERROR_OUTOFMEMORY);
-      return ERROR_OUTOFMEMORY;
-    }
-
-  Status = NtEnumerateKey (KeyHandle,
-			   (ULONG)dwIndex,
-			   lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
-			   KeyInfo,
-			   BufferSize,
-			   &ResultSize);
-  DPRINT("NtEnumerateKey() returned status 0x%X\n", Status);
-  if (!NT_SUCCESS(Status))
-    {
-      ErrorCode = RtlNtStatusToDosError (Status);
-    }
-  else
-    {
-      if (lpClass == NULL)
+		/* The class name should start at a dword boundary */
+		BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
+	}
+	else
 	{
-	  if (KeyInfo->Basic.NameLength > NameLength)
-	    {
-	      ErrorCode = ERROR_BUFFER_OVERFLOW;
-	    }
-	  else
-	    {
-	      StringU.Buffer = KeyInfo->Basic.Name;
-	      StringU.Length = KeyInfo->Basic.NameLength;
-	      StringU.MaximumLength = KeyInfo->Basic.NameLength;
-	    }
+		BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
 	}
-      else
+
+	KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
+	if (KeyInfo == NULL)
 	{
-	  if (KeyInfo->Node.NameLength > NameLength ||
-	      KeyInfo->Node.ClassLength > ClassLength)
-	    {
-	      ErrorCode = ERROR_BUFFER_OVERFLOW;
-	    }
-	  else
-	    {
-	      StringA.Buffer = lpClass;
-	      StringA.Length = 0;
-	      StringA.MaximumLength = *lpcbClass;
-	      StringU.Buffer = (PWCHAR)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset);
-	      StringU.Length = KeyInfo->Node.ClassLength;
-	      StringU.MaximumLength = KeyInfo->Node.ClassLength;
-	      RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
-	      lpClass[StringA.Length] = 0;
-	      *lpcbClass = StringA.Length;
-	      StringU.Buffer = KeyInfo->Node.Name;
-	      StringU.Length = KeyInfo->Node.NameLength;
-	      StringU.MaximumLength = KeyInfo->Node.NameLength;
-	    }
+		SetLastError (ERROR_OUTOFMEMORY);
+		return ERROR_OUTOFMEMORY;
 	}
 
-      if (ErrorCode == ERROR_SUCCESS)
+	Status = NtEnumerateKey (KeyHandle,
+								(ULONG)dwIndex,
+								lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
+								KeyInfo,
+								BufferSize,
+								&ResultSize);
+	DPRINT("NtEnumerateKey() returned status 0x%X\n", Status);
+	if (!NT_SUCCESS(Status))
 	{
-	  StringA.Buffer = lpName;
-	  StringA.Length = 0;
-	  StringA.MaximumLength = *lpcbName;
-	  RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
-	  lpName[StringA.Length] = 0;
-	  *lpcbName = StringA.Length;
-	  if (lpftLastWriteTime != NULL)
-	    {
-	      if (lpClass == NULL)
+		ErrorCode = RtlNtStatusToDosError (Status);
+	}
+	else
+	{
+		if (lpClass == NULL)
 		{
-		  lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
-		  lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
+			if (KeyInfo->Basic.NameLength > NameLength)
+			{
+				ErrorCode = ERROR_BUFFER_OVERFLOW;
+			}
+			else
+			{
+				StringU.Buffer = KeyInfo->Basic.Name;
+				StringU.Length = KeyInfo->Basic.NameLength;
+				StringU.MaximumLength = KeyInfo->Basic.NameLength;
+			}
 		}
-	      else
+		else
 		{
-		  lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
-		  lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
+			if (KeyInfo->Node.NameLength > NameLength ||
+				KeyInfo->Node.ClassLength > ClassLength)
+			{
+				ErrorCode = ERROR_BUFFER_OVERFLOW;
+			}
+			else
+			{
+				StringA.Buffer = lpClass;
+				StringA.Length = 0;
+				StringA.MaximumLength = *lpcbClass;
+				StringU.Buffer = (PWCHAR)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset);
+				StringU.Length = KeyInfo->Node.ClassLength;
+				StringU.MaximumLength = KeyInfo->Node.ClassLength;
+				RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
+				lpClass[StringA.Length] = 0;
+				*lpcbClass = StringA.Length;
+				StringU.Buffer = KeyInfo->Node.Name;
+				StringU.Length = KeyInfo->Node.NameLength;
+				StringU.MaximumLength = KeyInfo->Node.NameLength;
+			}
 		}
-	    }
+
+		if (ErrorCode == ERROR_SUCCESS)
+		{
+			StringA.Buffer = lpName;
+			StringA.Length = 0;
+			StringA.MaximumLength = *lpcbName;
+			RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
+			lpName[StringA.Length] = 0;
+			*lpcbName = StringA.Length;
+			if (lpftLastWriteTime != NULL)
+			{
+				if (lpClass == NULL)
+				{
+					lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;
+					lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
+				}
+				else
+				{
+					lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;
+					lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
+				}
+			}
+		}
 	}
-    }
 
-  DPRINT("Key Namea0 Length %d\n", StringU.Length);
-  DPRINT("Key Namea1 Length %d\n", NameLength);
-  DPRINT("Key Namea Length %d\n", *lpcbName);
-  DPRINT("Key Namea %s\n", lpName);
+	DPRINT("Key Namea0 Length %d\n", StringU.Length);
+	DPRINT("Key Namea1 Length %d\n", NameLength);
+	DPRINT("Key Namea Length %d\n", *lpcbName);
+	DPRINT("Key Namea %s\n", lpName);
 
-  RtlFreeHeap (ProcessHeap,
-	       0,
-	       KeyInfo);
+	RtlFreeHeap (ProcessHeap,
+		0,
+		KeyInfo);
 
-  if (ErrorCode != ERROR_SUCCESS)
-    {
-      SetLastError(ErrorCode);
-    }
+	if (ErrorCode != ERROR_SUCCESS)
+	{
+		SetLastError(ErrorCode);
+	}
 
-  return ErrorCode;
+	return ErrorCode;
 }
 
 
@@ -1174,161 +1171,222 @@
 RegEnumValueA (HKEY hKey,
 	       DWORD dwIndex,
 	       LPSTR lpValueName,
-	       LPDWORD lpcbValueName,
+	       LPDWORD lpcbValueName, // lpValueName buffer len
 	       LPDWORD lpReserved,
 	       LPDWORD lpType,
 	       LPBYTE lpData,
-	       LPDWORD lpcbData)
+	       LPDWORD lpcbData) // lpData buffer len
 {
-  union
-  {
-    KEY_VALUE_FULL_INFORMATION Full;
-    KEY_VALUE_BASIC_INFORMATION Basic;
-  } *ValueInfo;
+	union
+	{
+		KEY_VALUE_FULL_INFORMATION Full;
+		KEY_VALUE_BASIC_INFORMATION	Basic;
+	} *ValueInfo;
 
-  ULONG NameLength;
-  ULONG BufferSize;
-  ULONG DataLength = 0;
-  ULONG ResultSize;
-  HANDLE KeyHandle;
-  LONG ErrorCode;
-  NTSTATUS Status;
-  UNICODE_STRING StringU;
-  ANSI_STRING StringA;
-  BOOL IsStringType;
+	ULONG NameLength;
+	ULONG BufferSize;
+	ULONG DataLength = 0;
+	ULONG ResultSize;
+	HANDLE KeyHandle;
+	LONG ErrorCode;
+	NTSTATUS Status;
+	UNICODE_STRING StringU;
+	ANSI_STRING	StringA;
+	BOOL IsStringType;
 
-  ErrorCode = ERROR_SUCCESS;
+	ErrorCode =	ERROR_SUCCESS;
 
-  Status = MapDefaultKey (&KeyHandle,
-			  hKey);
-  if (!NT_SUCCESS(Status))
-    {
-      ErrorCode = RtlNtStatusToDosError (Status);
-      SetLastError (ErrorCode);
-      return ErrorCode;
-    }
+	Status = MapDefaultKey (&KeyHandle, hKey);
+	if (!NT_SUCCESS(Status))
+	{
+		ErrorCode =	RtlNtStatusToDosError (Status);
+		SetLastError (ErrorCode);
+		return ErrorCode;
+	}
 
-  if (*lpcbValueName > 0)
-    {
-      NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
-    }
-  else
-    {
-      NameLength = 0;
-    }
+	if (*lpcbValueName > 0)
+		NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
+	else
+		NameLength = 0;
 
-  if (lpData)
-    {
-      DataLength = min (*lpcbData * sizeof(WCHAR), REG_MAX_DATA_SIZE);
-      BufferSize = ((sizeof(KEY_VALUE_FULL_INFORMATION) + NameLength + 3) & ~3) + DataLength;
-    }
-  else
-    {
-      BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
-    }
+	if (lpData)
+	{
+		DataLength = min (*lpcbData	* sizeof(WCHAR), REG_MAX_DATA_SIZE);
+		BufferSize = ((sizeof(KEY_VALUE_FULL_INFORMATION) +	NameLength + 3)	& ~3) +	DataLength;
+	}
+	else
+	{
+		BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
+	}
 
-  ValueInfo = RtlAllocateHeap (ProcessHeap,
-			       0,
-			       BufferSize);
-  if (ValueInfo == NULL)
-    {
-      SetLastError(ERROR_OUTOFMEMORY);
-      return ERROR_OUTOFMEMORY;
-    }
+	ValueInfo =	RtlAllocateHeap	(ProcessHeap, 0, BufferSize);
+	if (ValueInfo == NULL)
+	{
+		SetLastError(ERROR_OUTOFMEMORY);
+		return ERROR_OUTOFMEMORY;
+	}
 
-  Status = NtEnumerateValueKey (KeyHandle,
-				(ULONG)dwIndex,
-				lpData ? KeyValueFullInformation : KeyValueBasicInformation,
-				ValueInfo,
-				BufferSize,
-				&ResultSize);
+	Status = NtEnumerateValueKey (KeyHandle,
+		(ULONG)dwIndex,
+		lpData ? KeyValueFullInformation : KeyValueBasicInformation,
+		ValueInfo,
+		BufferSize,
+		&ResultSize);
 
-  DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
-  if (!NT_SUCCESS(Status))
-    {
-      ErrorCode = RtlNtStatusToDosError (Status);
-    }
-  else
-    {
-      if (lpData)
-        {
-	  IsStringType = (ValueInfo->Full.Type == REG_SZ) ||
-			 (ValueInfo->Full.Type == REG_MULTI_SZ) ||
-			 (ValueInfo->Full.Type == REG_EXPAND_SZ);
-	  if (ValueInfo->Full.NameLength > NameLength ||
-	      (!IsStringType && ValueInfo->Full.DataLength > *lpcbData) ||
-	      ValueInfo->Full.DataLength > DataLength)
-	    {
-	      ErrorCode = ERROR_BUFFER_OVERFLOW;
-	    }
-	  else
-	    {
-	      if (IsStringType)
-	        {
-		  StringU.Buffer = (PWCHAR)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset);
-		  StringU.Length = ValueInfo->Full.DataLength;
-		  StringU.MaximumLength = DataLength;
-		  StringA.Buffer = (PCHAR)lpData;
-		  StringA.Length = 0;
-		  StringA.MaximumLength = *lpcbData;
-		  RtlUnicodeStringToAnsiString (&StringA,
-						&StringU,
-						FALSE);
-		  *lpcbData = StringA.Length;
-		}
-	      else
+	DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
+	if (!NT_SUCCESS(Status))
+	{
+		ErrorCode =	RtlNtStatusToDosError (Status);
+
+		// handle case when BufferSize was too small
+		// we must let caller know the minimum accepted size
+		// and value type
+		if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
 		{
-		  RtlCopyMemory (lpData,
-				 (PVOID)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset),
-				 ValueInfo->Full.DataLength);
-		  *lpcbData = ValueInfo->Full.DataLength;
+			ErrorCode = ERROR_MORE_DATA;
+
+			// query now with the sufficient buffer size
+			RtlFreeHeap	(ProcessHeap, 0, ValueInfo);
+			BufferSize = ResultSize;
+			ValueInfo =	RtlAllocateHeap	(ProcessHeap, 0, BufferSize); // will be freed at the bottom, as usual
+			if (ValueInfo == NULL)
+			{
+				SetLastError(ERROR_OUTOFMEMORY);
+				return ERROR_OUTOFMEMORY;
+			}
+
+			Status = NtEnumerateValueKey (KeyHandle,
+										(ULONG)dwIndex,
+										lpData ? KeyValueFullInformation : KeyValueBasicInformation,
+										ValueInfo,
+										BufferSize,
+										&ResultSize);
+			if (!NT_SUCCESS(Status))
+			{
+				// ok, some other error
+				ErrorCode =	RtlNtStatusToDosError (Status);
+			}
+			else
+			{
+				// we have information now, pass it to the caller
+				// but don't touch valueName length here
+				IsStringType = (ValueInfo->Full.Type ==	REG_SZ)	||
+							(ValueInfo->Full.Type == REG_MULTI_SZ) ||
+							(ValueInfo->Full.Type == REG_EXPAND_SZ); //FIXME: Include REG_LINK ?
+
+				if (lpData)
+				{
+					if (lpcbData)
+					{
+						if (IsStringType)
+							*lpcbData = ValueInfo->Full.DataLength / sizeof(WCHAR);
+						else
+							*lpcbData = ValueInfo->Full.DataLength;
+					}
+				}
+
+				// pass type also
+				if (lpType)
+					*lpType	= lpData ? ValueInfo->Full.Type	: ValueInfo->Basic.Type;
+			}            
 		}
-
-	      StringU.Buffer = ValueInfo->Full.Name;
-	      StringU.Length = ValueInfo->Full.NameLength;
-	      StringU.MaximumLength = NameLength;
-	    }
 	}
-      else
+	else
 	{
-	  if (ValueInfo->Basic.NameLength > NameLength)
-	    {
-	      ErrorCode = ERROR_BUFFER_OVERFLOW;
-	    }
-	  else
-	    {
-	      StringU.Buffer = ValueInfo->Basic.Name;
-	      StringU.Length = ValueInfo->Basic.NameLength;
-	      StringU.MaximumLength = NameLength;
-	    }
-	}
+		if (lpData)
+		{
+			IsStringType = (ValueInfo->Full.Type ==	REG_SZ)	||
+				(ValueInfo->Full.Type == REG_MULTI_SZ) ||
+				(ValueInfo->Full.Type == REG_EXPAND_SZ);
+			if (ValueInfo->Full.NameLength > NameLength	||
+				(!IsStringType && ValueInfo->Full.DataLength > *lpcbData) ||
+				ValueInfo->Full.DataLength > DataLength)
+			{
+				// overflow data
+				ErrorCode =	ERROR_MORE_DATA;
 
-      if (ErrorCode == ERROR_SUCCESS)
-        {
-	  StringA.Buffer = (PCHAR)lpValueName;
-	  StringA.Length = 0;
-	  StringA.MaximumLength = *lpcbValueName;
-	  RtlUnicodeStringToAnsiString (&StringA,
-					&StringU,
-					FALSE);
-	  StringA.Buffer[StringA.Length] = 0;
-	  *lpcbValueName = StringA.Length;
-	  if (lpType)
-	    {
-	      *lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type;
-	    }
+				// return correct information for data length and type
+                if (lpcbData)
+				{
+					if (IsStringType)
+						*lpcbData = ValueInfo->Full.DataLength / sizeof(WCHAR);
+					else
+						*lpcbData = ValueInfo->Full.DataLength;
+				}
+
+				if (lpType)
+					*lpType	= ValueInfo->Full.Type;
+			}
+			else
+			{
+				if (IsStringType)
+				{
+					StringU.Buffer = (PWCHAR)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset);
+					StringU.Length = ValueInfo->Full.DataLength;
+					StringU.MaximumLength =	DataLength;
+					StringA.Buffer = (PCHAR)lpData;
+					StringA.Length = 0;
+					StringA.MaximumLength =	*lpcbData;
+					RtlUnicodeStringToAnsiString (&StringA,	&StringU, FALSE);
+					*lpcbData =	StringA.Length;
+				}
+				else
+				{
+					RtlCopyMemory (lpData,
+						(PVOID)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset),
+						ValueInfo->Full.DataLength);
+					*lpcbData =	ValueInfo->Full.DataLength;
+				}
+
+				StringU.Buffer = ValueInfo->Full.Name;
+				StringU.Length = ValueInfo->Full.NameLength;
+				StringU.MaximumLength =	NameLength;
+			}
+		}
+		else
+		{
+			if (ValueInfo->Basic.NameLength	> NameLength)
+			{
+				// overflow name
+				ErrorCode =	ERROR_MORE_DATA;
+
+				if (IsStringType)
+					*lpcbData = ValueInfo->Full.DataLength / sizeof(WCHAR);
+				else
+					*lpcbData = ValueInfo->Full.DataLength;
+
+				if (lpType)
+					*lpType	= ValueInfo->Basic.Type;
+			}
+			else
+			{
+				StringU.Buffer = ValueInfo->Basic.Name;
+				StringU.Length = ValueInfo->Basic.NameLength;
+				StringU.MaximumLength =	NameLength;
+			}
+		}
+
+		if (ErrorCode == ERROR_SUCCESS)
+		{
+			StringA.Buffer = (PCHAR)lpValueName;
+			StringA.Length = 0;
+			StringA.MaximumLength =	*lpcbValueName;
+			RtlUnicodeStringToAnsiString (&StringA,	&StringU, FALSE);
+			StringA.Buffer[StringA.Length] = 0;
+			*lpcbValueName = StringA.Length;
+			if (lpType)
+			{
+				*lpType	= lpData ? ValueInfo->Full.Type	: ValueInfo->Basic.Type;
+			}
+		}
 	}
-    }
 
-  RtlFreeHeap (ProcessHeap,
-	       0,
-	       ValueInfo);
-  if (ErrorCode != ERROR_SUCCESS)
-    {
-      SetLastError(ErrorCode);
-    }
+	RtlFreeHeap	(ProcessHeap, 0, ValueInfo);
 
-  return ErrorCode;
+	if (ErrorCode != ERROR_SUCCESS)
+		SetLastError(ErrorCode);
+
+	return ErrorCode;
 }
 
 
@@ -1347,127 +1405,170 @@
 	       LPBYTE lpData,
 	       LPDWORD lpcbData)
 {
-  union
-  {
-    KEY_VALUE_FULL_INFORMATION Full;
-    KEY_VALUE_BASIC_INFORMATION Basic;
-  } *ValueInfo;
+	union
+	{
+		KEY_VALUE_FULL_INFORMATION Full;
+		KEY_VALUE_BASIC_INFORMATION Basic;
+	} *ValueInfo;
 
-  ULONG NameLength;
-  ULONG BufferSize;
-  ULONG DataLength = 0;
-  ULONG ResultSize;
-  HANDLE KeyHandle;
-  LONG ErrorCode;
-  NTSTATUS Status;
+	ULONG NameLength;
+	ULONG BufferSize;
+	ULONG DataLength = 0;
+	ULONG ResultSize;
+	HANDLE KeyHandle;
+	LONG ErrorCode;
+	NTSTATUS Status;
 
-  ErrorCode = ERROR_SUCCESS;
+	ErrorCode = ERROR_SUCCESS;
 
-  Status = MapDefaultKey (&KeyHandle,
-			  hKey);
-  if (!NT_SUCCESS(Status))
-    {
-      ErrorCode = RtlNtStatusToDosError (Status);
-      SetLastError (ErrorCode);
-      return ErrorCode;
-    }
+	Status = MapDefaultKey (&KeyHandle, hKey);
+	if (!NT_SUCCESS(Status))
+	{
+		ErrorCode = RtlNtStatusToDosError (Status);
+		SetLastError (ErrorCode);
+		return ErrorCode;
+	}
 
-  if (*lpcbValueName > 0)
-    {
-      NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
-    }
-  else
-    {
-      NameLength = 0;
-    }
+	if (*lpcbValueName > 0)
+		NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
+	else
+		NameLength = 0;
 
-  if (lpData)
-    {
-      DataLength = min(*lpcbData, REG_MAX_DATA_SIZE);
-      BufferSize = ((sizeof(KEY_VALUE_FULL_INFORMATION) + NameLength + 3) & ~3) + DataLength;
-    }
-  else
-    {
-      BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
-    }
-  ValueInfo = RtlAllocateHeap (ProcessHeap,
-			       0,
-			       BufferSize);
-  if (ValueInfo == NULL)
-    {
-      SetLastError (ERROR_OUTOFMEMORY);
-      return ERROR_OUTOFMEMORY;
-    }
-  Status = NtEnumerateValueKey (KeyHandle,
-				(ULONG)dwIndex,
-				lpData ? KeyValueFullInformation : KeyValueBasicInformation,
-				ValueInfo,
-				BufferSize,
-				&ResultSize);
-
-  DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
-  if (!NT_SUCCESS(Status))
-    {
-      ErrorCode = RtlNtStatusToDosError (Status);
-    }
-  else
-    {
-      if (lpData)
+	if (lpData)
 	{
-	  if (ValueInfo->Full.DataLength > DataLength ||
-	      ValueInfo->Full.NameLength > NameLength)
-	    {
-	      ErrorCode = ERROR_BUFFER_OVERFLOW;
-	    }
-	  else
-	    {
-	      RtlCopyMemory (lpValueName,
-			     ValueInfo->Full.Name,
-			     ValueInfo->Full.NameLength);
-	      *lpcbValueName = (DWORD)(ValueInfo->Full.NameLength / sizeof(WCHAR));
-	      lpValueName[*lpcbValueName] = 0;
-	      RtlCopyMemory (lpData,
-			     (PVOID)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset),
-			     ValueInfo->Full.DataLength);
-	      *lpcbData = (DWORD)ValueInfo->Full.DataLength;
-	    }
+		DataLength = min(*lpcbData, REG_MAX_DATA_SIZE);
+		BufferSize = ((sizeof(KEY_VALUE_FULL_INFORMATION) + NameLength + 3) & ~3) + DataLength;
 	}
-      else
+	else
 	{
-	  if (ValueInfo->Basic.NameLength > NameLength)
-	    {
-	      ErrorCode = ERROR_BUFFER_OVERFLOW;
-	    }
-	  else
-	    {
-	      RtlCopyMemory (lpValueName,
-			     ValueInfo->Basic.Name,
-			     ValueInfo->Basic.NameLength);
-	      *lpcbValueName = (DWORD)(ValueInfo->Basic.NameLength / sizeof(WCHAR));
-	      lpValueName[*lpcbValueName] = 0;
-	    }
-	  if (NULL != lpcbData)
-	    {
-	      *lpcbData = (DWORD)ValueInfo->Full.DataLength;
-	    }
+		BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
 	}
+	ValueInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
+	if (ValueInfo == NULL)
+	{
+		SetLastError (ERROR_OUTOFMEMORY);
+		return ERROR_OUTOFMEMORY;
+	}
+	Status = NtEnumerateValueKey (KeyHandle,
+		(ULONG)dwIndex,
+		lpData ? KeyValueFullInformation : KeyValueBasicInformation,
+		ValueInfo,
+		BufferSize,
+		&ResultSize);
 
-      if (ErrorCode == ERROR_SUCCESS && lpType != NULL)
+	DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
+	if (!NT_SUCCESS(Status))
 	{
-	  *lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type;
+		ErrorCode = RtlNtStatusToDosError (Status);
+
+		// handle case when BufferSize was too small
+		// we must let caller know the minimum accepted size
+		// and value type
+		if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
+		{
+			ErrorCode = ERROR_MORE_DATA;
+
+			// query now with the sufficient buffer size
+			RtlFreeHeap	(ProcessHeap, 0, ValueInfo);
+			BufferSize = ResultSize;
+			ValueInfo =	RtlAllocateHeap	(ProcessHeap, 0, BufferSize); // will be freed at the bottom, as usual
+			if (ValueInfo == NULL)
+			{
+				SetLastError(ERROR_OUTOFMEMORY);
+				return ERROR_OUTOFMEMORY;
+			}
+
+			Status = NtEnumerateValueKey (KeyHandle,
+										(ULONG)dwIndex,
+										lpData ? KeyValueFullInformation : KeyValueBasicInformation,
+										ValueInfo,
+										BufferSize,
+										&ResultSize);
+			if (!NT_SUCCESS(Status))
+			{
+				// ok, some other error
+				ErrorCode =	RtlNtStatusToDosError (Status);
+			}
+			else
+			{
+				// we have information now, pass it to the caller
+				// but don't touch valueName length here
+				if (lpData && lpcbData)
+					*lpcbData = ValueInfo->Full.DataLength;
+
+				// pass type also
+				if (lpType)
+					*lpType	= lpData ? ValueInfo->Full.Type	: ValueInfo->Basic.Type;
+			}
+		}
 	}
-    }
+	else
+	{
+		if (lpData)
+		{
+			if (ValueInfo->Full.DataLength > DataLength ||
+				ValueInfo->Full.NameLength > NameLength)
+			{
+				// overflow data
+				ErrorCode =	ERROR_MORE_DATA;
 
-  RtlFreeHeap (ProcessHeap,
-	       0,
-	       ValueInfo);
+				// return correct information for data length and type
+                if (lpcbData)
+					*lpcbData = ValueInfo->Full.DataLength;
 
-  if (ErrorCode != ERROR_SUCCESS)
-    {
-      SetLastError (ErrorCode);
-    }
+				if (lpType)
+					*lpType	= ValueInfo->Full.Type;
+			}
+			else
+			{
+				RtlCopyMemory (lpValueName, ValueInfo->Full.Name, ValueInfo->Full.NameLength);
+				*lpcbValueName = (DWORD)(ValueInfo->Full.NameLength / sizeof(WCHAR));
+				lpValueName[*lpcbValueName] = 0;
+				RtlCopyMemory (lpData,
+					(PVOID)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset),
+					ValueInfo->Full.DataLength);
+				*lpcbData = (DWORD)ValueInfo->Full.DataLength;
+			}
+		}
+		else
+		{
+			if (ValueInfo->Basic.NameLength > NameLength)
+			{
+				// overflow name
+				ErrorCode =	ERROR_MORE_DATA;
 
-  return ErrorCode;
+                if (lpcbData)
+					*lpcbData = ValueInfo->Full.DataLength;
+
+				if (lpType)
+					*lpType	= ValueInfo->Basic.Type;
+			}
+			else
+			{
+				RtlCopyMemory (lpValueName, ValueInfo->Basic.Name, ValueInfo->Basic.NameLength);
+				*lpcbValueName = (DWORD)(ValueInfo->Basic.NameLength / sizeof(WCHAR));
+				lpValueName[*lpcbValueName] = 0;
+			}
+
+			if (NULL != lpcbData)
+			{
+				*lpcbData = (DWORD)ValueInfo->Full.DataLength;
+				DPRINT1("BUG: Using ValueInfo as FULL when it is really BASIC\n");
+			}
+		}
+
+		if (ErrorCode == ERROR_SUCCESS && lpType != NULL)
+		{
+			*lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type;
+		}
+	}
+
+	RtlFreeHeap (ProcessHeap, 0, ValueInfo);
+
+	if (ErrorCode != ERROR_SUCCESS)
+		SetLastError (ErrorCode);
+
+	return ErrorCode;
 }
 
 
@@ -1741,7 +1842,7 @@
     {
       ErrorCode = RtlNtStatusToDosError (Status);
       SetLastError (ErrorCode);
-      return ErrorCode;
+      return Status;
     }
 
   RtlCreateUnicodeStringFromAsciiz (&SubKeyString,
@@ -1796,7 +1897,7 @@
     {
       ErrorCode = RtlNtStatusToDosError (Status);
       SetLastError (ErrorCode);
-      return ErrorCode;
+      return Status;
     }
 
   RtlInitUnicodeString (&SubKeyString,