[ADVAPI32]
[reactos.git] / reactos / dll / win32 / advapi32 / reg / reg.c
index cfc8ba1..c14466c 100644 (file)
@@ -14,8 +14,6 @@
 /* INCLUDES *****************************************************************/
 
 #include <advapi32.h>
-#include <wine/debug.h>
-
 WINE_DEFAULT_DEBUG_CHANNEL(reg);
 
 /* DEFINES ******************************************************************/
@@ -1023,8 +1021,9 @@ RegCreateKeyExA(HKEY hKey,
 {
     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");
@@ -1048,15 +1047,18 @@ RegCreateKeyExA(HKEY hKey,
                                          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,
@@ -1097,8 +1099,9 @@ RegCreateKeyExW(HKEY hKey,
 {
     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");
@@ -1116,17 +1119,20 @@ RegCreateKeyExW(HKEY hKey,
 
     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,
@@ -2545,7 +2551,7 @@ RegEnumKeyExA(HKEY hKey,
             if (KeyInfo->Node.NameLength > NameLength ||
                 KeyInfo->Node.ClassLength > ClassLength)
             {
-                               ErrorCode = ERROR_BUFFER_OVERFLOW;
+                ErrorCode = ERROR_BUFFER_OVERFLOW;
             }
             else
             {
@@ -3349,6 +3355,7 @@ RegOpenKeyExA(HKEY hKey,
     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",
@@ -3365,11 +3372,14 @@ RegOpenKeyExA(HKEY hKey,
         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);
 
@@ -3404,6 +3414,7 @@ RegOpenKeyExW(HKEY hKey,
     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",
@@ -3419,6 +3430,9 @@ RegOpenKeyExW(HKEY hKey,
         return RtlNtStatusToDosError(Status);
     }
 
+    if (ulOptions & REG_OPTION_OPEN_LINK)
+        Attributes |= OBJ_OPENLINK;
+
     if (lpSubKey != NULL)
         RtlInitUnicodeString(&SubKeyString, (LPWSTR)lpSubKey);
     else
@@ -3426,7 +3440,7 @@ RegOpenKeyExW(HKEY hKey,
 
     InitializeObjectAttributes(&ObjectAttributes,
                                &SubKeyString,
-                               OBJ_CASE_INSENSITIVE,
+                               Attributes,
                                KeyHandle,
                                NULL);
 
@@ -3974,128 +3988,127 @@ RegQueryReflectionKey(IN HKEY hBase,
 }
 
 
-/************************************************************************
- *  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;
-    LPWSTR lpValueBuffer;
-    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);
     }
 
-    Length = (lpcbData == NULL || lpData == NULL) ? 0 : *lpcbData * sizeof(WCHAR);
+    if (count) datalen = *count;
+    if (!data && count) *count = 0;
 
-    if (lpData)
+    RtlInitAnsiString( &nameA, name );
+    if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
     {
-        lpValueBuffer = RtlAllocateHeap(ProcessHeap,
-                                        0,
-                                        Length + sizeof(WCHAR));
-        if (!lpValueBuffer)
-        {
-            return ERROR_OUTOFMEMORY;
-        }
+        ClosePredefKey(hkey);
+        return RtlNtStatusToDosError(status);
     }
-    else
-    {
-        lpValueBuffer = NULL;
 
-        if (lpcbData)
-            *lpcbData = 0;
-    }
+    status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
+                              buffer, sizeof(buffer), &total_size );
+    if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
 
-    if(!RtlCreateUnicodeStringFromAsciiz(&ValueName,
-                                         (LPSTR)lpValueName))
+    /* 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))
     {
-        ERR("RtlCreateUnicodeStringFromAsciiz failed!\n");
-        ErrorCode = ERROR_OUTOFMEMORY;
-        goto cleanup;
-    }
-
-    ErrorCode = RegQueryValueExW(hKey,
-                                 ValueName.Buffer,
-                                 lpReserved,
-                                 &Type,
-                                 (LPBYTE)lpValueBuffer,
-                                 &Length);
-    TRACE("ErrorCode %lu\n", ErrorCode);
-
-    RtlFreeUnicodeString(&ValueName);
+        /* 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 );
+        }
 
-    if (ErrorCode == ERROR_SUCCESS ||
-        ErrorCode == ERROR_MORE_DATA)
-    {
+        if (status) goto done;
 
-        if (is_string(Type))
+        if (is_string(info->Type))
         {
-            if (ErrorCode == ERROR_SUCCESS && lpValueBuffer != NULL)
+            DWORD len;
+
+            RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
+                                       total_size - info_size );
+            if (data && len)
             {
-                Status = RtlUnicodeToMultiByteN((PCHAR)lpData, *lpcbData, &Index, (PWCHAR)lpValueBuffer, Length);
-                if (NT_SUCCESS(Status))
-                {
-                    PCHAR szData = (PCHAR)lpData;
-                    if(&szData[Index] < (PCHAR)(lpData + *lpcbData))
-                    {
-                        szData[Index] = '\0';
-                    }
-                }
+                if (len > datalen) status = STATUS_BUFFER_OVERFLOW;
                 else
                 {
-                    ErrorCode = RtlNtStatusToDosError(Status);
+                    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;
                 }
             }
-
-            Length = Length / sizeof(WCHAR);
-        }
-        else if (ErrorCode == ERROR_SUCCESS && lpValueBuffer != NULL)
-        {
-            if (*lpcbData < Length)
-            {
-                ErrorCode = ERROR_MORE_DATA;
-            }
-            else
-            {
-                RtlMoveMemory(lpData, lpValueBuffer, Length);
-            }
+            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;
-    }
-
-cleanup:
-    if (lpValueBuffer != NULL)
-    {
-        RtlFreeHeap(ProcessHeap, 0, lpValueBuffer);
-    }
+    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);
 }