mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 14:05:42 +00:00
[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:
parent
e854412f52
commit
91d04ae3c1
3 changed files with 324 additions and 158 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue