/* INCLUDES *****************************************************************/
#include <advapi32.h>
-#include <wine/debug.h>
-
WINE_DEFAULT_DEBUG_CHANNEL(reg);
/* DEFINES ******************************************************************/
{
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,
if (KeyInfo->Node.NameLength > NameLength ||
KeyInfo->Node.ClassLength > ClassLength)
{
- ErrorCode = ERROR_BUFFER_OVERFLOW;
+ ErrorCode = ERROR_BUFFER_OVERFLOW;
}
else
{
status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
buffer, total_size, &total_size );
- if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
+ if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done;
/* 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))
{
/* retry with a dynamically allocated buffer */
- while (status == STATUS_BUFFER_OVERFLOW)
+ 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 )))
{
ULONG len;
RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
- total_size - 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),
- total_size - 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;
}
else if (data)
{
- if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
- else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
+ if (info->DataLength > *count) status = STATUS_BUFFER_OVERFLOW;
+ else memcpy( data, buf_ptr + info->DataOffset, info->DataLength );
}
if (value && !status)
status = NtEnumerateValueKey( KeyHandle, index, KeyValueFullInformation,
buffer, total_size, &total_size );
- if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
+ if (status && (status != STATUS_BUFFER_OVERFLOW) && (status != STATUS_BUFFER_TOO_SMALL)) goto done;
if (value || data)
{
/* retry with a dynamically allocated buffer */
- while (status == STATUS_BUFFER_OVERFLOW)
+ 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 )))
if (data)
{
- if (total_size - info->DataOffset > *count)
+ if (info->DataLength > *count)
{
status = STATUS_BUFFER_OVERFLOW;
goto overflow;
}
- memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
- if (total_size - info->DataOffset <= *count-sizeof(WCHAR) && is_string(info->Type))
+ memcpy( data, buf_ptr + info->DataOffset, info->DataLength );
+ if (is_string(info->Type) && info->DataLength <= *count - sizeof(WCHAR))
{
/* if the type is REG_SZ and data is not 0-terminated
* and there is enough space in the buffer NT appends a \0 */
- WCHAR *ptr = (WCHAR *)(data + total_size - info->DataOffset);
+ WCHAR *ptr = (WCHAR *)(data + info->DataLength);
if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0;
}
}
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);
}
-/************************************************************************
- * 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);
}
return RtlNtStatusToDosError(Status);
}
- if (lpValueName != NULL)
- {
- RtlInitUnicodeString(&ValueName,
- lpValueName);
- }
- else
- {
- RtlInitUnicodeString(&ValueName, L"");
- }
+ RtlInitUnicodeString(&ValueName, lpValueName);
pValueName = &ValueName;
if (is_string(dwType) && (cbData != 0))