/* INCLUDES *****************************************************************/
#include <advapi32.h>
-#include <wine/debug.h>
+
+#include <ndk/cmfuncs.h>
+#include <pseh/pseh2.h>
WINE_DEFAULT_DEBUG_CHANNEL(reg);
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)
{
UNICODE_STRING SubKeyString;
UNICODE_STRING ClassString;
- OBJECT_ATTRIBUTES Attributes;
+ OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE ParentKey;
+ ULONG Attributes = OBJ_CASE_INSENSITIVE;
NTSTATUS Status;
TRACE("RegCreateKeyExA() called\n");
lpClass);
}
+ if (dwOptions & REG_OPTION_OPEN_LINK)
+ Attributes |= OBJ_OPENLINK;
+
RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
(LPSTR)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,
{
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 (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,
/************************************************************************
* RegDeleteKeyExA
*
- * @unimplemented
+ * @implemented
*/
LONG
WINAPI
REGSAM samDesired,
DWORD Reserved)
{
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return ERROR_CALL_NOT_IMPLEMENTED;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING SubKeyName;
+ HANDLE ParentKey;
+ HANDLE TargetKey;
+ NTSTATUS Status;
+
+ /* Make sure we got a subkey */
+ if (!lpSubKey)
+ {
+ /* Fail */
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ Status = MapDefaultKey(&ParentKey,
+ hKey);
+ if (!NT_SUCCESS(Status))
+ {
+ return RtlNtStatusToDosError(Status);
+ }
+
+ if (samDesired & KEY_WOW64_32KEY)
+ ERR("Wow64 not yet supported!\n");
+
+ if (samDesired & KEY_WOW64_64KEY)
+ ERR("Wow64 not yet supported!\n");
+
+ RtlCreateUnicodeStringFromAsciiz(&SubKeyName,
+ (LPSTR)lpSubKey);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &SubKeyName,
+ OBJ_CASE_INSENSITIVE,
+ ParentKey,
+ NULL);
+
+ Status = NtOpenKey(&TargetKey,
+ DELETE,
+ &ObjectAttributes);
+ RtlFreeUnicodeString(&SubKeyName);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ Status = NtDeleteKey(TargetKey);
+ NtClose (TargetKey);
+
+Cleanup:
+ ClosePredefKey(ParentKey);
+
+ if (!NT_SUCCESS(Status))
+ {
+ return RtlNtStatusToDosError(Status);
+ }
+
+ return ERROR_SUCCESS;
}
/************************************************************************
* RegDeleteKeyExW
*
- * @unimplemented
+ * @implemented
*/
LONG
WINAPI
REGSAM samDesired,
DWORD Reserved)
{
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return ERROR_CALL_NOT_IMPLEMENTED;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING SubKeyName;
+ HANDLE ParentKey;
+ HANDLE TargetKey;
+ NTSTATUS Status;
+
+ /* Make sure we got a subkey */
+ if (!lpSubKey)
+ {
+ /* Fail */
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ Status = MapDefaultKey(&ParentKey,
+ hKey);
+ if (!NT_SUCCESS(Status))
+ {
+ return RtlNtStatusToDosError(Status);
+ }
+
+ 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,
+ &SubKeyName,
+ OBJ_CASE_INSENSITIVE,
+ ParentKey,
+ NULL);
+ Status = NtOpenKey(&TargetKey,
+ DELETE,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ Status = NtDeleteKey(TargetKey);
+ NtClose(TargetKey);
+
+Cleanup:
+ ClosePredefKey(ParentKey);
+
+ if (!NT_SUCCESS(Status))
+ {
+ return RtlNtStatusToDosError(Status);
+ }
+
+ return ERROR_SUCCESS;
}
if (KeyInfo->Node.NameLength > NameLength ||
KeyInfo->Node.ClassLength > ClassLength)
{
- ErrorCode = ERROR_BUFFER_OVERFLOW;
+ ErrorCode = ERROR_BUFFER_OVERFLOW;
}
else
{
return RtlNtStatusToDosError(Status);
}
-#if 0
Status = NtQuerySecurityObject(KeyHandle,
SecurityInformation,
pSecurityDescriptor,
*lpcbSecurityDescriptor,
lpcbSecurityDescriptor);
-#endif
ClosePredefKey(KeyHandle);
UNICODE_STRING SubKeyString;
HANDLE KeyHandle;
NTSTATUS Status;
+ ULONG Attributes = OBJ_CASE_INSENSITIVE;
LONG ErrorCode = ERROR_SUCCESS;
TRACE("RegOpenKeyExA hKey 0x%x lpSubKey %s ulOptions 0x%x samDesired 0x%x phkResult %p\n",
return RtlNtStatusToDosError(Status);
}
+ if (ulOptions & REG_OPTION_OPEN_LINK)
+ Attributes |= OBJ_OPENLINK;
+
RtlCreateUnicodeStringFromAsciiz(&SubKeyString,
(LPSTR)lpSubKey);
InitializeObjectAttributes(&ObjectAttributes,
&SubKeyString,
- OBJ_CASE_INSENSITIVE,
+ Attributes,
KeyHandle,
NULL);
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 (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);
*lpcbMaxValueLen = FullInfo->MaxValueDataLen;
}
-#if 0
if (lpcbSecurityDescriptor != NULL)
{
Status = NtQuerySecurityObject(KeyHandle,
goto Cleanup;
}
}
-#endif
if (lpftLastWriteTime != NULL)
{
}
-/************************************************************************
- * RegQueryValueExA
+/******************************************************************************
+ * RegQueryValueExA [ADVAPI32.@]
*
- * @implemented
+ * Get the type and contents of a specified value under with a key.
+ *
+ * PARAMS
+ * hkey [I] Handle of the key to query
+ * name [I] Name of value under hkey to query
+ * reserved [I] Reserved - must be NULL
+ * type [O] Destination for the value type, or NULL if not required
+ * data [O] Destination for the values contents, or NULL if not required
+ * count [I/O] Size of data, updated with the number of bytes returned
+ *
+ * RETURNS
+ * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data.
+ * 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
+ * it remains untouched.
*/
-LONG WINAPI
-RegQueryValueExA(HKEY hKey,
- LPCSTR lpValueName,
- LPDWORD lpReserved,
- LPDWORD lpType,
- LPBYTE lpData,
- LPDWORD lpcbData)
+LONG
+WINAPI
+RegQueryValueExA(HKEY hkeyorg,
+ LPCSTR name,
+ LPDWORD reserved,
+ LPDWORD type,
+ LPBYTE data,
+ LPDWORD count)
{
- UNICODE_STRING ValueName;
- UNICODE_STRING ValueData;
- LONG ErrorCode;
- DWORD Length;
- DWORD Type;
- NTSTATUS Status;
- ULONG Index;
+ 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 );
- TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
- hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
+ TRACE("(%p,%s,%p,%p,%p,%p=%d)\n",
+ hkeyorg, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
- if (lpData != NULL && lpcbData == NULL)
+ if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
+ status = MapDefaultKey(&hkey, hkeyorg);
+ if (!NT_SUCCESS(status))
{
- return ERROR_INVALID_PARAMETER;
+ return RtlNtStatusToDosError(status);
}
- if (lpData)
- {
- ValueData.Length = 0;
- ValueData.MaximumLength = (*lpcbData + 1) * sizeof(WCHAR);
- ValueData.Buffer = RtlAllocateHeap(ProcessHeap,
- 0,
- ValueData.MaximumLength);
- if (!ValueData.Buffer)
- {
- return ERROR_OUTOFMEMORY;
- }
- }
- else
- {
- ValueData.Buffer = NULL;
- ValueData.Length = 0;
- ValueData.MaximumLength = 0;
+ if (count) datalen = *count;
+ if (!data && count) *count = 0;
- if (lpcbData)
- *lpcbData = 0;
+ RtlInitAnsiString( &nameA, name );
+ if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
+ {
+ ClosePredefKey(hkey);
+ return RtlNtStatusToDosError(status);
}
- RtlCreateUnicodeStringFromAsciiz(&ValueName,
- (LPSTR)lpValueName);
-
- Length = (lpcbData == NULL) ? 0 : *lpcbData * sizeof(WCHAR);
- ErrorCode = RegQueryValueExW(hKey,
- ValueName.Buffer,
- lpReserved,
- &Type,
- (lpData == NULL) ? NULL : (LPBYTE)ValueData.Buffer,
- &Length);
- TRACE("ErrorCode %lu\n", ErrorCode);
- RtlFreeUnicodeString(&ValueName);
+ status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
+ buffer, sizeof(buffer), &total_size );
+ if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
- if (ErrorCode == ERROR_SUCCESS ||
- ErrorCode == ERROR_MORE_DATA)
+ /* 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))
{
-
- if (is_string(Type))
+ /* retry with a dynamically allocated buffer */
+ while (status == STATUS_BUFFER_OVERFLOW)
{
- if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
+ if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
+ if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
{
- Status = RtlUnicodeToMultiByteN((PCHAR)lpData, *lpcbData, &Index, (PWCHAR)ValueData.Buffer, Length);
- if (NT_SUCCESS(Status))
- {
- PCHAR szData = (PCHAR)lpData;
- if(&szData[Index] < (PCHAR)(lpData + *lpcbData))
- {
- szData[Index] = '\0';
- }
- }
- else
- {
- ErrorCode = RtlNtStatusToDosError(Status);
- }
+ status = STATUS_NO_MEMORY;
+ goto done;
}
-
- Length = Length / sizeof(WCHAR);
+ info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
+ status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
+ buf_ptr, total_size, &total_size );
}
- else if (ErrorCode == ERROR_SUCCESS && ValueData.Buffer != NULL)
+
+ if (status) goto done;
+
+ if (is_string(info->Type))
{
- if (*lpcbData < Length)
- {
- ErrorCode = ERROR_MORE_DATA;
- }
- else
+ DWORD len;
+
+ RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
+ total_size - info_size );
+ if (data && len)
{
- RtlMoveMemory(lpData, ValueData.Buffer, Length);
+ 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;
}
-
- if (lpcbData != NULL)
+ else if (data)
{
- *lpcbData = Length;
+ if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW;
+ else memcpy( data, buf_ptr + info_size, total_size - info_size );
}
}
+ else status = STATUS_SUCCESS;
- if (lpType != NULL)
- {
- *lpType = Type;
- }
-
- if (ValueData.Buffer != NULL)
- {
- RtlFreeHeap(ProcessHeap, 0, ValueData.Buffer);
- }
+ if (type) *type = info->Type;
+ if (count) *count = total_size - info_size;
- return ErrorCode;
+ done:
+ if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
+ RtlFreeUnicodeString( &nameW );
+ ClosePredefKey(hkey);
+ return RtlNtStatusToDosError(status);
}
DWORD cbData)
{
UNICODE_STRING ValueName;
- PUNICODE_STRING pValueName;
HANDLE KeyHandle;
NTSTATUS Status;
+ if (is_string(dwType) && (cbData != 0))
+ {
+ PWSTR pwsData = (PWSTR)lpData;
+
+ _SEH2_TRY
+ {
+ 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)
+ {
+ _SEH2_YIELD(return ERROR_NOACCESS);
+ }
+ _SEH2_END;
+ }
+
Status = MapDefaultKey(&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
}
RtlInitUnicodeString(&ValueName, lpValueName);
- pValueName = &ValueName;
-
- if (is_string(dwType) && (cbData != 0))
- {
- PWSTR pwsData = (PWSTR)lpData;
-
- 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);
- }
- }
Status = NtSetValueKey(KeyHandle,
- pValueName,
+ &ValueName,
0,
dwType,
(PVOID)lpData,