+/************************************************************************
+ * RegNotifyChangeKeyValue
+ *
+ * @unimplemented
+ */
+LONG STDCALL
+RegNotifyChangeKeyValue (HKEY hKey,
+ BOOL bWatchSubtree,
+ DWORD dwNotifyFilter,
+ HANDLE hEvent,
+ BOOL fAsynchronous)
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ HANDLE KeyHandle;
+ NTSTATUS Status;
+
+ if (hKey == HKEY_PERFORMANCE_DATA)
+ {
+ return ERROR_INVALID_HANDLE;
+ }
+
+ if (fAsynchronous == TRUE && hEvent == NULL)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ Status = MapDefaultKey (&KeyHandle,
+ hKey);
+ if (!NT_SUCCESS(Status))
+ {
+ return RtlNtStatusToDosError (Status);
+ }
+
+ /* FIXME: Remote key handles must fail */
+
+ Status = NtNotifyChangeKey (KeyHandle,
+ hEvent,
+ 0,
+ 0,
+ &IoStatusBlock,
+ dwNotifyFilter,
+ bWatchSubtree,
+ 0,
+ 0,
+ fAsynchronous);
+ if (!NT_SUCCESS(Status) && Status != STATUS_TIMEOUT)
+ {
+ return RtlNtStatusToDosError (Status);
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+/************************************************************************
+ * RegOpenKeyA
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegOpenKeyA (HKEY hKey,
+ LPCSTR lpSubKey,
+ PHKEY phkResult)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING SubKeyString;
+ HANDLE KeyHandle;
+ LONG ErrorCode;
+ NTSTATUS Status;
+
+ Status = MapDefaultKey (&KeyHandle,
+ hKey);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorCode = RtlNtStatusToDosError (Status);
+ SetLastError (ErrorCode);
+ return ErrorCode;
+ }
+
+ RtlCreateUnicodeStringFromAsciiz (&SubKeyString,
+ (LPSTR)lpSubKey);
+ InitializeObjectAttributes (&ObjectAttributes,
+ &SubKeyString,
+ OBJ_CASE_INSENSITIVE,
+ KeyHandle,
+ NULL);
+ Status = NtOpenKey ((PHANDLE)phkResult,
+ MAXIMUM_ALLOWED,
+ &ObjectAttributes);
+ RtlFreeUnicodeString (&SubKeyString);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorCode = RtlNtStatusToDosError (Status);
+ SetLastError (ErrorCode);
+ return ErrorCode;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+/************************************************************************
+ * RegOpenKeyW
+ *
+ * 19981101 Ariadne
+ * 19990525 EA
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegOpenKeyW (HKEY hKey,
+ LPCWSTR lpSubKey,
+ PHKEY phkResult)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING SubKeyString;
+ HANDLE KeyHandle;
+ LONG ErrorCode;
+ NTSTATUS Status;
+
+ Status = MapDefaultKey (&KeyHandle,
+ hKey);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorCode = RtlNtStatusToDosError (Status);
+ SetLastError (ErrorCode);
+ return ErrorCode;
+ }
+
+ RtlInitUnicodeString (&SubKeyString,
+ (LPWSTR)lpSubKey);
+ InitializeObjectAttributes (&ObjectAttributes,
+ &SubKeyString,
+ OBJ_CASE_INSENSITIVE,
+ KeyHandle,
+ NULL);
+ Status = NtOpenKey ((PHANDLE)phkResult,
+ MAXIMUM_ALLOWED,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorCode = RtlNtStatusToDosError (Status);
+ SetLastError(ErrorCode);
+ return ErrorCode;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+/************************************************************************
+ * RegOpenKeyExA
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegOpenKeyExA (HKEY hKey,
+ LPCSTR lpSubKey,
+ DWORD ulOptions,
+ REGSAM samDesired,
+ PHKEY phkResult)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING SubKeyString;
+ HANDLE KeyHandle;
+ LONG ErrorCode;
+ NTSTATUS Status;
+
+ Status = MapDefaultKey (&KeyHandle,
+ hKey);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorCode = RtlNtStatusToDosError (Status);
+ SetLastError (ErrorCode);
+ return ErrorCode;
+ }
+
+ RtlCreateUnicodeStringFromAsciiz (&SubKeyString,
+ (LPSTR)lpSubKey);
+ InitializeObjectAttributes (&ObjectAttributes,
+ &SubKeyString,
+ OBJ_CASE_INSENSITIVE,
+ KeyHandle,
+ NULL);
+ Status = NtOpenKey ((PHANDLE)phkResult,
+ samDesired,
+ &ObjectAttributes);
+ RtlFreeUnicodeString (&SubKeyString);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorCode = RtlNtStatusToDosError (Status);
+ SetLastError (ErrorCode);
+ return ErrorCode;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+/************************************************************************
+ * RegOpenKeyExW
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegOpenKeyExW (HKEY hKey,
+ LPCWSTR lpSubKey,
+ DWORD ulOptions,
+ REGSAM samDesired,
+ PHKEY phkResult)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING SubKeyString;
+ HANDLE KeyHandle;
+ LONG ErrorCode;
+ NTSTATUS Status;
+
+ Status = MapDefaultKey (&KeyHandle,
+ hKey);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorCode = RtlNtStatusToDosError (Status);
+ SetLastError (ErrorCode);
+ return ErrorCode;
+ }
+
+ if (lpSubKey != NULL)
+ {
+ RtlInitUnicodeString (&SubKeyString,
+ (LPWSTR)lpSubKey);
+ }
+ else
+ {
+ RtlInitUnicodeString (&SubKeyString,
+ (LPWSTR)L"");
+ }
+ InitializeObjectAttributes (&ObjectAttributes,
+ &SubKeyString,
+ OBJ_CASE_INSENSITIVE,
+ KeyHandle,
+ NULL);
+ Status = NtOpenKey ((PHANDLE)phkResult,
+ samDesired,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorCode = RtlNtStatusToDosError (Status);
+ SetLastError (ErrorCode);
+ return ErrorCode;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+/************************************************************************
+ * RegQueryInfoKeyA
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegQueryInfoKeyA (HKEY hKey,
+ LPSTR lpClass,
+ LPDWORD lpcbClass,
+ LPDWORD lpReserved,
+ LPDWORD lpcSubKeys,
+ LPDWORD lpcbMaxSubKeyLen,
+ LPDWORD lpcbMaxClassLen,
+ LPDWORD lpcValues,
+ LPDWORD lpcbMaxValueNameLen,
+ LPDWORD lpcbMaxValueLen,
+ LPDWORD lpcbSecurityDescriptor,
+ PFILETIME lpftLastWriteTime)
+{
+ WCHAR ClassName[MAX_PATH];
+ UNICODE_STRING UnicodeString;
+ ANSI_STRING AnsiString;
+ LONG ErrorCode;
+
+ RtlInitUnicodeString (&UnicodeString,
+ NULL);
+ if (lpClass != NULL)
+ {
+ UnicodeString.Buffer = &ClassName[0];
+ UnicodeString.MaximumLength = sizeof(ClassName);
+ AnsiString.MaximumLength = *lpcbClass;
+ }
+
+ ErrorCode = RegQueryInfoKeyW (hKey,
+ UnicodeString.Buffer,
+ lpcbClass,
+ lpReserved,
+ lpcSubKeys,
+ lpcbMaxSubKeyLen,
+ lpcbMaxClassLen,
+ lpcValues,
+ lpcbMaxValueNameLen,
+ lpcbMaxValueLen,
+ 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;
+ }
+
+ return ErrorCode;
+}
+
+
+/************************************************************************
+ * RegQueryInfoKeyW
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegQueryInfoKeyW (HKEY hKey,
+ LPWSTR lpClass,
+ LPDWORD lpcbClass,
+ LPDWORD lpReserved,
+ LPDWORD lpcSubKeys,
+ LPDWORD lpcbMaxSubKeyLen,
+ LPDWORD lpcbMaxClassLen,
+ LPDWORD lpcValues,
+ LPDWORD lpcbMaxValueNameLen,
+ LPDWORD lpcbMaxValueLen,
+ LPDWORD lpcbSecurityDescriptor,
+ PFILETIME lpftLastWriteTime)
+{
+ KEY_FULL_INFORMATION FullInfoBuffer;
+ PKEY_FULL_INFORMATION FullInfo;
+ ULONG FullInfoSize;
+ ULONG ClassLength = 0;
+ HANDLE KeyHandle;
+ NTSTATUS Status;
+ LONG ErrorCode = ERROR_SUCCESS;
+ ULONG Length;
+
+ 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;
+ }
+
+ if (lpClass != NULL)
+ {
+ if (*lpcbClass > 0)
+ {
+ ClassLength = min(*lpcbClass - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
+ }
+ else
+ {
+ ClassLength = 0;
+ }
+
+ FullInfoSize = sizeof(KEY_FULL_INFORMATION) + ((ClassLength + 3) & ~3);
+ FullInfo = RtlAllocateHeap (ProcessHeap,
+ 0,
+ FullInfoSize);
+ if (FullInfo == NULL)
+ {
+ SetLastError (ERROR_OUTOFMEMORY);
+ return ERROR_OUTOFMEMORY;
+ }
+
+ FullInfo->ClassLength = ClassLength;
+ }
+ else
+ {
+ FullInfoSize = sizeof(KEY_FULL_INFORMATION);
+ FullInfo = &FullInfoBuffer;
+ FullInfo->ClassLength = 0;
+ }
+ FullInfo->ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
+
+ Status = NtQueryKey (KeyHandle,
+ KeyFullInformation,
+ FullInfo,
+ FullInfoSize,
+ &Length);
+ DPRINT("NtQueryKey() returned status 0x%X\n", Status);
+ if (!NT_SUCCESS(Status))
+ {
+ if (lpClass != NULL)
+ {
+ RtlFreeHeap (ProcessHeap,
+ 0,
+ FullInfo);
+ }
+
+ ErrorCode = RtlNtStatusToDosError (Status);
+ SetLastError (ErrorCode);
+ return ErrorCode;
+ }
+
+ DPRINT("SubKeys %d\n", FullInfo->SubKeys);
+ if (lpcSubKeys != NULL)
+ {
+ *lpcSubKeys = FullInfo->SubKeys;
+ }
+
+ DPRINT("MaxNameLen %lu\n", FullInfo->MaxNameLen);
+ if (lpcbMaxSubKeyLen != NULL)
+ {
+ *lpcbMaxSubKeyLen = FullInfo->MaxNameLen / sizeof(WCHAR) + 1;
+ }
+
+ DPRINT("MaxClassLen %lu\n", FullInfo->MaxClassLen);
+ if (lpcbMaxClassLen != NULL)
+ {
+ *lpcbMaxClassLen = FullInfo->MaxClassLen / sizeof(WCHAR) + 1;
+ }
+
+ DPRINT("Values %lu\n", FullInfo->Values);
+ if (lpcValues != NULL)
+ {
+ *lpcValues = FullInfo->Values;
+ }
+
+ DPRINT("MaxValueNameLen %lu\n", FullInfo->MaxValueNameLen);
+ if (lpcbMaxValueNameLen != NULL)
+ {
+ *lpcbMaxValueNameLen = FullInfo->MaxValueNameLen / sizeof(WCHAR) + 1;
+ }
+
+ DPRINT("MaxValueDataLen %lu\n", FullInfo->MaxValueDataLen);
+ if (lpcbMaxValueLen != NULL)
+ {
+ *lpcbMaxValueLen = FullInfo->MaxValueDataLen;
+ }
+
+ if (lpcbSecurityDescriptor != NULL)
+ {
+ /* FIXME */
+ *lpcbSecurityDescriptor = 0;
+ }
+
+ if (lpftLastWriteTime != NULL)
+ {
+ lpftLastWriteTime->dwLowDateTime = FullInfo->LastWriteTime.u.LowPart;
+ lpftLastWriteTime->dwHighDateTime = FullInfo->LastWriteTime.u.HighPart;
+ }
+
+ if (lpClass != NULL)
+ {
+ if (FullInfo->ClassLength > ClassLength)
+ {
+ ErrorCode = ERROR_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ RtlCopyMemory (lpClass,
+ FullInfo->Class,
+ FullInfo->ClassLength);
+ *lpcbClass = FullInfo->ClassLength / sizeof(WCHAR);
+ lpClass[*lpcbClass] = 0;
+ }
+
+ RtlFreeHeap (ProcessHeap,
+ 0,
+ FullInfo);
+ }
+
+ if (ErrorCode != ERROR_SUCCESS)
+ {
+ SetLastError (ErrorCode);
+ }
+
+ return ErrorCode;
+}
+
+
+/************************************************************************
+ * RegQueryMultipleValuesA
+ *
+ * @unimplemented
+ */
+LONG STDCALL
+RegQueryMultipleValuesA (HKEY hKey,
+ PVALENTA val_list,
+ DWORD num_vals,
+ LPSTR lpValueBuf,
+ LPDWORD ldwTotsize)
+{
+ UNIMPLEMENTED;
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/************************************************************************
+ * RegQueryMultipleValuesW
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegQueryMultipleValuesW (HKEY hKey,
+ PVALENTW val_list,
+ DWORD num_vals,
+ LPWSTR lpValueBuf,
+ LPDWORD ldwTotsize)
+{
+ ULONG i;
+ DWORD maxBytes = *ldwTotsize;
+ LPSTR bufptr = (LPSTR)lpValueBuf;
+ LONG ErrorCode;
+
+ if (maxBytes >= (1024*1024))
+ return ERROR_TRANSFER_TOO_LONG;
+
+ *ldwTotsize = 0;
+
+ DPRINT ("RegQueryMultipleValuesW(%p,%p,%ld,%p,%p=%ld)\n",
+ hKey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize);
+
+ for (i = 0; i < num_vals; ++i)
+ {
+ val_list[i].ve_valuelen = 0;
+ ErrorCode = RegQueryValueExW (hKey,
+ val_list[i].ve_valuename,
+ NULL,
+ NULL,
+ NULL,
+ &val_list[i].ve_valuelen);
+ if (ErrorCode != ERROR_SUCCESS)
+ {
+ return ErrorCode;
+ }
+
+ if (lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes)
+ {
+ ErrorCode = RegQueryValueExW (hKey,
+ val_list[i].ve_valuename,
+ NULL,
+ &val_list[i].ve_type,
+ bufptr,
+ &val_list[i].ve_valuelen);
+ if (ErrorCode != ERROR_SUCCESS)
+ {
+ return ErrorCode;
+ }
+
+ val_list[i].ve_valueptr = (DWORD_PTR)bufptr;
+
+ bufptr += val_list[i].ve_valuelen;
+ }
+
+ *ldwTotsize += val_list[i].ve_valuelen;
+ }
+
+ return (lpValueBuf != NULL && *ldwTotsize <= maxBytes) ? ERROR_SUCCESS : ERROR_MORE_DATA;
+}
+
+
+/************************************************************************
+ * RegQueryValueExW
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegQueryValueExW (HKEY hKey,
+ LPCWSTR lpValueName,
+ LPDWORD lpReserved,
+ LPDWORD lpType,
+ LPBYTE lpData,
+ LPDWORD lpcbData)
+{
+ PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
+ UNICODE_STRING ValueName;
+ NTSTATUS Status;
+ LONG ErrorCode = ERROR_SUCCESS;
+ ULONG BufferSize;
+ ULONG ResultSize;
+ HANDLE KeyHandle;
+ ULONG MaxCopy = lpcbData != NULL && lpData != NULL ? *lpcbData : 0;
+
+ DPRINT("hKey 0x%X lpValueName %S lpData 0x%X lpcbData %d\n",
+ hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
+
+ Status = MapDefaultKey (&KeyHandle,
+ hKey);
+ if (!NT_SUCCESS(Status))
+ {
+ ErrorCode = RtlNtStatusToDosError (Status);
+ SetLastError (ErrorCode);
+ return ErrorCode;
+ }
+
+ if (lpData != NULL && lpcbData == NULL)
+ {
+ SetLastError (ERROR_INVALID_PARAMETER);
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ RtlInitUnicodeString (&ValueName,
+ lpValueName);
+ BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + MaxCopy;
+ ValueInfo = RtlAllocateHeap (ProcessHeap,
+ 0,
+ BufferSize);
+ if (ValueInfo == NULL)
+ {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return ERROR_OUTOFMEMORY;
+ }
+
+ Status = NtQueryValueKey (hKey,
+ &ValueName,
+ KeyValuePartialInformation,
+ ValueInfo,
+ BufferSize,
+ &ResultSize);
+ DPRINT("Status 0x%X\n", Status);
+ if (Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
+ MaxCopy = 0;
+ ErrorCode = lpData ? ERROR_MORE_DATA : ERROR_SUCCESS;
+ }
+ else if (!NT_SUCCESS(Status))
+ {
+ ErrorCode = RtlNtStatusToDosError (Status);
+ SetLastError (ErrorCode);
+ MaxCopy = 0;
+ if (lpcbData != NULL)