implemented RegOpenUserClassesRoot (doesn't work in reactos because there's no symbolic link \Registry\User\<SID>_Classes yet)
Modified: trunk/reactos/lib/advapi32/advapi32.def
Modified: trunk/reactos/lib/advapi32/reg/reg.c

Modified: trunk/reactos/lib/advapi32/advapi32.def
--- trunk/reactos/lib/advapi32/advapi32.def	2005-05-05 17:20:10 UTC (rev 15008)
+++ trunk/reactos/lib/advapi32/advapi32.def	2005-05-05 17:45:00 UTC (rev 15009)
@@ -492,7 +492,7 @@
 RegOpenKeyExA@20
 RegOpenKeyExW@20
 RegOpenKeyW@12
-;RegOpenUserClassesRoot
+RegOpenUserClassesRoot@16
 ;RegOverridePredefKey
 RegQueryInfoKeyA@48
 RegQueryInfoKeyW@48

Modified: trunk/reactos/lib/advapi32/reg/reg.c
--- trunk/reactos/lib/advapi32/reg/reg.c	2005-05-05 17:20:10 UTC (rev 15008)
+++ trunk/reactos/lib/advapi32/reg/reg.c	2005-05-05 17:45:00 UTC (rev 15009)
@@ -1720,6 +1720,152 @@
 
 
 /************************************************************************
+ *  RegOpenUserClassesRoot
+ *
+ * @implemented
+ */
+LONG STDCALL
+RegOpenUserClassesRoot (IN HANDLE hToken,
+                        IN DWORD dwOptions,
+                        IN REGSAM samDesired,
+                        OUT PHKEY phkResult)
+{
+  const WCHAR UserClassesKeyPrefix[] = L"\\Registry\\User\\";
+  const WCHAR UserClassesKeySuffix[] = L"_Classes";
+  PTOKEN_USER TokenUserData;
+  ULONG RequiredLength;
+  UNICODE_STRING UserSidString, UserClassesKeyRoot;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  LONG ErrorCode;
+  NTSTATUS Status;
+  
+  /* check parameters */
+  if (hToken == NULL || dwOptions != 0 || phkResult == NULL)
+  {
+    return ERROR_INVALID_PARAMETER;
+  }
+  
+  /*
+   * Get the user sid from the token
+   */
+
+ReadTokenSid:
+  /* determine how much memory we need */
+  Status = NtQueryInformationToken(hToken,
+                                   TokenUser,
+                                   NULL,
+                                   0,
+                                   &RequiredLength);
+  if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_TOO_SMALL))
+  {
+    /* NOTE - as opposed to all other registry functions windows does indeed
+              change the last error code in case the caller supplied a invalid
+              handle for example! */
+    ErrorCode = RtlNtStatusToDosError (Status);
+    return ErrorCode;
+  }
+
+  TokenUserData = RtlAllocateHeap(ProcessHeap,
+                                  0,
+                                  RequiredLength);
+  if (TokenUserData == NULL)
+  {
+    return ERROR_NOT_ENOUGH_MEMORY;
+  }
+
+  /* attempt to read the information */
+  Status = NtQueryInformationToken(hToken,
+                                   TokenUser,
+                                   TokenUserData,
+                                   RequiredLength,
+                                   &RequiredLength);
+  if (!NT_SUCCESS(Status))
+  {
+    RtlFreeHeap(ProcessHeap,
+                0,
+                TokenUserData);
+    if (Status == STATUS_BUFFER_TOO_SMALL)
+    {
+      /* the information appears to have changed?! try again */
+      goto ReadTokenSid;
+    }
+    
+    /* NOTE - as opposed to all other registry functions windows does indeed
+              change the last error code in case the caller supplied a invalid
+              handle for example! */
+    ErrorCode = RtlNtStatusToDosError (Status);
+    return ErrorCode;
+  }
+  
+  /*
+   * Build the absolute path for the user's registry in the form
+   * "\Registry\User\<SID>_Classes"
+   */
+  Status = RtlConvertSidToUnicodeString(&UserSidString,
+                                        TokenUserData->User.Sid,
+                                        TRUE);
+
+  /* we don't need the user data anymore, free it */
+  RtlFreeHeap(ProcessHeap,
+              0,
+              TokenUserData);
+
+  if (!NT_SUCCESS(Status))
+  {
+    return RtlNtStatusToDosError (Status);
+  }
+  
+  /* allocate enough memory for the entire key string */
+  UserClassesKeyRoot.Length = 0;
+  UserClassesKeyRoot.MaximumLength = UserSidString.Length +
+                                     sizeof(UserClassesKeyPrefix) +
+                                     sizeof(UserClassesKeySuffix);
+  UserClassesKeyRoot.Buffer = RtlAllocateHeap(ProcessHeap,
+                                              0,
+                                              UserClassesKeyRoot.MaximumLength);
+  if (UserClassesKeyRoot.Buffer == NULL)
+  {
+    RtlFreeUnicodeString(&UserSidString);
+    return RtlNtStatusToDosError (Status);
+  }
+  
+  /* build the string */
+  RtlAppendUnicodeToString(&UserClassesKeyRoot,
+                           UserClassesKeyPrefix);
+  RtlAppendUnicodeStringToString(&UserClassesKeyRoot,
+                                 &UserSidString);
+  RtlAppendUnicodeToString(&UserClassesKeyRoot,
+                           UserClassesKeySuffix);
+  
+  DPRINT("RegOpenUserClassesRoot: Absolute path: %wZ\n", &UserClassesKeyRoot);
+
+  /*
+   * Open the key
+   */
+
+  InitializeObjectAttributes (&ObjectAttributes,
+			      &UserClassesKeyRoot,
+			      OBJ_CASE_INSENSITIVE,
+			      NULL,
+			      NULL);
+  
+  Status = NtOpenKey((PHANDLE)phkResult,
+                     samDesired,
+                     &ObjectAttributes);
+  
+  RtlFreeUnicodeString(&UserSidString);
+  RtlFreeUnicodeString(&UserClassesKeyRoot);
+  
+  if (!NT_SUCCESS(Status))
+  {
+    return RtlNtStatusToDosError (Status);
+  }
+  
+  return ERROR_SUCCESS;
+}
+
+
+/************************************************************************
  *  RegQueryInfoKeyA
  *
  * @implemented