[PATCH 1/2] advapi32: HKCR merge: foundation

George Stephanos gaf.stephanos at gmail.com
Mon Sep 16 09:05:22 CDT 2013


---
 dlls/advapi32/registry.c       | 250 ++++++++++++++++++++++++++++++++++++++++-
 dlls/advapi32/tests/registry.c |   6 +-
 2 files changed, 252 insertions(+), 4 deletions(-)

diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c
index c01e125..ab16a12 100644
--- a/dlls/advapi32/registry.c
+++ b/dlls/advapi32/registry.c
@@ -79,6 +79,30 @@ static const WCHAR * const root_key_names[] =
 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
 static BOOL hkcu_cache_disabled;
 
+typedef struct {
+    HKEY  hklm;
+} opened_hkcr_t;
+
+/* ############################### */
+
+static CRITICAL_SECTION hkcr_handles_cs;
+static CRITICAL_SECTION_DEBUG hkcr_handles_cs_debug =
+{
+    0, 0, &hkcr_handles_cs,
+    { &hkcr_handles_cs_debug.ProcessLocksList, &hkcr_handles_cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": hkcr_handles_cs") }
+};
+static CRITICAL_SECTION hkcr_handles_cs = { &hkcr_handles_cs_debug, -1, 0, 0, 0, 0 };
+
+/* ############################### */
+
+static opened_hkcr_t **hkcr_handles;
+static UINT nb_hkcr_handles;
+
+#define SPECIAL_HKEY_MASK 0x80000003
+#define HKCR_FLAG 2
+#define IS_HKCR(hk) (((UINT_PTR)(hk) & SPECIAL_HKEY_MASK) == HKCR_FLAG)
+
 static const int is_win64 = (sizeof(void *) > sizeof(int));
 
 /* check if value type needs string conversion (Ansi<->Unicode) */
@@ -224,13 +248,138 @@ static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *a
 
 }
 
+static LSTATUS create_hkcr_struct( HKEY *hkey, opened_hkcr_t **hkcr )
+{
+    UINT_PTR handle = nb_hkcr_handles, i;
+    LSTATUS ret = ERROR_SUCCESS;
+
+    EnterCriticalSection( &hkcr_handles_cs );
+
+    for (i = 0; i < nb_hkcr_handles; i++)
+    {
+        if (!hkcr_handles[i])
+        {
+            handle = i;
+            break;
+        }
+    }
+
+    if (handle >= nb_hkcr_handles)
+    {
+        opened_hkcr_t **new_array;
+        if (hkcr_handles)
+            new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, hkcr_handles,
+                                     (nb_hkcr_handles * 2) * sizeof(*new_array) );
+        else
+            new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                   16 * sizeof(*new_array) );
+
+        if (!new_array)
+        {
+            ret = ERROR_NOT_ENOUGH_MEMORY;
+            goto end;
+        }
+        hkcr_handles = new_array;
+
+        nb_hkcr_handles = !nb_hkcr_handles ? 16 : nb_hkcr_handles * 2;
+    }
+
+    *hkcr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(opened_hkcr_t) );
+
+    if (*hkcr)
+    {
+        hkcr_handles[handle] = *hkcr;
+        *hkey = (HKEY)( handle << 2 | HKCR_FLAG );
+    }
+    else ret = ERROR_NOT_ENOUGH_MEMORY;
+
+end:
+    LeaveCriticalSection( &hkcr_handles_cs );
+    return ret;
+}
+
+static HKEY resolve_hkcr( HKEY hkey )
+{
+    HKEY ret;
+    UINT_PTR idx = (UINT_PTR)hkey >> 2;
+    opened_hkcr_t *hkcr;
+    if (idx <= nb_hkcr_handles)
+    {
+        EnterCriticalSection( &hkcr_handles_cs );
+        hkcr = hkcr_handles[idx];
+
+        if (!hkcr)
+        {
+            LeaveCriticalSection( &hkcr_handles_cs );
+            return NULL;
+        }
+
+        ret = hkcr->hklm;
+
+        LeaveCriticalSection( &hkcr_handles_cs );
+        return ret;
+    }
+    return NULL;
+}
+
+static LSTATUS WINAPI create_hkcr( HKEY hkey, CONST WCHAR *name, WCHAR *class,
+                                   DWORD options, REGSAM samDesired,
+                                   SECURITY_ATTRIBUTES *sa, HKEY *retkey, DWORD *dispos )
+{
+    HKEY hklm;
+    opened_hkcr_t *hkcr = NULL;
+    LSTATUS res;
+    *retkey = 0;
+
+    if (hkey != HKEY_LOCAL_MACHINE) hkey = resolve_hkcr( hkey );
+    res = RegCreateKeyExW( hkey, name, 0, class, options, samDesired, sa, &hklm, dispos );
+    if (res) return res;
+
+    if ((res = create_hkcr_struct(retkey, &hkcr)))
+    {
+        RegCloseKey( hklm );
+        return res;
+    }
+
+    hkcr->hklm = hklm;
+
+    return res;
+}
+
+static LSTATUS WINAPI open_hkcr( HKEY hkey, CONST WCHAR *name, REGSAM samDesired, HKEY *retkey )
+{
+    HKEY hklm;
+    opened_hkcr_t *hkcr = NULL;
+    LSTATUS res;
+    *retkey = 0;
+
+    hkey = resolve_hkcr( hkey );
+    res = RegOpenKeyExW( hkey, name, 0, samDesired, &hklm );
+    if (res) return res;
+
+    if ((res = create_hkcr_struct(retkey, &hkcr)))
+    {
+        RegCloseKey( hklm );
+        return res;
+    }
+
+    hkcr->hklm = hklm;
+
+    return res;
+}
+
+
 /* create one of the HKEY_* special root keys */
 static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
 {
     HKEY ret = 0;
     int idx = HandleToUlong(hkey) - HandleToUlong(HKEY_SPECIAL_ROOT_FIRST);
 
-    if (HandleToUlong(hkey) == HandleToUlong(HKEY_CURRENT_USER))
+    if (HandleToUlong(hkey) == HandleToUlong(HKEY_CLASSES_ROOT))
+    {
+        if (create_hkcr( HKEY_LOCAL_MACHINE, name_CLASSES_ROOT + 8, NULL, 0, access, NULL, &hkey, NULL )) return 0;
+    }
+    else if (HandleToUlong(hkey) == HandleToUlong(HKEY_CURRENT_USER))
     {
         if (RtlOpenCurrentUser( access, (HANDLE *)&hkey )) return 0;
         TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
@@ -258,7 +407,7 @@ static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
     if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
         ret = hkey;
     else
-        NtClose( hkey );  /* somebody beat us to it */
+        RegCloseKey( hkey );
     return ret;
 }
 
@@ -276,6 +425,33 @@ static inline HKEY get_special_root_hkey( HKEY hkey )
     return ret;
 }
 
+static LSTATUS close_hkcr( HKEY hkey )
+{
+    UINT_PTR idx = (UINT_PTR)hkey >> 2;
+    opened_hkcr_t *hkcr;
+
+    if (idx <= nb_hkcr_handles)
+    {
+        EnterCriticalSection( &hkcr_handles_cs );
+
+        hkcr = hkcr_handles[idx];
+        if (!hkcr)
+        {
+            LeaveCriticalSection( &hkcr_handles_cs );
+            return ERROR_INVALID_HANDLE;
+        }
+
+        RegCloseKey(hkcr->hklm);
+
+        HeapFree( GetProcessHeap(), 0, hkcr );
+        hkcr_handles[idx] = 0;
+
+        LeaveCriticalSection( &hkcr_handles_cs );
+        return ERROR_SUCCESS;
+    }
+    return ERROR_INVALID_HANDLE;
+}
+
 
 /******************************************************************************
  * RegOverridePredefKey   [ADVAPI32.@]
@@ -320,6 +496,7 @@ LSTATUS WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR
 
     if (reserved) return ERROR_INVALID_PARAMETER;
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+    if (IS_HKCR(hkey)) return create_hkcr( hkey, name, class, options, access, sa, retkey, dispos );
 
     attr.Length = sizeof(attr);
     attr.RootDirectory = hkey;
@@ -375,6 +552,20 @@ LSTATUS WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR cl
     }
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey))
+    {
+        MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, name, -1,
+                             NtCurrentTeb()->StaticUnicodeBuffer,
+                             sizeof(NtCurrentTeb()->StaticUnicodeBuffer)/sizeof(WCHAR) );
+        RtlInitAnsiString( &classA, class );
+        if (!(status = RtlAnsiStringToUnicodeString( &classW, &classA, TRUE )))
+        {
+            status = create_hkcr( hkey, NtCurrentTeb()->StaticUnicodeBuffer, classW.Buffer, options, access, sa, retkey, dispos );
+            RtlFreeUnicodeString( &classW );
+        }
+        return status;
+    }
+
     attr.Length = sizeof(attr);
     attr.RootDirectory = hkey;
     attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
@@ -450,6 +641,8 @@ LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM acc
     if (!retkey) return ERROR_INVALID_PARAMETER;
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey)) return open_hkcr( hkey, name, access, retkey );
+
     attr.Length = sizeof(attr);
     attr.RootDirectory = hkey;
     attr.ObjectName = &nameW;
@@ -497,6 +690,14 @@ LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM acce
 
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey))
+    {
+        MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, name, -1,
+                             NtCurrentTeb()->StaticUnicodeBuffer,
+                             sizeof(NtCurrentTeb()->StaticUnicodeBuffer)/sizeof(WCHAR) );
+        return open_hkcr( hkey, NtCurrentTeb()->StaticUnicodeBuffer, access, retkey );
+    }
+
     attr.Length = sizeof(attr);
     attr.RootDirectory = hkey;
     attr.ObjectName = &NtCurrentTeb()->StaticUnicodeString;
@@ -623,6 +824,8 @@ LSTATUS WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_
     if (reserved) return ERROR_INVALID_PARAMETER;
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
                              buffer, sizeof(buffer), &total_size );
 
@@ -687,6 +890,8 @@ LSTATUS WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_l
     if (reserved) return ERROR_INVALID_PARAMETER;
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
     status = NtEnumerateKey( hkey, index, KeyNodeInformation,
                              buffer, sizeof(buffer), &total_size );
 
@@ -814,6 +1019,8 @@ LSTATUS WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPD
     if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
 
@@ -1000,6 +1207,8 @@ LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDW
     if (class && !class_len && is_version_nt()) return ERROR_INVALID_PARAMETER;
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
     status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size );
     if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
 
@@ -1062,6 +1271,7 @@ LSTATUS WINAPI RegCloseKey( HKEY hkey )
 {
     if (!hkey) return ERROR_INVALID_HANDLE;
     if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
+    if (IS_HKCR(hkey)) return close_hkcr( hkey );
     return RtlNtStatusToDosError( NtClose( hkey ) );
 }
 
@@ -1078,6 +1288,16 @@ LSTATUS WINAPI RegDeleteKeyExW( HKEY hkey, LPCWSTR name, REGSAM access, DWORD re
 
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey))
+    {
+        if (!(ret = open_hkcr( hkey, name, access | DELETE, &tmp )))
+        {
+            ret = RtlNtStatusToDosError( NtDeleteKey( resolve_hkcr(tmp) ) );
+            close_hkcr( tmp );
+        }
+        return ret;
+    }
+
     access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
     if (!(ret = RegOpenKeyExW( hkey, name, 0, access | DELETE, &tmp )))
     {
@@ -1112,6 +1332,19 @@ LSTATUS WINAPI RegDeleteKeyExA( HKEY hkey, LPCSTR name, REGSAM access, DWORD res
 
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey))
+    {
+        MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, name, -1,
+                             NtCurrentTeb()->StaticUnicodeBuffer,
+                             sizeof(NtCurrentTeb()->StaticUnicodeBuffer)/sizeof(WCHAR) );
+        if (!(ret = open_hkcr( hkey, NtCurrentTeb()->StaticUnicodeBuffer, access | DELETE, &tmp )))
+        {
+            ret = RtlNtStatusToDosError( NtDeleteKey( resolve_hkcr(tmp) ) );
+            close_hkcr( tmp );
+        }
+        return ret;
+    }
+
     access &= KEY_WOW64_64KEY | KEY_WOW64_32KEY;
     if (!(ret = RegOpenKeyExA( hkey, name, 0, access | DELETE, &tmp )))
     {
@@ -1193,6 +1426,8 @@ LSTATUS WINAPI RegSetValueExW( HKEY hkey, LPCWSTR name, DWORD reserved,
     }
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
     RtlInitUnicodeString( &nameW, name );
     return RtlNtStatusToDosError( NtSetValueKey( hkey, &nameW, 0, type, data, count ) );
 }
@@ -1231,6 +1466,8 @@ LSTATUS WINAPI RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD typ
 
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
     if (is_string( type )) /* need to convert to Unicode */
     {
         DWORD lenW;
@@ -1336,6 +1573,8 @@ LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDW
     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
     RtlInitUnicodeString( &name_str, name );
 
     if (data) total_size = min( sizeof(buffer), *count + info_size );
@@ -1426,6 +1665,8 @@ LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWO
     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
     if (count) datalen = *count;
     if (!data && count) *count = 0;
 
@@ -1864,6 +2105,8 @@ LSTATUS WINAPI RegEnumValueW( HKEY hkey, DWORD index, LPWSTR value, LPDWORD val_
     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
     if (data) total_size += *count;
     total_size = min( sizeof(buffer), total_size );
@@ -1949,6 +2192,8 @@ LSTATUS WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_c
     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
     if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
 
+    if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
+
     total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
     if (data) total_size += *count;
     total_size = min( sizeof(buffer), total_size );
@@ -2468,6 +2713,7 @@ LSTATUS WINAPI RegGetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInform
 LSTATUS WINAPI RegFlushKey( HKEY hkey )
 {
     hkey = get_special_root_hkey( hkey );
+    if (IS_HKCR(hkey) && !(hkey = resolve_hkcr( hkey ))) return ERROR_INVALID_HANDLE;
     if (!hkey) return ERROR_INVALID_HANDLE;
 
     return RtlNtStatusToDosError( NtFlushKey( hkey ) );
diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c
index 981ac93..027728a 100644
--- a/dlls/advapi32/tests/registry.c
+++ b/dlls/advapi32/tests/registry.c
@@ -31,7 +31,9 @@
 #include "winerror.h"
 #include "aclapi.h"
 
-#define IS_HKCR(hk) ((UINT_PTR)hk > 0 && ((UINT_PTR)hk & 3) == 2)
+#define SPECIAL_HKEY_MASK 0x80000003
+#define HKCR_FLAG 2
+#define IS_HKCR(hk) (((UINT_PTR)(hk) & SPECIAL_HKEY_MASK) == HKCR_FLAG)
 
 static HKEY hkey_main;
 static DWORD GLE;
@@ -2584,7 +2586,7 @@ static void test_classesroot_mask(void)
 
     res = RegOpenKeyA( HKEY_CLASSES_ROOT, "CLSID", &hkey );
     ok(res == ERROR_SUCCESS, "RegOpenKeyA failed: %d\n", res);
-    todo_wine ok(IS_HKCR(hkey) || broken(!IS_HKCR(hkey)) /* WinNT */,
+    ok(IS_HKCR(hkey) || broken(!IS_HKCR(hkey)) /* WinNT */,
                  "hkcr mask not set in %p\n", hkey);
     RegCloseKey( hkey );
 
-- 
1.8.2.3




More information about the wine-patches mailing list