[ADVAPI32]

- Fix a stupid crash I introduced in RegQueryValueExA
 - Reimplement RegEnumKeyExA as wrapper around RegEnumKeyExW
 - Implement RegEnumKeyExW for HKCR subkeys
 - Fix a few potential handle leaks
CORE-8582

svn path=/trunk/; revision=64445
This commit is contained in:
Jérôme Gardou 2014-10-01 22:51:44 +00:00
parent e854412f52
commit 91d04ae3c1
3 changed files with 324 additions and 158 deletions

View file

@ -263,7 +263,7 @@ CreateHKCRKey(
}
/* See if the subkey already exists in HKCU. */
ErrorCode = RegOpenKeyExW(QueriedKey, lpSubKey, 0, KEY_READ, &TestKey);
ErrorCode = RegOpenKeyExW(QueriedKey, lpSubKey, 0, 0, &TestKey);
if (ErrorCode != ERROR_FILE_NOT_FOUND)
{
if (ErrorCode == ERROR_SUCCESS)
@ -585,3 +585,217 @@ SetHKCRValue(
return ErrorCode;
}
/* HKCR version of RegEnumKeyExW */
LONG
WINAPI
EnumHKCRKey(
_In_ HKEY hKey,
_In_ DWORD dwIndex,
_Out_ LPWSTR lpName,
_Inout_ LPDWORD lpcbName,
_Reserved_ LPDWORD lpReserved,
_Out_opt_ LPWSTR lpClass,
_Inout_opt_ LPDWORD lpcbClass,
_Out_opt_ PFILETIME lpftLastWriteTime)
{
HKEY PreferredKey, FallbackKey;
DWORD NumPreferredSubKeys;
DWORD MaxFallbackSubKeyLen;
DWORD FallbackIndex;
WCHAR* FallbackSubKeyName = NULL;
LONG ErrorCode;
ASSERT(IsHKCRKey(hKey));
/* Remove the HKCR flag while we're working */
hKey = (HKEY)(((ULONG_PTR)hKey) & ~0x2);
/* Get the preferred key */
ErrorCode = GetPreferredHKCRKey(hKey, &PreferredKey);
if (ErrorCode != ERROR_SUCCESS)
{
if (ErrorCode == ERROR_FILE_NOT_FOUND)
{
/* Only the HKLM key exists */
return RegEnumKeyExW(
hKey,
dwIndex,
lpName,
lpcbName,
lpReserved,
lpClass,
lpcbClass,
lpftLastWriteTime);
}
return ErrorCode;
}
/* Get the fallback key */
ErrorCode = GetFallbackHKCRKey(hKey, &FallbackKey, FALSE);
if (ErrorCode != ERROR_SUCCESS)
{
if (PreferredKey != hKey)
RegCloseKey(PreferredKey);
if (ErrorCode == ERROR_FILE_NOT_FOUND)
{
/* Only the HKCU key exists */
return RegEnumKeyExW(
hKey,
dwIndex,
lpName,
lpcbName,
lpReserved,
lpClass,
lpcbClass,
lpftLastWriteTime);
}
return ErrorCode;
}
/* Get some info on the HKCU side */
ErrorCode = RegQueryInfoKeyW(
PreferredKey,
NULL,
NULL,
NULL,
&NumPreferredSubKeys,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
if (ErrorCode != ERROR_SUCCESS)
goto Exit;
if (dwIndex < NumPreferredSubKeys)
{
/* HKCU side takes precedence */
ErrorCode = RegEnumKeyExW(
PreferredKey,
dwIndex,
lpName,
lpcbName,
lpReserved,
lpClass,
lpcbClass,
lpftLastWriteTime);
goto Exit;
}
/* Here it gets tricky. We must enumerate the values from the HKLM side,
* without reporting those which are present on the HKCU side */
/* Squash out the indices from HKCU */
dwIndex -= NumPreferredSubKeys;
/* Get some info */
ErrorCode = RegQueryInfoKeyW(
FallbackKey,
NULL,
NULL,
NULL,
NULL,
&MaxFallbackSubKeyLen,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
if (ErrorCode != ERROR_SUCCESS)
{
ERR("Could not query info of key %p (Err: %d)\n", FallbackKey, ErrorCode);
goto Exit;
}
ERR("Maxfallbacksubkeylen: %d\n", MaxFallbackSubKeyLen);
/* Allocate our buffer */
FallbackSubKeyName = RtlAllocateHeap(
RtlGetProcessHeap(), 0, (MaxFallbackSubKeyLen + 1) * sizeof(WCHAR));
if (!FallbackSubKeyName)
{
ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
goto Exit;
}
/* We must begin at the very first subkey of the fallback key,
* and then see if we meet keys that already are in the preferred key.
* In that case, we must bump dwIndex, as otherwise we would enumerate a key we already
* saw in a previous call.
*/
FallbackIndex = 0;
while (TRUE)
{
HKEY PreferredSubKey;
DWORD FallbackSubkeyLen = MaxFallbackSubKeyLen;
/* Try enumerating */
ErrorCode = RegEnumKeyExW(
FallbackKey,
FallbackIndex,
FallbackSubKeyName,
&FallbackSubkeyLen,
NULL,
NULL,
NULL,
NULL);
if (ErrorCode != ERROR_SUCCESS)
{
/* Most likely ERROR_NO_MORE_ITEMS */
ERR("Returning %d.\n", ErrorCode);
goto Exit;
}
FallbackSubKeyName[FallbackSubkeyLen] = L'\0';
/* See if there is such a value on HKCU side */
ErrorCode = RegOpenKeyExW(
PreferredKey,
FallbackSubKeyName,
0,
0,
&PreferredSubKey);
if (ErrorCode == ERROR_SUCCESS)
{
RegCloseKey(PreferredSubKey);
/* So we already enumerated it on HKCU side. */
dwIndex++;
}
else if (ErrorCode != ERROR_FILE_NOT_FOUND)
{
ERR("Got error %d while querying for %s on HKCU side.\n", ErrorCode, FallbackSubKeyName);
goto Exit;
}
/* See if we caught up */
if (FallbackIndex == dwIndex)
break;
FallbackIndex++;
}
/* We can finally enumerate on the fallback side */
ErrorCode = RegEnumKeyExW(
FallbackKey,
dwIndex,
lpName,
lpcbName,
lpReserved,
lpClass,
lpcbClass,
lpftLastWriteTime);
Exit:
if (PreferredKey != hKey)
RegCloseKey(PreferredKey);
if (FallbackKey != hKey)
RegCloseKey(FallbackKey);
if (FallbackSubKeyName)
RtlFreeHeap(RtlGetProcessHeap(), 0, FallbackSubKeyName);
return ErrorCode;
}

View file

@ -1306,7 +1306,11 @@ RegDeleteKeyExW(
}
if (IsHKCRKey(ParentKey))
return DeleteHKCRKey(ParentKey, lpSubKey, samDesired, Reserved);
{
LONG ErrorCode = DeleteHKCRKey(ParentKey, lpSubKey, samDesired, Reserved);
ClosePredefKey(ParentKey);
return ErrorCode;
}
if (samDesired & KEY_WOW64_32KEY)
ERR("Wow64 not yet supported!\n");
@ -2442,166 +2446,81 @@ RegEnumKeyW(HKEY hKey,
*
* @implemented
*/
LONG WINAPI
RegEnumKeyExA(HKEY hKey,
DWORD dwIndex,
LPSTR lpName,
LPDWORD lpcbName,
LPDWORD lpReserved,
LPSTR lpClass,
LPDWORD lpcbClass,
PFILETIME lpftLastWriteTime)
LONG
WINAPI
RegEnumKeyExA(
_In_ HKEY hKey,
_In_ DWORD dwIndex,
_Out_ LPSTR lpName,
_Inout_ LPDWORD lpcbName,
_Reserved_ LPDWORD lpReserved,
_Out_opt_ LPSTR lpClass,
_Inout_opt_ LPDWORD lpcbClass,
_Out_opt_ PFILETIME lpftLastWriteTime)
{
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;
ULONG ResultSize;
HANDLE KeyHandle;
NTSTATUS Status;
TRACE("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))
{
return ERROR_INVALID_PARAMETER;
}
Status = MapDefaultKey(&KeyHandle, hKey);
if (!NT_SUCCESS(Status))
{
return RtlNtStatusToDosError(Status);
}
WCHAR* NameBuffer = NULL;
WCHAR* ClassBuffer = NULL;
DWORD NameLength, ClassLength;
LONG ErrorCode;
/* Allocate our buffers */
if (*lpcbName > 0)
{
NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
}
else
{
NameLength = 0;
NameLength = *lpcbName;
NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbName * sizeof(WCHAR));
if (NameBuffer == NULL)
{
ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
goto Exit;
}
}
if (lpClass)
{
if (*lpcbClass > 0)
{
ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
ClassLength = *lpcbClass;
ClassBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbClass * sizeof(WCHAR));
if (ClassBuffer == NULL)
{
ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
goto Exit;
}
}
else
{
ClassLength = 0;
}
/* The class name should start at a dword boundary */
BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
}
else
/* Do the actual call */
ErrorCode = RegEnumKeyExW(
hKey,
dwIndex,
NameBuffer,
lpcbName,
lpReserved,
ClassBuffer,
lpcbClass,
lpftLastWriteTime);
if (ErrorCode != ERROR_SUCCESS)
goto Exit;
/* Convert the strings */
RtlUnicodeToMultiByteN(lpName, *lpcbName, 0, NameBuffer, *lpcbName * sizeof(WCHAR));
/* NULL terminate if we can */
if (NameLength > *lpcbName)
lpName[*lpcbName] = '\0';
if (lpClass)
{
BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
RtlUnicodeToMultiByteN(lpClass, *lpcbClass, 0, NameBuffer, *lpcbClass * sizeof(WCHAR));
if (ClassLength > *lpcbClass)
lpClass[*lpcbClass] = '\0';
}
KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
if (KeyInfo == NULL)
{
ErrorCode = ERROR_OUTOFMEMORY;
goto Cleanup;
}
Status = NtEnumerateKey(KeyHandle,
(ULONG)dwIndex,
lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
KeyInfo,
BufferSize,
&ResultSize);
TRACE("NtEnumerateKey() returned status 0x%X\n", Status);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
}
else
{
if (lpClass == NULL)
{
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
{
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;
}
}
}
}
/*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */
TRACE("Key Name1 Length %d\n", NameLength);
TRACE("Key Name Length %d\n", *lpcbName);
TRACE("Key Name %s\n", lpName);
RtlFreeHeap(ProcessHeap,
0,
KeyInfo);
Cleanup:
ClosePredefKey(KeyHandle);
Exit:
if (NameBuffer)
RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
if (ClassBuffer)
RtlFreeHeap(RtlGetProcessHeap(), 0, ClassBuffer);
return ErrorCode;
}
@ -2612,15 +2531,17 @@ Cleanup:
*
* @implemented
*/
LONG WINAPI
RegEnumKeyExW(HKEY hKey,
DWORD dwIndex,
LPWSTR lpName,
LPDWORD lpcbName,
LPDWORD lpReserved,
LPWSTR lpClass,
LPDWORD lpcbClass,
PFILETIME lpftLastWriteTime)
LONG
WINAPI
RegEnumKeyExW(
_In_ HKEY hKey,
_In_ DWORD dwIndex,
_Out_ LPWSTR lpName,
_Inout_ LPDWORD lpcbName,
_Reserved_ LPDWORD lpReserved,
_Out_opt_ LPWSTR lpClass,
_Inout_opt_ LPDWORD lpcbClass,
_Out_opt_ PFILETIME lpftLastWriteTime)
{
union
{
@ -2643,6 +2564,21 @@ RegEnumKeyExW(HKEY hKey,
return RtlNtStatusToDosError(Status);
}
if (IsHKCRKey(KeyHandle))
{
ErrorCode = EnumHKCRKey(
KeyHandle,
dwIndex,
lpName,
lpcbName,
lpReserved,
lpClass,
lpcbClass,
lpftLastWriteTime);
ClosePredefKey(KeyHandle);
return ErrorCode;
}
if (*lpcbName > 0)
{
NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
@ -3419,7 +3355,11 @@ RegOpenKeyExW(HKEY hKey,
}
if (IsHKCRKey(KeyHandle))
return OpenHKCRKey(KeyHandle, lpSubKey, ulOptions, samDesired, phkResult);
{
ErrorCode = OpenHKCRKey(KeyHandle, lpSubKey, ulOptions, samDesired, phkResult);
ClosePredefKey(KeyHandle);
return ErrorCode;
}
if (ulOptions & REG_OPTION_OPEN_LINK)
Attributes |= OBJ_OPENLINK;
@ -4035,7 +3975,7 @@ RegQueryValueExA(
ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, NULL, &LocalType, NULL, &BufferSize);
if (ErrorCode != ERROR_SUCCESS)
{
if (!data)
if ((!data) && count)
*count = 0;
RtlFreeUnicodeString(&nameW);
return ErrorCode;

View file

@ -72,3 +72,15 @@ SetHKCRValue(
_In_ CONST BYTE* Data,
_In_ DWORD DataSize);
LONG
WINAPI
EnumHKCRKey(
_In_ HKEY hKey,
_In_ DWORD dwIndex,
_Out_ LPWSTR lpName,
_Inout_ LPDWORD lpcbName,
_Reserved_ LPDWORD lpReserved,
_Out_opt_ LPWSTR lpClass,
_Inout_opt_ LPDWORD lpcbClass,
_Out_opt_ PFILETIME lpftLastWriteTime);