diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c
index bc8be94b2040242fbb605fb1088159148e249d9c..c67372a12d9e4b3a5917fc734a1a50f0cb78bb36 100644
--- a/dlls/advapi32/registry.c
+++ b/dlls/advapi32/registry.c
@@ -39,6 +39,47 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(reg);
 
+/* allowed bits for access mask */
+#define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
+
+#define HKEY_SPECIAL_ROOT_FIRST   HKEY_CLASSES_ROOT
+#define HKEY_SPECIAL_ROOT_LAST    HKEY_DYN_DATA
+#define NB_SPECIAL_ROOT_KEYS      ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
+
+static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
+
+static const WCHAR name_CLASSES_ROOT[] =
+    {'M','a','c','h','i','n','e','\\',
+     'S','o','f','t','w','a','r','e','\\',
+     'C','l','a','s','s','e','s',0};
+static const WCHAR name_LOCAL_MACHINE[] =
+    {'M','a','c','h','i','n','e',0};
+static const WCHAR name_USERS[] =
+    {'U','s','e','r',0};
+static const WCHAR name_PERFORMANCE_DATA[] =
+    {'P','e','r','f','D','a','t','a',0};
+static const WCHAR name_CURRENT_CONFIG[] =
+    {'M','a','c','h','i','n','e','\\',
+     'S','y','s','t','e','m','\\',
+     'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
+     'H','a','r','d','w','a','r','e','P','r','o','f','i','l','e','s','\\',
+     'C','u','r','r','e','n','t',0};
+static const WCHAR name_DYN_DATA[] =
+    {'D','y','n','D','a','t','a',0};
+
+#define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
+static UNICODE_STRING root_key_names[NB_SPECIAL_ROOT_KEYS] =
+{
+    DECL_STR(CLASSES_ROOT),
+    { 0, 0, NULL },         /* HKEY_CURRENT_USER is determined dynamically */
+    DECL_STR(LOCAL_MACHINE),
+    DECL_STR(USERS),
+    DECL_STR(PERFORMANCE_DATA),
+    DECL_STR(CURRENT_CONFIG),
+    DECL_STR(DYN_DATA)
+};
+#undef DECL_STR
+
 
 /* check if value type needs string conversion (Ansi<->Unicode) */
 inline static int is_string( DWORD type )
@@ -52,8 +93,51 @@ inline static int is_version_nt(void)
     return !(GetVersion() & 0x80000000);
 }
 
-/* allowed bits for access mask */
-#define KEY_ACCESS_MASK (KEY_ALL_ACCESS | MAXIMUM_ALLOWED)
+/* create one of the HKEY_* special root keys */
+static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
+{
+    HKEY ret = 0;
+    int idx = (UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST;
+
+    if (hkey == HKEY_CURRENT_USER)
+    {
+        if (RtlOpenCurrentUser( access, &hkey )) return 0;
+        TRACE( "HKEY_CURRENT_USER -> %08x\n", hkey );
+    }
+    else
+    {
+        OBJECT_ATTRIBUTES attr;
+
+        attr.Length = sizeof(attr);
+        attr.RootDirectory = 0;
+        attr.ObjectName = &root_key_names[idx];
+        attr.Attributes = 0;
+        attr.SecurityDescriptor = NULL;
+        attr.SecurityQualityOfService = NULL;
+        if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
+        TRACE( "%s -> %08x\n", debugstr_w(attr.ObjectName->Buffer), hkey );
+    }
+
+    if (!(ret = InterlockedCompareExchange( (PLONG)&special_root_keys[idx], hkey, 0 )))
+        ret = hkey;
+    else
+        NtClose( hkey );  /* somebody beat us to it */
+    return ret;
+}
+
+/* map the hkey from special root to normal key if necessary */
+inline static HKEY get_special_root_hkey( HKEY hkey )
+{
+    HKEY ret = hkey;
+
+    if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
+    {
+        if (!(ret = special_root_keys[(UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST]))
+            ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
+    }
+    return ret;
+}
+
 
 /******************************************************************************
  *           RegCreateKeyExW   [ADVAPI32.@]
@@ -83,6 +167,7 @@ DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR cl
 
     if (reserved) return ERROR_INVALID_PARAMETER;
     if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     attr.Length = sizeof(attr);
     attr.RootDirectory = hkey;
@@ -115,6 +200,7 @@ DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR clas
     if (reserved) return ERROR_INVALID_PARAMETER;
     if (!is_version_nt()) access = KEY_ALL_ACCESS;  /* Win95 ignores the access mask */
     else if (!(access & KEY_ACCESS_MASK) || (access & ~KEY_ACCESS_MASK)) return ERROR_ACCESS_DENIED;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     attr.Length = sizeof(attr);
     attr.RootDirectory = hkey;
@@ -187,6 +273,8 @@ DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, REGSAM acce
     OBJECT_ATTRIBUTES attr;
     UNICODE_STRING nameW;
 
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
     attr.Length = sizeof(attr);
     attr.RootDirectory = hkey;
     attr.ObjectName = &nameW;
@@ -209,6 +297,8 @@ DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, REGSAM acces
 
     if (!is_version_nt()) access = KEY_ALL_ACCESS;  /* Win95 ignores the access mask */
 
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
     attr.Length = sizeof(attr);
     attr.RootDirectory = hkey;
     attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
@@ -295,8 +385,7 @@ DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_le
            name_len ? *name_len : -1, reserved, class, class_len, ft );
 
     if (reserved) return ERROR_INVALID_PARAMETER;
-
-    if (!hkey) return ERROR_INVALID_HANDLE;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
                              buffer, sizeof(buffer), &total_size );
@@ -358,8 +447,7 @@ DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len
            name_len ? *name_len : -1, reserved, class, class_len, ft );
 
     if (reserved) return ERROR_INVALID_PARAMETER;
-
-    if (!hkey) return ERROR_INVALID_HANDLE;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
                              buffer, sizeof(buffer), &total_size );
@@ -464,6 +552,7 @@ DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWO
            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
 
     if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
@@ -612,6 +701,7 @@ DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWOR
            reserved, subkeys, max_subkey, values, max_value, max_data, security, modif );
 
     if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
@@ -694,6 +784,8 @@ DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name )
     DWORD ret;
     HKEY tmp;
 
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
     if (!name || !*name)
     {
         ret = RtlNtStatusToDosError( NtDeleteKey( hkey ) );
@@ -726,6 +818,8 @@ DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name )
     DWORD ret;
     HKEY tmp;
 
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
     if (!name || !*name)
     {
         ret = RtlNtStatusToDosError( NtDeleteKey( hkey ) );
@@ -788,6 +882,7 @@ DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
         if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
             count += sizeof(WCHAR);
     }
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     RtlInitUnicodeString( &nameW, name );
     return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
@@ -814,6 +909,8 @@ DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
         if (data[count-1] && !data[count]) count++;
     }
 
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
     if (is_string( type )) /* need to convert to Unicode */
     {
         DWORD lenW;
@@ -916,6 +1013,7 @@ DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWOR
           hkey, debugstr_w(name), reserved, type, data, count, count ? *count : 0 );
 
     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     RtlInitUnicodeString( &name_str, name );
 
@@ -983,6 +1081,7 @@ DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD
           hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
 
     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     RtlInitAnsiString( &nameA, name );
     if ((status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
@@ -1132,6 +1231,7 @@ DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_co
 
     /* NT only checks count, not val_count */
     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
     if (data) total_size += *count;
@@ -1214,6 +1314,7 @@ DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_cou
 
     /* NT only checks count, not val_count */
     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
     if (data) total_size += *count;
@@ -1313,6 +1414,9 @@ DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_cou
 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR name )
 {
     UNICODE_STRING nameW;
+
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
     RtlInitUnicodeString( &nameW, name );
     return RtlNtStatusToDosError( NtDeleteValueKey( hkey, &nameW ) );
 }
@@ -1326,12 +1430,12 @@ DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR name )
     STRING nameA;
     NTSTATUS status;
 
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
     RtlInitAnsiString( &nameA, name );
     if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
                                                  &nameA, FALSE )))
-    {
         status = NtDeleteValueKey( hkey, &NtCurrentTeb()->StaticUnicodeString );
-    }
     return RtlNtStatusToDosError( status );
 }
 
@@ -1353,6 +1457,7 @@ LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR subkey, LPCWSTR filename )
 
     if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
     if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     len = strlenW( subkey ) * sizeof(WCHAR);
     if (len > MAX_PATH*sizeof(WCHAR)) return ERROR_INVALID_PARAMETER;
@@ -1393,6 +1498,7 @@ LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR subkey, LPCSTR filename )
 
     if (!filename || !*filename) return ERROR_INVALID_PARAMETER;
     if (!subkey || !*subkey) return ERROR_INVALID_PARAMETER;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     if (!(len = MultiByteToWideChar( CP_ACP, 0, subkey, strlen(subkey), buffer, MAX_PATH )))
         return ERROR_INVALID_PARAMETER;
@@ -1439,6 +1545,7 @@ LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa )
     TRACE( "(%x,%s,%p)\n", hkey, debugstr_a(file), sa );
 
     if (!file || !*file) return ERROR_INVALID_PARAMETER;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     err = GetLastError();
     GetFullPathNameA( file, sizeof(buffer), buffer, &name );
diff --git a/dlls/ntdll/cdrom.c b/dlls/ntdll/cdrom.c
index f53a39285edd012bec4802a024fe567134943405..206802c21976f19aec79d4901f3ce65892834f3a 100644
--- a/dlls/ntdll/cdrom.c
+++ b/dlls/ntdll/cdrom.c
@@ -188,7 +188,7 @@ void CDROM_InitRegistry(int dev)
     DWORD disp;
 
     attr.Length = sizeof(attr);
-    attr.RootDirectory = HKEY_LOCAL_MACHINE;
+    attr.RootDirectory = 0;
     attr.ObjectName = &nameW;
     attr.Attributes = 0;
     attr.SecurityDescriptor = NULL;
@@ -198,7 +198,7 @@ void CDROM_InitRegistry(int dev)
         return;
 
     /* Ensure there is Scsi key */
-    if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "HARDWARE\\DEVICEMAP\\Scsi" ) ||
+    if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\HARDWARE\\DEVICEMAP\\Scsi" ) ||
         NtCreateKey( &scsiKey, KEY_ALL_ACCESS, &attr, 0,
                      NULL, REG_OPTION_VOLATILE, &disp ))
     {
diff --git a/dlls/ntdll/reg.c b/dlls/ntdll/reg.c
index fb0a3a325ba228f503d4c897139d292fc4fe8195..940a0aa3e612876103ae5eb34931f442190ce1d9 100644
--- a/dlls/ntdll/reg.c
+++ b/dlls/ntdll/reg.c
@@ -621,7 +621,7 @@ DWORD WINAPI RtlOpenCurrentUser(
 
 	RtlFormatCurrentUserKeyPath(&ObjectName);
 	InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
-	ret = NtOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
+	ret = NtCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, 0, NULL);
 	RtlFreeUnicodeString(&ObjectName);
 	return ret;
 }
diff --git a/misc/registry.c b/misc/registry.c
index 945bf7094526aebea6b1c3bb1eac4d36991a3caa..d7e20639431424555793f5178f5bb4546f8df17e 100644
--- a/misc/registry.c
+++ b/misc/registry.c
@@ -1086,7 +1086,8 @@ static void _save_at_exit(HKEY hkey,LPCSTR path)
 }
 
 /* configure save files and start the periodic saving timer [Internal] */
-static void _init_registry_saving( HKEY hkey_users_default )
+static void _init_registry_saving( HKEY hkey_local_machine, HKEY hkey_current_user,
+                                   HKEY hkey_users_default )
 {
     int all;
     int period = 0;
@@ -1106,8 +1107,8 @@ static void _init_registry_saving( HKEY hkey_users_default )
 
     if (PROFILE_GetWineIniBool(registryW, WritetoHomeRegistryFilesW, 1))
     {
-        _save_at_exit(HKEY_CURRENT_USER,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
-        _save_at_exit(HKEY_LOCAL_MACHINE,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
+        _save_at_exit(hkey_current_user,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER );
+        _save_at_exit(hkey_local_machine,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
         _save_at_exit(hkey_users_default,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT);
     }
 
@@ -1503,7 +1504,8 @@ static void _convert_and_load_native_registry(LPCWSTR fn, HKEY hkey, int reg_typ
 }
 
 /* load all native windows registry files [Internal] */
-static void _load_windows_registry( HKEY hkey_users_default )
+static void _load_windows_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
+                                    HKEY hkey_users_default )
 {
     int reg_type;
     WCHAR windir[MAX_PATHNAME_LEN];
@@ -1515,7 +1517,6 @@ static void _load_windows_registry( HKEY hkey_users_default )
     static const WCHAR WineW[] = {'W','i','n','e',0};
     static const WCHAR ProfileW[] = {'P','r','o','f','i','l','e',0};
     static const WCHAR empty_strW[] = { 0 };
-    static const WCHAR Machine[] = {'M','a','c','h','i','n','e',0};
     static const WCHAR System[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
     static const WCHAR Software[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
     static const WCHAR Clone[] = {'M','a','c','h','i','n','e','\\',
@@ -1545,7 +1546,7 @@ static void _load_windows_registry( HKEY hkey_users_default )
             /* user specific ntuser.dat */
             if (PROFILE_GetWineIniString( WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN )) {
                 strcatW(path, ntuser_datW);
-                _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WINNT,1);
+                _convert_and_load_native_registry(path,hkey_current_user,REG_WINNT,1);
             }
 
             /* default user.dat */
@@ -1576,18 +1577,13 @@ static void _load_windows_registry( HKEY hkey_users_default )
                 NtClose( hkey );
             }
 
-            RtlInitUnicodeString( &nameW, Machine );
-            if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
-            {
-                strcpyW(path, windir);
-                strcatW(path, samW);
-                _convert_and_load_native_registry(path,hkey,REG_WINNT,0);
+            strcpyW(path, windir);
+            strcatW(path, samW);
+            _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
 
-                strcpyW(path,windir);
-                strcatW(path, securityW);
-                _convert_and_load_native_registry(path,hkey,REG_WINNT,0);
-                NtClose( hkey );
-            }
+            strcpyW(path,windir);
+            strcatW(path, securityW);
+            _convert_and_load_native_registry(path,hkey_local_machine,REG_WINNT,0);
 
             /* this key is generated when the nt-core booted successfully */
             RtlInitUnicodeString( &nameW, Clone );
@@ -1602,16 +1598,11 @@ static void _load_windows_registry( HKEY hkey_users_default )
             static const WCHAR classes_datW[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
             static const WCHAR user_datW[] = {'\\','u','s','e','r','.','d','a','t',0};
 
-            RtlInitUnicodeString( &nameW, Machine );
-            if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
-            {
-                _convert_and_load_native_registry(system_1stW,hkey,REG_WIN95,0);
+            _convert_and_load_native_registry(system_1stW,hkey_local_machine,REG_WIN95,0);
 
-                strcpyW(path, windir);
-                strcatW(path, system_datW);
-                _convert_and_load_native_registry(path,hkey,REG_WIN95,0);
-                NtClose( hkey );
-            }
+            strcpyW(path, windir);
+            strcatW(path, system_datW);
+            _convert_and_load_native_registry(path,hkey_local_machine,REG_WIN95,0);
 
             RtlInitUnicodeString( &nameW, ClassesRootW );
             if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
@@ -1625,7 +1616,7 @@ static void _load_windows_registry( HKEY hkey_users_default )
             if (PROFILE_GetWineIniString(WineW, ProfileW, empty_strW, path, MAX_PATHNAME_LEN)) {
 	        /* user specific user.dat */
 	        strcatW(path, user_datW);
-                _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
+                _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
 
 	        /* default user.dat */
 	        if (hkey_users_default) {
@@ -1636,7 +1627,7 @@ static void _load_windows_registry( HKEY hkey_users_default )
             } else {
                 strcpyW(path, windir);
                 strcatW(path, user_datW);
-                _convert_and_load_native_registry(path,HKEY_CURRENT_USER,REG_WIN95,1);
+                _convert_and_load_native_registry(path,hkey_current_user,REG_WIN95,1);
             }
             break;
         }
@@ -1658,19 +1649,20 @@ static void _load_windows_registry( HKEY hkey_users_default )
 }
 
 /* load global registry files (stored in /etc/wine) [Internal] */
-static void _load_global_registry(void)
+static void _load_global_registry( HKEY hkey_local_machine, HKEY hkey_users )
 {
     TRACE("(void)\n");
 
     /* Load the global HKU hive directly from sysconfdir */
-    load_wine_registry( HKEY_USERS, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT );
+    load_wine_registry( hkey_users, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT );
 
     /* Load the global machine defaults directly from sysconfdir */
-    load_wine_registry( HKEY_LOCAL_MACHINE, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE );
+    load_wine_registry( hkey_local_machine, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE );
 }
 
 /* load home registry files (stored in ~/.wine) [Internal] */
-static void _load_home_registry( HKEY hkey_users_default )
+static void _load_home_registry( HKEY hkey_local_machine, HKEY hkey_current_user,
+                                 HKEY hkey_users_default )
 {
     LPCSTR confdir = wine_get_config_dir();
     LPSTR tmp = _xmalloc(strlen(confdir)+20);
@@ -1681,11 +1673,11 @@ static void _load_home_registry( HKEY hkey_users_default )
 
     strcpy(tmp,confdir);
     strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER);
-    load_wine_registry(HKEY_CURRENT_USER,tmp);
+    load_wine_registry(hkey_current_user,tmp);
 
     strcpy(tmp,confdir);
     strcat(tmp,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE);
-    load_wine_registry(HKEY_LOCAL_MACHINE,tmp);
+    load_wine_registry(hkey_local_machine,tmp);
 
     free(tmp);
 }
@@ -1693,11 +1685,13 @@ static void _load_home_registry( HKEY hkey_users_default )
 /* load all registry (native and global and home) */
 void SHELL_LoadRegistry( void )
 {
-    HKEY hkey_users_default;
+    HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user;
     OBJECT_ATTRIBUTES attr;
     UNICODE_STRING nameW;
 
-    static const WCHAR DefaultW[] = {'U','s','e','r','\\','.','D','e','f','a','u','l','t',0};
+    static const WCHAR MachineW[] = {'M','a','c','h','i','n','e',0};
+    static const WCHAR UserW[] = {'U','s','e','r',0};
+    static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t',0};
     static const WCHAR RegistryW[] = {'R','e','g','i','s','t','r','y',0};
     static const WCHAR load_win_reg_filesW[] = {'L','o','a','d','W','i','n','d','o','w','s','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
     static const WCHAR load_global_reg_filesW[] = {'L','o','a','d','G','l','o','b','a','l','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
@@ -1714,22 +1708,32 @@ void SHELL_LoadRegistry( void )
     attr.SecurityDescriptor = NULL;
     attr.SecurityQualityOfService = NULL;
 
+    RtlInitUnicodeString( &nameW, MachineW );
+    NtCreateKey( &hkey_local_machine, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
+    RtlInitUnicodeString( &nameW, UserW );
+    NtCreateKey( &hkey_users, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL );
+
+    attr.RootDirectory = hkey_users;
     RtlInitUnicodeString( &nameW, DefaultW );
     if (NtCreateKey( &hkey_users_default, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ))
     {
         ERR("Cannot create HKEY_USERS/.Default\n" );
         ExitProcess(1);
     }
+    RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey_current_user );
 
     _set_registry_levels(0,0,0);
     _allocate_default_keys();
     if (PROFILE_GetWineIniBool(RegistryW, load_win_reg_filesW, 1))
-        _load_windows_registry( hkey_users_default );
+        _load_windows_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
     if (PROFILE_GetWineIniBool(RegistryW, load_global_reg_filesW, 1))
-        _load_global_registry();
+        _load_global_registry( hkey_local_machine, hkey_users );
     _set_registry_levels(1,0,0);
     if (PROFILE_GetWineIniBool(RegistryW, load_home_reg_filesW, 1))
-        _load_home_registry( hkey_users_default );
-    _init_registry_saving( hkey_users_default );
+        _load_home_registry( hkey_local_machine, hkey_current_user, hkey_users_default );
+    _init_registry_saving( hkey_local_machine, hkey_current_user, hkey_users_default );
     NtClose(hkey_users_default);
+    NtClose(hkey_current_user);
+    NtClose(hkey_users);
+    NtClose(hkey_local_machine);
 }
diff --git a/win32/device.c b/win32/device.c
index 2e11c033c835ec8ed5f8743e3998420053db866d..9fb573c7c44a30067bc9406d551f80ca7526e737 100644
--- a/win32/device.c
+++ b/win32/device.c
@@ -570,12 +570,95 @@ void VxDCall( DWORD service, CONTEXT86 *context )
  */
 
 
+#define HKEY_SPECIAL_ROOT_FIRST   HKEY_CLASSES_ROOT
+#define HKEY_SPECIAL_ROOT_LAST    HKEY_DYN_DATA
+#define NB_SPECIAL_ROOT_KEYS      ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
+
+static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
+
+static const WCHAR name_CLASSES_ROOT[] =
+    {'M','a','c','h','i','n','e','\\',
+     'S','o','f','t','w','a','r','e','\\',
+     'C','l','a','s','s','e','s',0};
+static const WCHAR name_LOCAL_MACHINE[] =
+    {'M','a','c','h','i','n','e',0};
+static const WCHAR name_USERS[] =
+    {'U','s','e','r',0};
+static const WCHAR name_PERFORMANCE_DATA[] =
+    {'P','e','r','f','D','a','t','a',0};
+static const WCHAR name_CURRENT_CONFIG[] =
+    {'M','a','c','h','i','n','e','\\',
+     'S','y','s','t','e','m','\\',
+     'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
+     'H','a','r','d','w','a','r','e','P','r','o','f','i','l','e','s','\\',
+     'C','u','r','r','e','n','t',0};
+static const WCHAR name_DYN_DATA[] =
+    {'D','y','n','D','a','t','a',0};
+
+#define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
+static UNICODE_STRING root_key_names[NB_SPECIAL_ROOT_KEYS] =
+{
+    DECL_STR(CLASSES_ROOT),
+    { 0, 0, NULL },         /* HKEY_CURRENT_USER is determined dynamically */
+    DECL_STR(LOCAL_MACHINE),
+    DECL_STR(USERS),
+    DECL_STR(PERFORMANCE_DATA),
+    DECL_STR(CURRENT_CONFIG),
+    DECL_STR(DYN_DATA)
+};
+#undef DECL_STR
+
+
 /* check if value type needs string conversion (Ansi<->Unicode) */
 inline static int is_string( DWORD type )
 {
     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
 }
 
+/* create one of the HKEY_* special root keys */
+static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
+{
+    HKEY ret = 0;
+    int idx = (UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST;
+
+    if (hkey == HKEY_CURRENT_USER)
+    {
+        if (RtlOpenCurrentUser( access, &hkey )) return 0;
+    }
+    else
+    {
+        OBJECT_ATTRIBUTES attr;
+
+        attr.Length = sizeof(attr);
+        attr.RootDirectory = 0;
+        attr.ObjectName = &root_key_names[idx];
+        attr.Attributes = 0;
+        attr.SecurityDescriptor = NULL;
+        attr.SecurityQualityOfService = NULL;
+        if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
+    }
+
+    if (!(ret = InterlockedCompareExchange( (PLONG)&special_root_keys[idx], hkey, 0 )))
+        ret = hkey;
+    else
+        NtClose( hkey );  /* somebody beat us to it */
+    return ret;
+}
+
+/* map the hkey from special root to normal key if necessary */
+inline static HKEY get_special_root_hkey( HKEY hkey )
+{
+    HKEY ret = hkey;
+
+    if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
+    {
+        if (!(ret = special_root_keys[(UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST]))
+            ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
+    }
+    return ret;
+}
+
+
 /******************************************************************************
  *           VMM_RegCreateKeyA
  */
@@ -586,6 +669,8 @@ static DWORD VMM_RegCreateKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey )
     ANSI_STRING nameA;
     NTSTATUS status;
 
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
     attr.Length = sizeof(attr);
     attr.RootDirectory = hkey;
     attr.ObjectName = &nameW;
@@ -614,6 +699,8 @@ DWORD WINAPI VMM_RegOpenKeyExA(HKEY hkey, LPCSTR name, DWORD reserved, REGSAM ac
     STRING nameA;
     NTSTATUS status;
 
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
     attr.Length = sizeof(attr);
     attr.RootDirectory = hkey;
     attr.ObjectName = &nameW;
@@ -649,7 +736,9 @@ static DWORD VMM_RegDeleteKeyA( HKEY hkey, LPCSTR name )
     DWORD ret;
     HKEY tmp;
 
-    if (!name || !*name) return NtDeleteKey( hkey );
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
+    if (!name || !*name) return RtlNtStatusToDosError( NtDeleteKey( hkey ) );
     if (!(ret = VMM_RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
     {
         ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
@@ -670,6 +759,8 @@ static DWORD VMM_RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD t
     WCHAR *dataW = NULL;
     NTSTATUS status;
 
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
     if (is_string(type))
     {
         DWORD lenW;
@@ -726,6 +817,8 @@ static DWORD VMM_RegDeleteValueA( HKEY hkey, LPCSTR name )
     STRING nameA;
     NTSTATUS status;
 
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
     RtlInitAnsiString( &nameA, name );
     if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
     {
@@ -751,6 +844,7 @@ static DWORD VMM_RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPD
     static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );
 
     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     RtlInitAnsiString( &nameA, name );
     if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
@@ -862,6 +956,7 @@ static DWORD VMM_RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val
 
     /* NT only checks count, not val_count */
     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
     if (data) total_size += *count;
@@ -957,6 +1052,8 @@ static DWORD VMM_RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len
     KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
     DWORD total_size;
 
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
                              buffer, sizeof(buffer), &total_size );
 
@@ -1003,6 +1100,8 @@ static DWORD VMM_RegQueryInfoKeyA( HKEY hkey, LPDWORD subkeys, LPDWORD max_subke
     KEY_FULL_INFORMATION info;
     DWORD total_size;
 
+    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
     status = NtQueryKey( hkey, KeyFullInformation, &info, sizeof(info), &total_size );
     if (status && status != STATUS_BUFFER_OVERFLOW) return RtlNtStatusToDosError( status );