/* INCLUDES *****************************************************************/
#include <advapi32.h>
+
+#include <ndk/cmfuncs.h>
+#include <pseh/pseh2.h>
+
+#include "reg.h"
+
WINE_DEFAULT_DEBUG_CHANNEL(reg);
/* DEFINES ******************************************************************/
static NTSTATUS
-OpenClassesRootKey(PHANDLE KeyHandle)
+OpenClassesRootKey(_Out_ PHANDLE KeyHandle)
{
OBJECT_ATTRIBUTES Attributes;
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\CLASSES");
+ NTSTATUS Status;
TRACE("OpenClassesRootKey()\n");
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
- return NtOpenKey(KeyHandle,
- MAXIMUM_ALLOWED,
- &Attributes);
+ Status = NtOpenKey(KeyHandle,
+ MAXIMUM_ALLOWED,
+ &Attributes);
+
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ /* Mark it as HKCR */
+ MakeHKCRKey((HKEY*)KeyHandle);
+
+ return Status;
}
NTSTATUS Status;
/* don't close null handle or a pseudo handle */
- if ((!hKey) || (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000))
+ if (!hKey)
{
return ERROR_INVALID_HANDLE;
}
+ if (((ULONG_PTR)hKey & 0xF0000000) == 0x80000000)
+ {
+ return ERROR_SUCCESS;
+ }
+
Status = NtClose(hKey);
if (!NT_SUCCESS(Status))
{
LocalObjectAttributes.ObjectName = &LocalKeyName;
FullNameLength = LocalKeyName.Length / sizeof(WCHAR);
- LocalKeyHandle = NULL;
+ LocalKeyHandle = NULL;
/* Remove the last part of the key name and try to create the key again. */
while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
* @implemented
*/
LONG WINAPI
-RegCreateKeyExA(HKEY hKey,
- LPCSTR lpSubKey,
- DWORD Reserved,
- LPSTR lpClass,
- DWORD dwOptions,
- REGSAM samDesired,
- LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- PHKEY phkResult,
- LPDWORD lpdwDisposition)
+RegCreateKeyExA(
+ _In_ HKEY hKey,
+ _In_ LPCSTR lpSubKey,
+ _In_ DWORD Reserved,
+ _In_ LPSTR lpClass,
+ _In_ DWORD dwOptions,
+ _In_ REGSAM samDesired,
+ _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ _Out_ PHKEY phkResult,
+ _Out_ LPDWORD lpdwDisposition)
{
UNICODE_STRING SubKeyString;
UNICODE_STRING ClassString;
- OBJECT_ATTRIBUTES Attributes;
- HANDLE ParentKey;
- NTSTATUS Status;
-
- TRACE("RegCreateKeyExA() called\n");
-
- if (lpSecurityAttributes && lpSecurityAttributes->nLength != sizeof(SECURITY_ATTRIBUTES))
- return ERROR_INVALID_USER_BUFFER;
-
- /* get the real parent key */
- Status = MapDefaultKey(&ParentKey,
- hKey);
- if (!NT_SUCCESS(Status))
- {
- return RtlNtStatusToDosError(Status);
- }
+ DWORD ErrorCode;
- TRACE("ParentKey %p\n", ParentKey);
+ RtlInitEmptyUnicodeString(&ClassString, NULL, 0);
+ RtlInitEmptyUnicodeString(&SubKeyString, NULL, 0);
- if (lpClass != NULL)
+ if (lpClass)
{
- RtlCreateUnicodeStringFromAsciiz(&ClassString,
- lpClass);
+ if (!RtlCreateUnicodeStringFromAsciiz(&ClassString, lpClass))
+ {
+ ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ goto Exit;
+ }
}
- RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
- (LPSTR)lpSubKey);
- InitializeObjectAttributes(&Attributes,
- &SubKeyString,
- OBJ_CASE_INSENSITIVE,
- (HANDLE)ParentKey,
- lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL);
- Status = CreateNestedKey(phkResult,
- &Attributes,
- (lpClass == NULL)? NULL : &ClassString,
- dwOptions,
- samDesired,
- lpdwDisposition);
- RtlFreeUnicodeString(&SubKeyString);
- if (lpClass != NULL)
+ if (lpSubKey)
{
- RtlFreeUnicodeString(&ClassString);
+ if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString, lpSubKey))
+ {
+ ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ goto Exit;
+ }
}
- ClosePredefKey(ParentKey);
+ ErrorCode = RegCreateKeyExW(
+ hKey,
+ SubKeyString.Buffer,
+ Reserved,
+ ClassString.Buffer,
+ dwOptions,
+ samDesired,
+ lpSecurityAttributes,
+ phkResult,
+ lpdwDisposition);
- TRACE("Status %x\n", Status);
- if (!NT_SUCCESS(Status))
- {
- return RtlNtStatusToDosError(Status);
- }
+Exit:
+ RtlFreeUnicodeString(&SubKeyString);
+ RtlFreeUnicodeString(&ClassString);
- return ERROR_SUCCESS;
+ return ErrorCode;
}
*
* @implemented
*/
-LONG WINAPI
-RegCreateKeyExW(HKEY hKey,
- LPCWSTR lpSubKey,
- DWORD Reserved,
- LPWSTR lpClass,
- DWORD dwOptions,
- REGSAM samDesired,
- LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- PHKEY phkResult,
- LPDWORD lpdwDisposition)
+LONG
+WINAPI
+RegCreateKeyExW(
+ _In_ HKEY hKey,
+ _In_ LPCWSTR lpSubKey,
+ _In_ DWORD Reserved,
+ _In_opt_ LPWSTR lpClass,
+ _In_ DWORD dwOptions,
+ _In_ REGSAM samDesired,
+ _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ _Out_ PHKEY phkResult,
+ _Out_opt_ LPDWORD lpdwDisposition)
{
UNICODE_STRING SubKeyString;
UNICODE_STRING ClassString;
- OBJECT_ATTRIBUTES Attributes;
+ OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE ParentKey;
+ ULONG Attributes = OBJ_CASE_INSENSITIVE;
NTSTATUS Status;
TRACE("RegCreateKeyExW() called\n");
TRACE("ParentKey %p\n", ParentKey);
+ if (IsHKCRKey(ParentKey))
+ {
+ LONG ErrorCode = CreateHKCRKey(
+ ParentKey,
+ lpSubKey,
+ Reserved,
+ lpClass,
+ dwOptions,
+ samDesired,
+ lpSecurityAttributes,
+ phkResult,
+ lpdwDisposition);
+ ClosePredefKey(ParentKey);
+ return ErrorCode;
+ }
+
+ if (dwOptions & REG_OPTION_OPEN_LINK)
+ Attributes |= OBJ_OPENLINK;
+
RtlInitUnicodeString(&ClassString,
lpClass);
RtlInitUnicodeString(&SubKeyString,
lpSubKey);
- InitializeObjectAttributes(&Attributes,
+ InitializeObjectAttributes(&ObjectAttributes,
&SubKeyString,
- OBJ_CASE_INSENSITIVE,
+ Attributes,
(HANDLE)ParentKey,
lpSecurityAttributes ? (PSECURITY_DESCRIPTOR)lpSecurityAttributes->lpSecurityDescriptor : NULL);
Status = CreateNestedKey(phkResult,
- &Attributes,
+ &ObjectAttributes,
(lpClass == NULL)? NULL : &ClassString,
dwOptions,
samDesired,
*
* @implemented
*/
-LONG WINAPI
-RegDeleteKeyA(HKEY hKey,
- LPCSTR lpSubKey)
+LONG
+WINAPI
+RegDeleteKeyA(
+ _In_ HKEY hKey,
+ _In_ LPCSTR lpSubKey)
{
- OBJECT_ATTRIBUTES ObjectAttributes;
- UNICODE_STRING SubKeyName;
- HANDLE ParentKey;
- HANDLE TargetKey;
- NTSTATUS Status;
+ return RegDeleteKeyExA(hKey, lpSubKey, 0, 0);
+}
- /* Make sure we got a subkey */
- if (!lpSubKey)
- {
- /* Fail */
- return ERROR_INVALID_PARAMETER;
- }
- Status = MapDefaultKey(&ParentKey,
- hKey);
- if (!NT_SUCCESS(Status))
- {
- return RtlNtStatusToDosError(Status);
- }
+/************************************************************************
+ * RegDeleteKeyW
+ *
+ * @implemented
+ */
+LONG
+WINAPI
+RegDeleteKeyW(
+ _In_ HKEY hKey,
+ _In_ LPCWSTR lpSubKey)
+{
+ return RegDeleteKeyExW(hKey, lpSubKey, 0, 0);
+}
- RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
- (LPSTR)lpSubKey);
- InitializeObjectAttributes(&ObjectAttributes,
- &SubKeyName,
- OBJ_CASE_INSENSITIVE,
- ParentKey,
- NULL);
- Status = NtOpenKey(&TargetKey,
- DELETE,
- &ObjectAttributes);
- RtlFreeUnicodeString(&SubKeyName);
- if (!NT_SUCCESS(Status))
+/************************************************************************
+ * RegDeleteKeyExA
+ *
+ * @implemented
+ */
+LONG
+WINAPI
+RegDeleteKeyExA(
+ _In_ HKEY hKey,
+ _In_ LPCSTR lpSubKey,
+ _In_ REGSAM samDesired,
+ _In_ DWORD Reserved)
+{
+ LONG ErrorCode;
+ UNICODE_STRING SubKeyName;
+
+ if (lpSubKey)
{
- goto Cleanup;
+ if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyName, lpSubKey))
+ return ERROR_NOT_ENOUGH_MEMORY;
}
+ else
+ RtlInitEmptyUnicodeString(&SubKeyName, NULL, 0);
- Status = NtDeleteKey(TargetKey);
- NtClose (TargetKey);
-
-Cleanup:
- ClosePredefKey(ParentKey);
+ ErrorCode = RegDeleteKeyExW(hKey, SubKeyName.Buffer, samDesired, Reserved);
- if (!NT_SUCCESS(Status))
- {
- return RtlNtStatusToDosError(Status);
- }
+ RtlFreeUnicodeString(&SubKeyName);
- return ERROR_SUCCESS;
+ return ErrorCode;
}
/************************************************************************
- * RegDeleteKeyW
+ * RegDeleteKeyExW
*
* @implemented
*/
-LONG WINAPI
-RegDeleteKeyW(HKEY hKey,
- LPCWSTR lpSubKey)
+LONG
+WINAPI
+RegDeleteKeyExW(
+ _In_ HKEY hKey,
+ _In_ LPCWSTR lpSubKey,
+ _In_ REGSAM samDesired,
+ _In_ DWORD Reserved)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING SubKeyName;
return RtlNtStatusToDosError(Status);
}
+ if (IsHKCRKey(ParentKey))
+ {
+ LONG ErrorCode = DeleteHKCRKey(ParentKey, lpSubKey, samDesired, Reserved);
+ ClosePredefKey(ParentKey);
+ return ErrorCode;
+ }
+
+ if (samDesired & KEY_WOW64_32KEY)
+ ERR("Wow64 not yet supported!\n");
+
+ if (samDesired & KEY_WOW64_64KEY)
+ ERR("Wow64 not yet supported!\n");
+
+
RtlInitUnicodeString(&SubKeyName,
(LPWSTR)lpSubKey);
InitializeObjectAttributes(&ObjectAttributes,
}
-/************************************************************************
- * RegDeleteKeyExA
- *
- * @unimplemented
- */
-LONG
-WINAPI
-RegDeleteKeyExA(HKEY hKey,
- LPCSTR lpSubKey,
- REGSAM samDesired,
- DWORD Reserved)
-{
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/************************************************************************
- * RegDeleteKeyExW
- *
- * @unimplemented
- */
-LONG
-WINAPI
-RegDeleteKeyExW(HKEY hKey,
- LPCWSTR lpSubKey,
- REGSAM samDesired,
- DWORD Reserved)
-{
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-
/************************************************************************
* RegDeleteKeyValueW
*
* NOTES
* - Unless RRF_NOEXPAND is specified, REG_EXPAND_SZ values are automatically
* expanded and pdwType is set to REG_SZ instead.
- * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
+ * - Restrictions are applied after expanding, using RRF_RT_REG_EXPAND_SZ
* without RRF_NOEXPAND is thus not allowed.
* An exception is the case where RRF_RT_ANY is specified, because then
* RRF_NOEXPAND is allowed.
*
* @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)
+{
+ WCHAR* NameBuffer = NULL;
+ WCHAR* ClassBuffer = NULL;
+ DWORD NameLength, ClassLength;
+ LONG ErrorCode;
+
+ /* Allocate our buffers */
+ if (*lpcbName > 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 = *lpcbClass;
+ ClassBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbClass * sizeof(WCHAR));
+ if (ClassBuffer == NULL)
+ {
+ ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ goto Exit;
+ }
+ }
+ }
+
+ /* 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)
+ {
+ RtlUnicodeToMultiByteN(lpClass, *lpcbClass, 0, NameBuffer, *lpcbClass * sizeof(WCHAR));
+ if (ClassLength > *lpcbClass)
+ lpClass[*lpcbClass] = '\0';
+ }
+
+Exit:
+ if (NameBuffer)
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
+ if (ClassBuffer)
+ RtlFreeHeap(RtlGetProcessHeap(), 0, ClassBuffer);
+
+ return ErrorCode;
+}
+
+
+/************************************************************************
+ * RegEnumKeyExW
+ *
+ * @implemented
+ */
+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
{
KEY_BASIC_INFORMATION Basic;
} *KeyInfo;
- UNICODE_STRING StringU;
- ANSI_STRING StringA;
- LONG ErrorCode = ERROR_SUCCESS;
- DWORD NameLength;
- DWORD ClassLength = 0;
- DWORD BufferSize;
+ ULONG BufferSize;
ULONG ResultSize;
+ ULONG NameLength;
+ ULONG ClassLength = 0;
HANDLE KeyHandle;
+ LONG ErrorCode = ERROR_SUCCESS;
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))
+ Status = MapDefaultKey(&KeyHandle,
+ hKey);
+ if (!NT_SUCCESS(Status))
{
- return ERROR_INVALID_PARAMETER;
+ return RtlNtStatusToDosError(Status);
}
- Status = MapDefaultKey(&KeyHandle, hKey);
- if (!NT_SUCCESS(Status))
+ if (IsHKCRKey(KeyHandle))
{
- return RtlNtStatusToDosError(Status);
+ 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);
+ NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
}
else
{
{
if (*lpcbClass > 0)
{
- ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
+ ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
}
else
{
ClassLength = 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;
}
- KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
+ KeyInfo = RtlAllocateHeap(ProcessHeap,
+ 0,
+ BufferSize);
if (KeyInfo == NULL)
{
ErrorCode = ERROR_OUTOFMEMORY;
Status = NtEnumerateKey(KeyHandle,
(ULONG)dwIndex,
- lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
+ lpClass ? KeyNodeInformation : KeyBasicInformation,
KeyInfo,
BufferSize,
&ResultSize);
{
if (KeyInfo->Basic.NameLength > NameLength)
{
- ErrorCode = ERROR_BUFFER_OVERFLOW;
+ ErrorCode = ERROR_MORE_DATA;
}
else
{
- StringU.Buffer = KeyInfo->Basic.Name;
- StringU.Length = KeyInfo->Basic.NameLength;
- StringU.MaximumLength = KeyInfo->Basic.NameLength;
+ RtlCopyMemory(lpName,
+ KeyInfo->Basic.Name,
+ KeyInfo->Basic.NameLength);
+ *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
+ lpName[*lpcbName] = 0;
}
}
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);
-
- return ErrorCode;
-}
-
-
-/************************************************************************
- * RegEnumKeyExW
- *
- * @implemented
- */
-LONG WINAPI
-RegEnumKeyExW(HKEY hKey,
- DWORD dwIndex,
- LPWSTR lpName,
- LPDWORD lpcbName,
- LPDWORD lpReserved,
- LPWSTR lpClass,
- LPDWORD lpcbClass,
- PFILETIME lpftLastWriteTime)
-{
- union
- {
- KEY_NODE_INFORMATION Node;
- KEY_BASIC_INFORMATION Basic;
- } *KeyInfo;
-
- ULONG BufferSize;
- ULONG ResultSize;
- ULONG NameLength;
- ULONG ClassLength = 0;
- HANDLE KeyHandle;
- LONG ErrorCode = ERROR_SUCCESS;
- NTSTATUS Status;
-
- Status = MapDefaultKey(&KeyHandle,
- hKey);
- if (!NT_SUCCESS(Status))
- {
- return RtlNtStatusToDosError(Status);
- }
-
- if (*lpcbName > 0)
- {
- NameLength = min (*lpcbName - 1, REG_MAX_NAME_SIZE) * sizeof (WCHAR);
- }
- else
- {
- NameLength = 0;
- }
-
- if (lpClass)
- {
- if (*lpcbClass > 0)
- {
- ClassLength = min (*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
- }
- else
- {
- ClassLength = 0;
- }
-
- BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength;
- }
- else
- {
- BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
- }
-
- KeyInfo = RtlAllocateHeap(ProcessHeap,
- 0,
- BufferSize);
- if (KeyInfo == NULL)
- {
- ErrorCode = ERROR_OUTOFMEMORY;
- goto Cleanup;
- }
-
- Status = NtEnumerateKey(KeyHandle,
- (ULONG)dwIndex,
- lpClass ? KeyNodeInformation : KeyBasicInformation,
- 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
- {
- RtlCopyMemory(lpName,
- KeyInfo->Basic.Name,
- KeyInfo->Basic.NameLength);
- *lpcbName = (DWORD)(KeyInfo->Basic.NameLength / sizeof(WCHAR));
- lpName[*lpcbName] = 0;
- }
- }
- else
- {
- if (KeyInfo->Node.NameLength > NameLength ||
- KeyInfo->Node.ClassLength > ClassLength)
- {
- ErrorCode = ERROR_BUFFER_OVERFLOW;
+ ErrorCode = ERROR_MORE_DATA;
}
else
{
* @implemented
*/
LONG WINAPI
-RegEnumValueA(HKEY hKey,
- DWORD index,
- LPSTR value,
- LPDWORD val_count,
- LPDWORD reserved,
- LPDWORD type,
- LPBYTE data,
- LPDWORD count)
+RegEnumValueA(
+ _In_ HKEY hKey,
+ _In_ DWORD dwIndex,
+ _Out_ LPSTR lpName,
+ _Inout_ LPDWORD lpcbName,
+ _Reserved_ LPDWORD lpdwReserved,
+ _Out_opt_ LPDWORD lpdwType,
+ _Out_opt_ LPBYTE lpData,
+ _Inout_opt_ LPDWORD lpcbData)
{
- HANDLE KeyHandle;
- NTSTATUS status;
- ULONG total_size;
- char buffer[256], *buf_ptr = buffer;
- KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
- static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
+ WCHAR* NameBuffer;
+ DWORD NameBufferSize, NameLength;
+ LONG ErrorCode;
+ DWORD LocalType = REG_NONE;
+ BOOL NameOverflow = FALSE;
- //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
- // hkey, index, value, val_count, reserved, type, data, count );
+ /* Do parameter checks now, once and for all. */
+ if (!lpName || !lpcbName)
+ return ERROR_INVALID_PARAMETER;
- /* NT only checks count, not val_count */
- if ((data && !count) || reserved)
+ if ((lpData && !lpcbData) || lpdwReserved)
return ERROR_INVALID_PARAMETER;
- status = MapDefaultKey(&KeyHandle, hKey);
- if (!NT_SUCCESS(status))
+ /* Get the size of the buffer we must use for the first call to RegEnumValueW */
+ ErrorCode = RegQueryInfoKeyW(
+ hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &NameBufferSize, NULL, NULL, NULL);
+ if (ErrorCode != ERROR_SUCCESS)
+ return ErrorCode;
+
+ /* Add space for the null terminator */
+ NameBufferSize++;
+
+ /* 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;
- total_size = min( sizeof(buffer), total_size );
-
- status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
- buffer, total_size, &total_size );
- if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done;
+ /*
+ * This code calls RegEnumValueW twice, because we need to know the type of the enumerated value.
+ * 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
+ * call with the supplied value. This is merdique, but this is how it is.
+ */
+ NameLength = *lpcbName;
+ ErrorCode = RegEnumValueW(
+ hKey,
+ dwIndex,
+ NameBuffer,
+ &NameLength,
+ NULL,
+ &LocalType,
+ NULL,
+ NULL);
+ if (ErrorCode != ERROR_SUCCESS)
+ {
+ if (ErrorCode == ERROR_MORE_DATA)
+ NameOverflow = TRUE;
+ else
+ goto Exit;
+ }
- /* we need to fetch the contents for a string type even if not requested,
- * because we need to compute the length of the ASCII string. */
- if (value || data || is_string(info->Type))
+ if (is_string(LocalType) && lpcbData)
{
- /* retry with a dynamically allocated buffer */
- while ((status == STATUS_BUFFER_OVERFLOW) || (status == STATUS_BUFFER_TOO_SMALL))
- {
- if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
- if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
- {
- status = STATUS_INSUFFICIENT_RESOURCES;
- goto done;
- }
- info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
- status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
- buf_ptr, total_size, &total_size );
- }
+ /* 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 (status) goto done;
+ if (lpData)
+ DataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbData * sizeof(WCHAR));
- if (is_string(info->Type))
+ /* Do the real call */
+ ErrorCode = RegEnumValueW(
+ hKey,
+ dwIndex,
+ NameBuffer,
+ &NameBufferSize,
+ lpdwReserved,
+ lpdwType,
+ (LPBYTE)DataBuffer,
+ &DataBufferSize);
+
+ *lpcbData = DataBufferSize / sizeof(WCHAR);
+
+ if (ErrorCode != ERROR_SUCCESS)
{
- ULONG len;
- RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
- info->DataLength );
- if (data && len)
- {
- 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;
+ RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer);
+ goto Exit;
}
- else if (data)
+
+ /* Copy the data whatever the error code is */
+ if (lpData)
{
- if (info->DataLength > *count) status = STATUS_BUFFER_OVERFLOW;
- else memcpy( data, buf_ptr + info->DataOffset, info->DataLength );
+ /* Do the data conversion */
+ RtlUnicodeToMultiByteN(DataStr, DataLength, 0, DataBuffer, DataBufferSize);
+ /* NULL-terminate if there is enough room */
+ if ((DataLength > *lpcbData) && (DataStr[*lpcbData - 1] != '\0'))
+ DataStr[*lpcbData] = '\0';
}
- if (value && !status)
- {
- ULONG len;
+ RtlFreeHeap(RtlGetProcessHeap(), 0, DataBuffer);
+ }
+ 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 (len >= *val_count)
- {
- 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;
- }
+ if (ErrorCode != ERROR_SUCCESS)
+ {
+ goto Exit;
}
}
- else status = STATUS_SUCCESS;
- if (type) *type = info->Type;
- if (count) *count = info->DataLength;
+ if (NameOverflow)
+ {
+ ErrorCode = ERROR_MORE_DATA;
+ goto Exit;
+ }
- done:
- if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
- ClosePredefKey(KeyHandle);
- return RtlNtStatusToDosError(status);
+ /* Convert the name string */
+ RtlUnicodeToMultiByteN(lpName, *lpcbName, lpcbName, NameBuffer, NameBufferSize * sizeof(WCHAR));
+ ((PSTR)lpName)[*lpcbName] = '\0';
+
+Exit:
+ if (NameBuffer)
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
+
+ return ErrorCode;
}
* Success: ERROR_SUCCESS
* Failure: nonzero error code from Winerror.h
*/
-LONG WINAPI
-RegEnumValueW(HKEY hKey,
- DWORD index,
- LPWSTR value,
- PDWORD val_count,
- PDWORD reserved,
- PDWORD type,
- LPBYTE data,
- PDWORD count)
+LONG
+WINAPI
+RegEnumValueW(
+ _In_ HKEY hKey,
+ _In_ DWORD index,
+ _Out_ LPWSTR value,
+ _Inout_ PDWORD val_count,
+ _Reserved_ PDWORD reserved,
+ _Out_opt_ PDWORD type,
+ _Out_opt_ LPBYTE data,
+ _Inout_opt_ PDWORD count)
{
HANDLE KeyHandle;
NTSTATUS status;
KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
static const int info_size = FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name );
- //TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
- // hkey, index, value, val_count, reserved, type, data, count );
+ TRACE("(%p,%ld,%p,%p,%p,%p,%p,%p)\n",
+ hKey, index, value, val_count, reserved, type, data, count );
- /* NT only checks count, not val_count */
- if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
+ if (!value || !val_count)
+ return ERROR_INVALID_PARAMETER;
+
+ if ((data && !count) || reserved)
+ return ERROR_INVALID_PARAMETER;
status = MapDefaultKey(&KeyHandle, hKey);
if (!NT_SUCCESS(status))
return RtlNtStatusToDosError(status);
}
+ if (IsHKCRKey(KeyHandle))
+ {
+ LONG ErrorCode = EnumHKCRValue(
+ KeyHandle,
+ index,
+ value,
+ val_count,
+ reserved,
+ type,
+ data,
+ count);
+ ClosePredefKey(KeyHandle);
+ return ErrorCode;
+ }
+
total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
if (data) total_size += *count;
total_size = min( sizeof(buffer), total_size );
return RtlNtStatusToDosError(Status);
}
-#if 0
Status = NtQuerySecurityObject(KeyHandle,
SecurityInformation,
pSecurityDescriptor,
*lpcbSecurityDescriptor,
lpcbSecurityDescriptor);
-#endif
ClosePredefKey(KeyHandle);
UNICODE_STRING KeyName;
LONG ErrorCode;
- RtlCreateUnicodeStringFromAsciiz(&KeyName,
- (LPSTR)lpSubKey);
- RtlCreateUnicodeStringFromAsciiz(&FileName,
- (LPSTR)lpFile);
+ RtlInitEmptyUnicodeString(&KeyName, NULL, 0);
+ RtlInitEmptyUnicodeString(&FileName, NULL, 0);
+
+ if (lpSubKey)
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey))
+ {
+ ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ goto Exit;
+ }
+ }
+
+ if (lpFile)
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
+ {
+ ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ goto Exit;
+ }
+ }
ErrorCode = RegLoadKeyW(hKey,
KeyName.Buffer,
FileName.Buffer);
+Exit:
RtlFreeUnicodeString(&FileName);
RtlFreeUnicodeString(&KeyName);
return ERROR_INVALID_HANDLE;
}
- if (fAsynchronous == TRUE && hEvent == NULL)
+ if ((fAsynchronous != FALSE) && (hEvent == NULL))
{
return ERROR_INVALID_PARAMETER;
}
* @implemented
*/
LONG WINAPI
-RegOpenKeyExA(HKEY hKey,
- LPCSTR lpSubKey,
- DWORD ulOptions,
- REGSAM samDesired,
- PHKEY phkResult)
+RegOpenKeyExA(
+ _In_ HKEY hKey,
+ _In_ LPCSTR lpSubKey,
+ _In_ DWORD ulOptions,
+ _In_ REGSAM samDesired,
+ _Out_ PHKEY phkResult)
{
- OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING SubKeyString;
- HANDLE KeyHandle;
- NTSTATUS Status;
- LONG ErrorCode = ERROR_SUCCESS;
+ LONG ErrorCode;
TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
hKey, lpSubKey, ulOptions, samDesired, phkResult);
- if (!phkResult)
- {
- return ERROR_INVALID_PARAMETER;
- }
- Status = MapDefaultKey(&KeyHandle,
- hKey);
- if (!NT_SUCCESS(Status))
+ if (lpSubKey)
{
- return RtlNtStatusToDosError(Status);
+ if (!RtlCreateUnicodeStringFromAsciiz(&SubKeyString, lpSubKey))
+ return ERROR_NOT_ENOUGH_MEMORY;
}
+ else
+ RtlInitEmptyUnicodeString(&SubKeyString, NULL, 0);
- RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
- (LPSTR)lpSubKey);
- InitializeObjectAttributes(&ObjectAttributes,
- &SubKeyString,
- OBJ_CASE_INSENSITIVE,
- KeyHandle,
- NULL);
+ ErrorCode = RegOpenKeyExW(hKey, SubKeyString.Buffer, ulOptions, samDesired, phkResult);
- Status = NtOpenKey((PHANDLE)phkResult,
- samDesired,
- &ObjectAttributes);
RtlFreeUnicodeString(&SubKeyString);
- if (!NT_SUCCESS(Status))
- {
- ErrorCode = RtlNtStatusToDosError(Status);
- }
-
- ClosePredefKey(KeyHandle);
return ErrorCode;
}
UNICODE_STRING SubKeyString;
HANDLE KeyHandle;
NTSTATUS Status;
+ ULONG Attributes = OBJ_CASE_INSENSITIVE;
LONG ErrorCode = ERROR_SUCCESS;
TRACE("RegOpenKeyExW hKey 0x%x lpSubKey %S ulOptions 0x%x samDesired 0x%x phkResult %p\n",
return RtlNtStatusToDosError(Status);
}
+ if (IsHKCRKey(KeyHandle))
+ {
+ ErrorCode = OpenHKCRKey(KeyHandle, lpSubKey, ulOptions, samDesired, phkResult);
+ ClosePredefKey(KeyHandle);
+ return ErrorCode;
+ }
+
+ if (ulOptions & REG_OPTION_OPEN_LINK)
+ Attributes |= OBJ_OPENLINK;
+
if (lpSubKey != NULL)
RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey);
else
InitializeObjectAttributes(&ObjectAttributes,
&SubKeyString,
- OBJ_CASE_INSENSITIVE,
+ Attributes,
KeyHandle,
NULL);
- Status = NtOpenKey((PHANDLE)phkResult,
- samDesired,
- &ObjectAttributes);
+ Status = NtOpenKey((PHANDLE)phkResult,
+ samDesired,
+ &ObjectAttributes);
+
+ if (Status == STATUS_DATATYPE_MISALIGNMENT)
+ {
+ HANDLE hAligned;
+ UNICODE_STRING AlignedString;
+
+ Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+ &SubKeyString,
+ &AlignedString);
+ if (NT_SUCCESS(Status))
+ {
+ /* Try again with aligned parameters */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &AlignedString,
+ Attributes,
+ KeyHandle,
+ NULL);
+
+ Status = NtOpenKey(&hAligned,
+ samDesired,
+ &ObjectAttributes);
+
+ RtlFreeUnicodeString(&AlignedString);
+
+ if (NT_SUCCESS(Status))
+ *phkResult = hAligned;
+ }
+ else
+ {
+ /* Restore the original error */
+ Status = STATUS_DATATYPE_MISALIGNMENT;
+ }
+ }
+
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError(Status);
}
+
ClosePredefKey(KeyHandle);
return ErrorCode;
LONG WINAPI
RegQueryInfoKeyA(HKEY hKey,
LPSTR lpClass,
- LPDWORD lpcbClass,
+ LPDWORD lpcClass,
LPDWORD lpReserved,
LPDWORD lpcSubKeys,
- LPDWORD lpcbMaxSubKeyLen,
- LPDWORD lpcbMaxClassLen,
+ LPDWORD lpcMaxSubKeyLen,
+ LPDWORD lpcMaxClassLen,
LPDWORD lpcValues,
- LPDWORD lpcbMaxValueNameLen,
- LPDWORD lpcbMaxValueLen,
+ LPDWORD lpcMaxValueNameLen,
+ LPDWORD lpcMaxValueLen,
LPDWORD lpcbSecurityDescriptor,
PFILETIME lpftLastWriteTime)
{
UNICODE_STRING UnicodeString;
ANSI_STRING AnsiString;
LONG ErrorCode;
+ NTSTATUS Status;
+ DWORD cClass = 0;
+
+ if ((lpClass) && (!lpcClass))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
RtlInitUnicodeString(&UnicodeString,
NULL);
if (lpClass != NULL)
{
- UnicodeString.Buffer = &ClassName[0];
- UnicodeString.MaximumLength = sizeof(ClassName);
- AnsiString.MaximumLength = *lpcbClass;
+ RtlInitEmptyUnicodeString(&UnicodeString,
+ ClassName,
+ sizeof(ClassName));
+ cClass = sizeof(ClassName) / sizeof(WCHAR);
}
ErrorCode = RegQueryInfoKeyW(hKey,
UnicodeString.Buffer,
- lpcbClass,
+ &cClass,
lpReserved,
lpcSubKeys,
- lpcbMaxSubKeyLen,
- lpcbMaxClassLen,
+ lpcMaxSubKeyLen,
+ lpcMaxClassLen,
lpcValues,
- lpcbMaxValueNameLen,
- lpcbMaxValueLen,
+ lpcMaxValueNameLen,
+ lpcMaxValueLen,
lpcbSecurityDescriptor,
lpftLastWriteTime);
if ((ErrorCode == ERROR_SUCCESS) && (lpClass != NULL))
{
- AnsiString.Buffer = lpClass;
- AnsiString.Length = 0;
- UnicodeString.Length = *lpcbClass * sizeof(WCHAR);
- RtlUnicodeStringToAnsiString(&AnsiString,
- &UnicodeString,
- FALSE);
- *lpcbClass = AnsiString.Length;
- lpClass[AnsiString.Length] = 0;
+ if (*lpcClass == 0)
+ {
+ return ErrorCode;
+ }
+
+ RtlInitEmptyAnsiString(&AnsiString, lpClass, *lpcClass);
+ UnicodeString.Length = cClass * sizeof(WCHAR);
+ Status = RtlUnicodeStringToAnsiString(&AnsiString,
+ &UnicodeString,
+ FALSE);
+ ErrorCode = RtlNtStatusToDosError(Status);
+ cClass = AnsiString.Length;
+ lpClass[cClass] = ANSI_NULL;
+ }
+
+ if (lpcClass != NULL)
+ {
+ *lpcClass = cClass;
}
return ErrorCode;
LONG WINAPI
RegQueryInfoKeyW(HKEY hKey,
LPWSTR lpClass,
- LPDWORD lpcbClass,
+ LPDWORD lpcClass,
LPDWORD lpReserved,
LPDWORD lpcSubKeys,
- LPDWORD lpcbMaxSubKeyLen,
- LPDWORD lpcbMaxClassLen,
+ LPDWORD lpcMaxSubKeyLen,
+ LPDWORD lpcMaxClassLen,
LPDWORD lpcValues,
- LPDWORD lpcbMaxValueNameLen,
- LPDWORD lpcbMaxValueLen,
+ LPDWORD lpcMaxValueNameLen,
+ LPDWORD lpcMaxValueLen,
LPDWORD lpcbSecurityDescriptor,
PFILETIME lpftLastWriteTime)
{
ULONG Length;
LONG ErrorCode = ERROR_SUCCESS;
- if ((lpClass) && (!lpcbClass))
+ if ((lpClass) && (!lpcClass))
{
return ERROR_INVALID_PARAMETER;
}
if (lpClass != NULL)
{
- if (*lpcbClass > 0)
+ if (*lpcClass > 0)
{
- ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
+ ClassLength = min(*lpcClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
}
else
{
ErrorCode = ERROR_OUTOFMEMORY;
goto Cleanup;
}
-
- FullInfo->ClassLength = ClassLength;
}
else
{
FullInfoSize = sizeof(KEY_FULL_INFORMATION);
FullInfo = &FullInfoBuffer;
- FullInfo->ClassLength = 0;
}
- FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
+
+ if (lpcbSecurityDescriptor != NULL)
+ *lpcbSecurityDescriptor = 0;
Status = NtQueryKey(KeyHandle,
KeyFullInformation,
FullInfoSize,
&Length);
TRACE("NtQueryKey() returned status 0x%X\n", Status);
- if (!NT_SUCCESS(Status))
+ if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
{
- if (lpClass != NULL)
- {
- RtlFreeHeap(ProcessHeap,
- 0,
- FullInfo);
- }
-
ErrorCode = RtlNtStatusToDosError(Status);
goto Cleanup;
}
}
TRACE("MaxNameLen %lu\n", FullInfo->MaxNameLen);
- if (lpcbMaxSubKeyLen != NULL)
+ if (lpcMaxSubKeyLen != NULL)
{
- *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
+ *lpcMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR);
}
TRACE("MaxClassLen %lu\n", FullInfo->MaxClassLen);
- if (lpcbMaxClassLen != NULL)
+ if (lpcMaxClassLen != NULL)
{
- *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
+ *lpcMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR);
}
TRACE("Values %lu\n", FullInfo->Values);
}
TRACE("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
- if (lpcbMaxValueNameLen != NULL)
+ if (lpcMaxValueNameLen != NULL)
{
- *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
+ *lpcMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR);
}
TRACE("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
- if (lpcbMaxValueLen != NULL)
+ if (lpcMaxValueLen != NULL)
{
- *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
+ *lpcMaxValueLen = FullInfo->MaxValueDataLen;
}
-#if 0
if (lpcbSecurityDescriptor != NULL)
{
Status = NtQuerySecurityObject(KeyHandle,
NULL,
0,
lpcbSecurityDescriptor);
- if (!NT_SUCCESS(Status))
- {
- if (lpClass != NULL)
- {
- RtlFreeHeap(ProcessHeap,
- 0,
- FullInfo);
- }
-
- ErrorCode = RtlNtStatusToDosError(Status);
- goto Cleanup;
- }
+ TRACE("NtQuerySecurityObject() returned status 0x%X\n", Status);
}
-#endif
if (lpftLastWriteTime != NULL)
{
if (lpClass != NULL)
{
+ if (*lpcClass == 0)
+ {
+ goto Cleanup;
+ }
+
if (FullInfo->ClassLength > ClassLength)
{
- ErrorCode = ERROR_BUFFER_OVERFLOW;
+ ErrorCode = ERROR_INSUFFICIENT_BUFFER;
}
else
{
RtlCopyMemory(lpClass,
FullInfo->Class,
FullInfo->ClassLength);
- *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
- lpClass[*lpcbClass] = 0;
+ lpClass[FullInfo->ClassLength / sizeof(WCHAR)] = UNICODE_NULL;
}
+ }
+
+ if (lpcClass != NULL)
+ {
+ *lpcClass = FullInfo->ClassLength / sizeof(WCHAR);
+ }
+Cleanup:
+ if (lpClass != NULL)
+ {
RtlFreeHeap(ProcessHeap,
0,
FullInfo);
}
-Cleanup:
ClosePredefKey(KeyHandle);
return ErrorCode;
LONG ErrorCode;
if (maxBytes >= (1024*1024))
- return ERROR_TRANSFER_TOO_LONG;
+ return ERROR_MORE_DATA;
*ldwTotsize = 0;
LONG ErrorCode;
if (maxBytes >= (1024*1024))
- return ERROR_TRANSFER_TOO_LONG;
+ return ERROR_MORE_DATA;
*ldwTotsize = 0;
* Failure: ERROR_INVALID_HANDLE, if hkey is invalid.
* ERROR_INVALID_PARAMETER, if any other parameter is invalid.
* ERROR_MORE_DATA, if on input *count is too small to hold the contents.
- *
+ *
* NOTES
- * MSDN states that if data is too small it is partially filled. In reality
+ * MSDN states that if data is too small it is partially filled. In reality
* it remains untouched.
*/
LONG
WINAPI
-RegQueryValueExA(HKEY hkeyorg,
- LPCSTR name,
- LPDWORD reserved,
- LPDWORD type,
- LPBYTE data,
- LPDWORD count)
+RegQueryValueExA(
+ _In_ HKEY hkeyorg,
+ _In_ LPCSTR name,
+ _In_ LPDWORD reserved,
+ _Out_opt_ LPDWORD type,
+ _Out_opt_ LPBYTE data,
+ _Inout_opt_ LPDWORD count)
{
- HANDLE hkey;
- NTSTATUS status;
- ANSI_STRING nameA;
UNICODE_STRING nameW;
- DWORD total_size, datalen = 0;
- char buffer[256], *buf_ptr = buffer;
- KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
- static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
+ DWORD DataLength;
+ DWORD ErrorCode;
+ DWORD BufferSize = 0;
+ WCHAR* Buffer;
+ CHAR* DataStr = (CHAR*)data;
+ DWORD LocalType;
- TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
- hkeyorg, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
+ /* Validate those parameters, the rest will be done with the first RegQueryValueExW call */
+ if ((data && !count) || reserved)
+ return ERROR_INVALID_PARAMETER;
- if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
- status = MapDefaultKey(&hkey, hkeyorg);
- if (!NT_SUCCESS(status))
+ if (name)
{
- return RtlNtStatusToDosError(status);
+ if (!RtlCreateUnicodeStringFromAsciiz(&nameW, name))
+ return ERROR_NOT_ENOUGH_MEMORY;
}
+ else
+ RtlInitEmptyUnicodeString(&nameW, NULL, 0);
- if (count) datalen = *count;
- if (!data && count) *count = 0;
+ ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, NULL, &LocalType, NULL, &BufferSize);
+ if (ErrorCode != ERROR_SUCCESS)
+ {
+ if ((!data) && count)
+ *count = 0;
+ RtlFreeUnicodeString(&nameW);
+ return ErrorCode;
+ }
- RtlInitAnsiString( &nameA, name );
- if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
+ /* See if we can directly handle the call without caring for conversion */
+ if (!is_string(LocalType) || !count)
{
- ClosePredefKey(hkey);
- return RtlNtStatusToDosError(status);
+ ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, data, count);
+ RtlFreeUnicodeString(&nameW);
+ return ErrorCode;
}
- status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
- buffer, sizeof(buffer), &total_size );
- if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
+ /* Allocate a unicode string to get the data */
+ Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
+ if (!Buffer)
+ {
+ RtlFreeUnicodeString(&nameW);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
- /* we need to fetch the contents for a string type even if not requested,
- * because we need to compute the length of the ASCII string. */
- if (data || is_string(info->Type))
+ ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, reserved, type, (LPBYTE)Buffer, &BufferSize);
+ if (ErrorCode != ERROR_SUCCESS)
{
- /* retry with a dynamically allocated buffer */
- while (status == STATUS_BUFFER_OVERFLOW)
- {
- if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
- if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
- {
- status = STATUS_NO_MEMORY;
- goto done;
- }
- info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
- status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
- buf_ptr, total_size, &total_size );
- }
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+ RtlFreeUnicodeString(&nameW);
+ return ErrorCode;
+ }
- if (status) goto done;
+ /* We don't need this anymore */
+ RtlFreeUnicodeString(&nameW);
- if (is_string(info->Type))
- {
- DWORD len;
+ DataLength = *count;
+ RtlUnicodeToMultiByteSize(count, Buffer, BufferSize);
- RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
- total_size - info_size );
- if (data && len)
- {
- if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
- else
- {
- RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(buf_ptr + info_size),
- total_size - info_size );
- /* 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 < datalen && data[len-1]) data[len] = 0;
- }
- }
- total_size = len + info_size;
- }
- else if (data)
- {
- if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
- else memcpy( data, buf_ptr + info_size, total_size - info_size );
- }
+ if ((!data) || (DataLength < *count))
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+ return data ? ERROR_MORE_DATA : ERROR_SUCCESS;
}
- else status = STATUS_SUCCESS;
- if (type) *type = info->Type;
- if (count) *count = total_size - info_size;
+ /* We can finally do the conversion */
+ RtlUnicodeToMultiByteN(DataStr, DataLength, NULL, Buffer, BufferSize);
- done:
- if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
- RtlFreeUnicodeString( &nameW );
- ClosePredefKey(hkey);
- return RtlNtStatusToDosError(status);
+ /* NULL-terminate if there is enough room */
+ if ((DataLength > *count) && (DataStr[*count - 1] != '\0'))
+ DataStr[*count] = '\0';
+
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+
+ return ERROR_SUCCESS;
}
*/
LONG
WINAPI
-RegQueryValueExW(HKEY hkeyorg,
- LPCWSTR name,
- LPDWORD reserved,
- LPDWORD type,
- LPBYTE data,
- LPDWORD count)
+RegQueryValueExW(
+ _In_ HKEY hkeyorg,
+ _In_ LPCWSTR name,
+ _In_ LPDWORD reserved,
+ _In_ LPDWORD type,
+ _In_ LPBYTE data,
+ _In_ LPDWORD count)
{
HANDLE hkey;
NTSTATUS status;
return RtlNtStatusToDosError(status);
}
+ if (IsHKCRKey(hkey))
+ {
+ LONG ErrorCode = QueryHKCRValue(hkey, name, reserved, type, data, count);
+ ClosePredefKey(hkey);
+ return ErrorCode;
+ }
+
RtlInitUnicodeString( &name_str, name );
- if (data) total_size = min( sizeof(buffer), *count + info_size );
+ if (data)
+ total_size = min( sizeof(buffer), *count + info_size );
else
- {
total_size = info_size;
- if (count) *count = 0;
- }
- /* this matches Win9x behaviour - NT sets *type to a random value */
- if (type) *type = REG_NONE;
status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation,
buffer, total_size, &total_size );
- if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) goto done;
+
+ if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW)
+ {
+ // NT: Valid handles with inexistant/null values or invalid (but not NULL) handles sets type to REG_NONE
+ // On windows these conditions are likely to be side effects of the implementation...
+ if (status == STATUS_INVALID_HANDLE && hkey)
+ {
+ if (type) *type = REG_NONE;
+ if (count) *count = 0;
+ }
+ else if (status == STATUS_OBJECT_NAME_NOT_FOUND)
+ {
+ if (type) *type = REG_NONE;
+ if (data == NULL && count) *count = 0;
+ }
+ goto done;
+ }
if (data)
{
if (name && name[0])
{
ret = RegOpenKeyW( hkey, name, &subkey);
- if (ret != ERROR_SUCCESS)
+ if (ret != ERROR_SUCCESS)
{
return ret;
}
}
ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count );
-
- if (subkey != hkey)
+
+ if (subkey != hkey)
{
RegCloseKey( subkey );
}
if (ret == ERROR_FILE_NOT_FOUND)
{
/* return empty string if default value not found */
- if (data)
+ if (data)
*data = 0;
- if (count)
+ if (count)
*count = sizeof(WCHAR);
ret = ERROR_SUCCESS;
}
UNICODE_STRING OldFile;
LONG ErrorCode;
- RtlCreateUnicodeStringFromAsciiz(&SubKey,
- (PCSZ)lpSubKey);
- RtlCreateUnicodeStringFromAsciiz(&OldFile,
- (PCSZ)lpOldFile);
- RtlCreateUnicodeStringFromAsciiz(&NewFile,
- (PCSZ)lpNewFile);
+ RtlInitEmptyUnicodeString(&SubKey, NULL, 0);
+ RtlInitEmptyUnicodeString(&OldFile, NULL, 0);
+ RtlInitEmptyUnicodeString(&NewFile, NULL, 0);
+
+ if (lpSubKey)
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&SubKey, lpSubKey))
+ {
+ ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ goto Exit;
+ }
+ }
+
+ if (lpOldFile)
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&OldFile, lpOldFile))
+ {
+ ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ goto Exit;
+ }
+ }
+
+ if (lpNewFile)
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&NewFile, lpNewFile))
+ {
+ ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ goto Exit;
+ }
+ }
ErrorCode = RegReplaceKeyW(hKey,
SubKey.Buffer,
NewFile.Buffer,
OldFile.Buffer);
+Exit:
RtlFreeUnicodeString(&OldFile);
RtlFreeUnicodeString(&NewFile);
RtlFreeUnicodeString(&SubKey);
UNICODE_STRING FileName;
LONG ErrorCode;
- RtlCreateUnicodeStringFromAsciiz(&FileName,
- (PCSZ)lpFile);
+ if (lpFile)
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else
+ RtlInitEmptyUnicodeString(&FileName, NULL, 0);
ErrorCode = RegRestoreKeyW(hKey,
FileName.Buffer,
UNICODE_STRING FileName;
LONG ErrorCode;
- RtlCreateUnicodeStringFromAsciiz(&FileName,
- (LPSTR)lpFile);
+ if (lpFile)
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else
+ RtlInitEmptyUnicodeString(&FileName, NULL, 0);
+
ErrorCode = RegSaveKeyW(hKey,
FileName.Buffer,
lpSecurityAttributes);
UNICODE_STRING FileName;
LONG ErrorCode;
- RtlCreateUnicodeStringFromAsciiz(&FileName,
- (LPSTR)lpFile);
+ if (lpFile)
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFile))
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else
+ RtlInitEmptyUnicodeString(&FileName, NULL, 0);
+
ErrorCode = RegSaveKeyExW(hKey,
FileName.Buffer,
lpSecurityAttributes,
/* Convert SubKey name to Unicode */
if (lpValueName != NULL && lpValueName[0] != '\0')
{
- BOOL bConverted;
- bConverted = RtlCreateUnicodeStringFromAsciiz(&ValueName,
- (PSTR)lpValueName);
- if(!bConverted)
+ if (!RtlCreateUnicodeStringFromAsciiz(&ValueName, (PSTR)lpValueName))
return ERROR_NOT_ENOUGH_MEMORY;
}
else
*
* @implemented
*/
-LONG WINAPI
-RegSetValueExW(HKEY hKey,
- LPCWSTR lpValueName,
- DWORD Reserved,
- DWORD dwType,
- CONST BYTE* lpData,
- DWORD cbData)
+LONG
+WINAPI
+RegSetValueExW(
+ _In_ HKEY hKey,
+ _In_ LPCWSTR lpValueName,
+ _In_ DWORD Reserved,
+ _In_ DWORD dwType,
+ _In_ CONST BYTE* lpData,
+ _In_ DWORD cbData)
{
UNICODE_STRING ValueName;
- PUNICODE_STRING pValueName;
HANDLE KeyHandle;
NTSTATUS Status;
return RtlNtStatusToDosError(Status);
}
- RtlInitUnicodeString(&ValueName, lpValueName);
- pValueName = &ValueName;
+ if (IsHKCRKey(KeyHandle))
+ {
+ LONG ErrorCode = SetHKCRValue(KeyHandle, lpValueName, Reserved, dwType, lpData, cbData);
+ ClosePredefKey(KeyHandle);
+ return ErrorCode;
+ }
if (is_string(dwType) && (cbData != 0))
{
PWSTR pwsData = (PWSTR)lpData;
- if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') &&
- (pwsData[cbData / sizeof(WCHAR)] == L'\0'))
+ _SEH2_TRY
{
- /* Increment length if last character is not zero and next is zero */
- cbData += sizeof(WCHAR);
+ if((pwsData[cbData / sizeof(WCHAR) - 1] != L'\0') &&
+ (pwsData[cbData / sizeof(WCHAR)] == L'\0'))
+ {
+ /* Increment length if last character is not zero and next is zero */
+ cbData += sizeof(WCHAR);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ClosePredefKey(KeyHandle);
+ return ERROR_NOACCESS;
}
+ _SEH2_END;
}
+ RtlInitUnicodeString(&ValueName, lpValueName);
+
Status = NtSetValueKey(KeyHandle,
- pValueName,
+ &ValueName,
0,
dwType,
(PVOID)lpData,
UNICODE_STRING KeyName;
DWORD ErrorCode;
- RtlCreateUnicodeStringFromAsciiz(&KeyName,
- (LPSTR)lpSubKey);
+ if (lpSubKey)
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&KeyName, lpSubKey))
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else
+ RtlInitEmptyUnicodeString(&KeyName, NULL, 0);
ErrorCode = RegUnLoadKeyW(hKey,
KeyName.Buffer);
return ERROR_SUCCESS;
}
-
-/******************************************************************************
- * load_string [Internal]
- *
- * This is basically a copy of user32/resource.c's LoadStringW. Necessary to
- * avoid importing user32, which is higher level than advapi32. Helper for
- * RegLoadMUIString.
- */
-static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
-{
- HGLOBAL hMemory;
- HRSRC hResource;
- WCHAR *pString;
- int idxString;
-
- /* Negative values have to be inverted. */
- if (HIWORD(resId) == 0xffff)
- resId = (UINT)(-((INT)resId));
-
- /* Load the resource into memory and get a pointer to it. */
- hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING);
- if (!hResource) return 0;
- hMemory = LoadResource(hModule, hResource);
- if (!hMemory) return 0;
- pString = LockResource(hMemory);
-
- /* Strings are length-prefixed. Lowest nibble of resId is an index. */
- idxString = resId & 0xf;
- while (idxString--) pString += *pString + 1;
-
- /* If no buffer is given, return length of the string. */
- if (!pwszBuffer) return *pString;
-
- /* Else copy over the string, respecting the buffer size. */
- cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1);
- if (cMaxChars >= 0)
- {
- memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR));
- pwszBuffer[cMaxChars] = L'\0';
- }
-
- return cMaxChars;
-}
-
-
-/************************************************************************
- * RegLoadMUIStringW
- *
- * @implemented
- */
-LONG WINAPI
-RegLoadMUIStringW(IN HKEY hKey,
- IN LPCWSTR pszValue OPTIONAL,
- OUT LPWSTR pszOutBuf,
- IN DWORD cbOutBuf,
- OUT LPDWORD pcbData OPTIONAL,
- IN DWORD Flags,
- IN LPCWSTR pszDirectory OPTIONAL)
-{
- DWORD dwValueType, cbData;
- LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL;
- LONG result;
-
- /* Parameter sanity checks. */
- if (!hKey || !pszOutBuf)
- return ERROR_INVALID_PARAMETER;
-
- if (pszDirectory && *pszDirectory)
- {
- FIXME("BaseDir parameter not yet supported!\n");
- return ERROR_INVALID_PARAMETER;
- }
-
- /* Check for value existence and correctness of it's type, allocate a buffer and load it. */
- result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData);
- if (result != ERROR_SUCCESS) goto cleanup;
- if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData)
- {
- result = ERROR_FILE_NOT_FOUND;
- goto cleanup;
- }
- pwszTempBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
- if (!pwszTempBuffer)
- {
- result = ERROR_NOT_ENOUGH_MEMORY;
- goto cleanup;
- }
- result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData);
- if (result != ERROR_SUCCESS) goto cleanup;
-
- /* Expand environment variables, if appropriate, or copy the original string over. */
- if (dwValueType == REG_EXPAND_SZ)
- {
- cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR);
- if (!cbData) goto cleanup;
- pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
- if (!pwszExpandedBuffer)
- {
- result = ERROR_NOT_ENOUGH_MEMORY;
- goto cleanup;
- }
- ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData);
- }
- else
- {
- pwszExpandedBuffer = HeapAlloc(GetProcessHeap(), 0, cbData);
- memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData);
- }
-
- /* If the value references a resource based string, parse the value and load the string.
- * Else just copy over the original value. */
- result = ERROR_SUCCESS;
- if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */
- {
- lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR));
- }
- else
- {
- WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L',');
- UINT uiStringId;
- HMODULE hModule;
-
- /* Format of the expanded value is 'path_to_dll,-resId' */
- if (!pComma || pComma[1] != L'-')
- {
- result = ERROR_BADKEY;
- goto cleanup;
- }
-
- uiStringId = _wtoi(pComma+2);
- *pComma = L'\0';
-
- hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE);
- if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR)))
- result = ERROR_BADKEY;
- FreeLibrary(hModule);
- }
-
-cleanup:
- HeapFree(GetProcessHeap(), 0, pwszTempBuffer);
- HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer);
- return result;
-}
-
-
-/************************************************************************
- * RegLoadMUIStringA
- *
- * @implemented
- */
-LONG WINAPI
-RegLoadMUIStringA(IN HKEY hKey,
- IN LPCSTR pszValue OPTIONAL,
- OUT LPSTR pszOutBuf,
- IN DWORD cbOutBuf,
- OUT LPDWORD pcbData OPTIONAL,
- IN DWORD Flags,
- IN LPCSTR pszDirectory OPTIONAL)
-{
- UNICODE_STRING valueW, baseDirW;
- WCHAR *pwszBuffer;
- DWORD cbData = cbOutBuf * sizeof(WCHAR);
- LONG result;
-
- valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL;
- if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) ||
- !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) ||
- !(pwszBuffer = HeapAlloc(GetProcessHeap(), 0, cbData)))
- {
- result = ERROR_NOT_ENOUGH_MEMORY;
- goto cleanup;
- }
-
- result = RegLoadMUIStringW(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags,
- baseDirW.Buffer);
-
- if (result == ERROR_SUCCESS)
- {
- cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL);
- if (pcbData)
- *pcbData = cbData;
- }
-
-cleanup:
- HeapFree(GetProcessHeap(), 0, pwszBuffer);
- RtlFreeUnicodeString(&baseDirW);
- RtlFreeUnicodeString(&valueW);
-
- return result;
-}
-
/* EOF */