RFC: HKCR merge implementation

George Stephanos gaf.stephanos at gmail.com
Tue Sep 10 15:00:04 CDT 2013


I'm proposing my HKEY_CLASSES_ROOT implementation patches for review. Feel
free to comment.
So far, I've written code for all functions except for the RegEnum family.

General description:

HKCR handles are special. All wine handles have the two lowest bits zero'd.
HKCR handles are masked. 10b specifically.
They have their own table separate from the generic handle table.
An HKCR handle has an HKCU handle and an HKLM handle below it. Access mask
and a string representing the path are also needed
since the handle has to attempt to reopen previously failed openings at
certain stages.

First patch: specially handles HKCR handles WITHOUT affecting the general
behavior. The end result is still the exact same. Patch provides a
foundation for the rest.
Second patch: added path management
Third patch: added HKCU

Here's a quick description of each function:

create_hkcr_struct: allocates the memory needed for the struct, adds it to
the table and gives back a pointer to it
get_hkcr_path: given an HKCR handle and a subkey string, prepares a subkey
string representing the same subkey rooted at HKLM/HKCU.
create_hkcr: RegCreateKeyEx
open_hkcr: RegOpenKeyEx
resolve_hkcr: checks the HKCR handle, tries to reopen previously failed
internal handles, gives back HKCU first if available then HKLM
close_hkcr: deallocates path and struct, removes struct from table.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20130910/dc4b5c44/attachment-0001.html>
-------------- next part --------------
From 09e5a3c2629ddcc795a69f70b0672f393abd96ed Mon Sep 17 00:00:00 2001
From: George Stephanos <gaf.stephanos at gmail.com>
Date: Sat, 24 Aug 2013 20:30:05 +0200
Subject: [PATCH 1/3] advapi32: HKCR merge: foundation

---
 dlls/advapi32/registry.c       | 249 ++++++++++++++++++++++++++++++++++++++++-
 dlls/advapi32/tests/registry.c |   2 +-
 2 files changed, 248 insertions(+), 3 deletions(-)

diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c
index c01e125..5768272 100644
--- a/dlls/advapi32/registry.c
+++ b/dlls/advapi32/registry.c
@@ -79,6 +79,29 @@ 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 HKCR_MASK 2
+#define IS_HKCR(hk) ((UINT_PTR)hk > 0 && ((UINT_PTR)hk & 3) == HKCR_MASK)
+
 static const int is_win64 = (sizeof(void *) > sizeof(int));
 
 /* check if value type needs string conversion (Ansi<->Unicode) */
@@ -224,13 +247,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_MASK );
+    }
+    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 +406,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 +424,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 +495,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 +551,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 +640,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 +689,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 +823,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 +889,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 +1018,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 +1206,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 +1270,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 +1287,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 +1331,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 +1425,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 +1465,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 +1572,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 +1664,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 +2104,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 +2191,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 +2712,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..d94757f 100644
--- a/dlls/advapi32/tests/registry.c
+++ b/dlls/advapi32/tests/registry.c
@@ -2584,7 +2584,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
-------------- next part --------------
From 065b3e658cfcbea4ebb76ca49949620e71fdf3dc Mon Sep 17 00:00:00 2001
From: George Stephanos <gaf.stephanos at gmail.com>
Date: Sun, 25 Aug 2013 01:36:30 +0200
Subject: [PATCH 2/3] advapi32: HKCR merge: added path management

---
 dlls/advapi32/registry.c | 70 +++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 64 insertions(+), 6 deletions(-)

diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c
index 5768272..385d98c 100644
--- a/dlls/advapi32/registry.c
+++ b/dlls/advapi32/registry.c
@@ -81,6 +81,8 @@ static BOOL hkcu_cache_disabled;
 
 typedef struct {
     HKEY  hklm;
+    DWORD samDesired;
+    WCHAR *path;
 } opened_hkcr_t;
 
 /* ############################### */
@@ -313,6 +315,7 @@ static HKEY resolve_hkcr( HKEY hkey )
             return NULL;
         }
 
+        if (!hkcr->hklm) RegOpenKeyExW( HKEY_LOCAL_MACHINE, hkcr->path, 0, hkcr->samDesired, &hkcr->hklm );
         ret = hkcr->hklm;
 
         LeaveCriticalSection( &hkcr_handles_cs );
@@ -321,6 +324,53 @@ static HKEY resolve_hkcr( HKEY hkey )
     return NULL;
 }
 
+static LSTATUS get_hkcr_path( HKEY hkey, CONST WCHAR *path, WCHAR **buf )
+{
+    const static WCHAR root[] = {'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
+    opened_hkcr_t *hkcr = NULL;
+    UINT_PTR idx = ((UINT_PTR)(hkey) & ~HKCR_MASK)/4;
+    int len;
+
+    if (hkey) /* HKCR handle supplied */
+    {
+        EnterCriticalSection( &hkcr_handles_cs );
+
+        if (idx > nb_hkcr_handles || !hkcr_handles[idx])
+        {
+            LeaveCriticalSection( &hkcr_handles_cs );
+            return ERROR_INVALID_HANDLE;
+        }
+
+        hkcr = hkcr_handles[idx];
+
+        LeaveCriticalSection( &hkcr_handles_cs );
+
+        /* construct path */
+        hkcr = hkcr_handles[idx];
+        len = lstrlenW(hkcr->path);
+        *buf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, (len+lstrlenW(path)+2)*sizeof(WCHAR) );
+        if (!*buf) return ERROR_NOT_ENOUGH_MEMORY;
+        lstrcpyW( *buf, hkcr->path );
+        (*buf)[len] = '\\';
+        lstrcpyW( *buf+len+1, path+(*path=='\\') );
+    }
+    else if (path) /* HKEY_CLASSES_ROOT is root for path */
+    {
+        *buf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(root)+(lstrlenW(path)+2)*sizeof(WCHAR) );
+        if (!*buf) return ERROR_NOT_ENOUGH_MEMORY;
+        lstrcpyW( *buf, root );
+        (*buf)[sizeof(root)]='\\';
+        lstrcpyW( *buf+sizeof(root)+1, path+(*path=='\\') );
+    }
+    else /* open HKEY_CLASSES_ROOT */
+    {
+        *buf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(root) );
+        if (!*buf) return ERROR_NOT_ENOUGH_MEMORY;
+        lstrcpyW( *buf, root );
+    }
+    return ERROR_SUCCESS;
+}
+
 static LSTATUS WINAPI create_hkcr( HKEY hkey, CONST WCHAR *name, WCHAR *class,
                                    DWORD options, REGSAM samDesired,
                                    SECURITY_ATTRIBUTES *sa, HKEY *retkey, DWORD *dispos )
@@ -328,10 +378,12 @@ static LSTATUS WINAPI create_hkcr( HKEY hkey, CONST WCHAR *name, WCHAR *class,
     HKEY hklm;
     opened_hkcr_t *hkcr = NULL;
     LSTATUS res;
+    WCHAR *buf = NULL;
     *retkey = 0;
 
-    if (hkey != HKEY_LOCAL_MACHINE) hkey = resolve_hkcr( hkey );
-    res = RegCreateKeyExW( hkey, name, 0, class, options, samDesired, sa, &hklm, dispos );
+    if ((res = get_hkcr_path( hkey, name, &buf ))) return res;
+
+    res = RegCreateKeyExW( HKEY_LOCAL_MACHINE, buf, 0, class, options, samDesired, sa, &hklm, dispos );
     if (res) return res;
 
     if ((res = create_hkcr_struct(retkey, &hkcr)))
@@ -341,6 +393,8 @@ static LSTATUS WINAPI create_hkcr( HKEY hkey, CONST WCHAR *name, WCHAR *class,
     }
 
     hkcr->hklm = hklm;
+    hkcr->path = buf;
+    hkcr->samDesired = samDesired;
 
     return res;
 }
@@ -350,10 +404,12 @@ static LSTATUS WINAPI open_hkcr( HKEY hkey, CONST WCHAR *name, REGSAM samDesired
     HKEY hklm;
     opened_hkcr_t *hkcr = NULL;
     LSTATUS res;
+    WCHAR *buf = NULL;
     *retkey = 0;
 
-    hkey = resolve_hkcr( hkey );
-    res = RegOpenKeyExW( hkey, name, 0, samDesired, &hklm );
+    if ((res = get_hkcr_path( hkey, name, &buf ))) return res;
+
+    res = RegOpenKeyExW( HKEY_LOCAL_MACHINE, buf, 0, samDesired, &hklm );
     if (res) return res;
 
     if ((res = create_hkcr_struct(retkey, &hkcr)))
@@ -363,6 +419,8 @@ static LSTATUS WINAPI open_hkcr( HKEY hkey, CONST WCHAR *name, REGSAM samDesired
     }
 
     hkcr->hklm = hklm;
+    hkcr->path = buf;
+    hkcr->samDesired = samDesired;
 
     return res;
 }
@@ -376,7 +434,7 @@ static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
 
     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;
+        if (create_hkcr( NULL, NULL, NULL, 0, access, NULL, &hkey, NULL )) return 0;
     }
     else if (HandleToUlong(hkey) == HandleToUlong(HKEY_CURRENT_USER))
     {
@@ -441,7 +499,7 @@ static LSTATUS close_hkcr( HKEY hkey )
         }
 
         RegCloseKey(hkcr->hklm);
-
+        HeapFree( GetProcessHeap(), 0, hkcr->path );
         HeapFree( GetProcessHeap(), 0, hkcr );
         hkcr_handles[idx] = 0;
 
-- 
1.8.2.3
-------------- next part --------------
From ec978c49ebf347987abc76ed2a775dfc9fa88d03 Mon Sep 17 00:00:00 2001
From: George Stephanos <gaf.stephanos at gmail.com>
Date: Sun, 25 Aug 2013 01:42:46 +0200
Subject: [PATCH 3/3] advapi32: HKCR merge: added hkcu

---
 dlls/advapi32/registry.c       | 22 +++++++++++++++++-----
 dlls/advapi32/tests/registry.c | 20 +++++++++-----------
 2 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c
index 385d98c..5cabe5b 100644
--- a/dlls/advapi32/registry.c
+++ b/dlls/advapi32/registry.c
@@ -80,6 +80,7 @@ static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
 static BOOL hkcu_cache_disabled;
 
 typedef struct {
+    HKEY  hkcu;
     HKEY  hklm;
     DWORD samDesired;
     WCHAR *path;
@@ -315,8 +316,10 @@ static HKEY resolve_hkcr( HKEY hkey )
             return NULL;
         }
 
+        if (!hkcr->hkcu) RegOpenKeyExW( HKEY_CURRENT_USER , hkcr->path, 0, hkcr->samDesired, &hkcr->hkcu );
         if (!hkcr->hklm) RegOpenKeyExW( HKEY_LOCAL_MACHINE, hkcr->path, 0, hkcr->samDesired, &hkcr->hklm );
-        ret = hkcr->hklm;
+
+        ret = hkcr->hkcu ? hkcr->hkcu : hkcr->hklm;
 
         LeaveCriticalSection( &hkcr_handles_cs );
         return ret;
@@ -375,7 +378,7 @@ 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;
+    HKEY hkcu, hklm;
     opened_hkcr_t *hkcr = NULL;
     LSTATUS res;
     WCHAR *buf = NULL;
@@ -383,15 +386,19 @@ static LSTATUS WINAPI create_hkcr( HKEY hkey, CONST WCHAR *name, WCHAR *class,
 
     if ((res = get_hkcr_path( hkey, name, &buf ))) return res;
 
-    res = RegCreateKeyExW( HKEY_LOCAL_MACHINE, buf, 0, class, options, samDesired, sa, &hklm, dispos );
+    res = RegOpenKeyExW( HKEY_CURRENT_USER, buf, 0, samDesired, &hkcu );
+    if (res == ERROR_SUCCESS) RegOpenKeyExW( HKEY_LOCAL_MACHINE, buf, 0, samDesired, &hklm );
+    else res = RegCreateKeyExW( HKEY_LOCAL_MACHINE, buf, 0, class, options, samDesired, sa, &hklm, dispos );
     if (res) return res;
 
     if ((res = create_hkcr_struct(retkey, &hkcr)))
     {
+        RegCloseKey( hkcu );
         RegCloseKey( hklm );
         return res;
     }
 
+    hkcr->hkcu = hkcu;
     hkcr->hklm = hklm;
     hkcr->path = buf;
     hkcr->samDesired = samDesired;
@@ -401,7 +408,7 @@ static LSTATUS WINAPI create_hkcr( HKEY hkey, CONST WCHAR *name, WCHAR *class,
 
 static LSTATUS WINAPI open_hkcr( HKEY hkey, CONST WCHAR *name, REGSAM samDesired, HKEY *retkey )
 {
-    HKEY hklm;
+    HKEY hkcu, hklm;
     opened_hkcr_t *hkcr = NULL;
     LSTATUS res;
     WCHAR *buf = NULL;
@@ -409,15 +416,19 @@ static LSTATUS WINAPI open_hkcr( HKEY hkey, CONST WCHAR *name, REGSAM samDesired
 
     if ((res = get_hkcr_path( hkey, name, &buf ))) return res;
 
-    res = RegOpenKeyExW( HKEY_LOCAL_MACHINE, buf, 0, samDesired, &hklm );
+    res = RegOpenKeyExW( HKEY_CURRENT_USER, buf, 0, samDesired, &hkcu );
+    if (res == ERROR_SUCCESS) RegOpenKeyExW( HKEY_LOCAL_MACHINE, buf, 0, samDesired, &hklm );
+    else res = RegOpenKeyExW( HKEY_LOCAL_MACHINE, buf, 0, samDesired, &hklm );
     if (res) return res;
 
     if ((res = create_hkcr_struct(retkey, &hkcr)))
     {
+        RegCloseKey( hkcu );
         RegCloseKey( hklm );
         return res;
     }
 
+    hkcr->hkcu = hkcu;
     hkcr->hklm = hklm;
     hkcr->path = buf;
     hkcr->samDesired = samDesired;
@@ -498,6 +509,7 @@ static LSTATUS close_hkcr( HKEY hkey )
             return ERROR_INVALID_HANDLE;
         }
 
+        RegCloseKey(hkcr->hkcu);
         RegCloseKey(hkcr->hklm);
         HeapFree( GetProcessHeap(), 0, hkcr->path );
         HeapFree( GetProcessHeap(), 0, hkcr );
diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c
index d94757f..b119005 100644
--- a/dlls/advapi32/tests/registry.c
+++ b/dlls/advapi32/tests/registry.c
@@ -2127,9 +2127,8 @@ static void test_classesroot(void)
     /* try to open that key in hkcr */
     res = RegOpenKeyExA( HKEY_CLASSES_ROOT, "WineTestCls", 0,
                          KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
-    todo_wine ok(res == ERROR_SUCCESS ||
-                 broken(res == ERROR_FILE_NOT_FOUND /* WinNT */),
-                 "test key not found in hkcr: %d\n", res);
+    ok(res == ERROR_SUCCESS || broken(res == ERROR_FILE_NOT_FOUND /* WinNT */),
+       "test key not found in hkcr: %d\n", res);
     if (res)
     {
         skip("HKCR key merging not supported\n");
@@ -2138,7 +2137,7 @@ static void test_classesroot(void)
         return;
     }
 
-    todo_wine ok(IS_HKCR(hkcr), "hkcr mask not set in %p\n", hkcr);
+    ok(IS_HKCR(hkcr), "hkcr mask not set in %p\n", hkcr);
 
     /* set a value in user's classes */
     res = RegSetValueExA(hkey, "val1", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
@@ -2423,9 +2422,8 @@ static void test_classesroot_enum(void)
     }
 
     res = RegOpenKeyA( HKEY_CLASSES_ROOT, "WineTestCls", &hkcr );
-    todo_wine ok(res == ERROR_SUCCESS ||
-                 broken(res == ERROR_FILE_NOT_FOUND /* WinNT */),
-                 "test key not found in hkcr: %d\n", res);
+    ok(res == ERROR_SUCCESS || broken(res == ERROR_FILE_NOT_FOUND /* WinNT */),
+       "test key not found in hkcr: %d\n", res);
     if (res)
     {
         skip("HKCR key merging not supported\n");
@@ -2506,8 +2504,8 @@ static void test_classesroot_enum(void)
     ok(!strcmp( buffer, "Y" ), "expected 'Y', got '%s'\n", buffer);
     size = sizeof(buffer);
     res = RegEnumValueA( hkcr, 2, buffer, &size, NULL, NULL, NULL, NULL );
-    ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
-    ok(!strcmp( buffer, "Z" ), "expected 'Z', got '%s'\n", buffer);
+    todo_wine ok(res == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", res );
+    todo_wine ok(!strcmp( buffer, "Z" ), "expected 'Z', got '%s'\n", buffer);
     size = sizeof(buffer);
     res = RegEnumValueA( hkcr, 3, buffer, &size, NULL, NULL, NULL, NULL );
     ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", res );
@@ -2519,8 +2517,8 @@ static void test_classesroot_enum(void)
     ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
     ok(!strcmp( buffer, "B" ), "expected 'B', got '%s'\n", buffer);
     res = RegEnumKeyA( hkcr, 2, buffer, size );
-    ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
-    ok(!strcmp( buffer, "C" ), "expected 'C', got '%s'\n", buffer);
+    todo_wine ok(res == ERROR_SUCCESS, "RegEnumKey failed: %d\n", res );
+    todo_wine ok(!strcmp( buffer, "C" ), "expected 'C', got '%s'\n", buffer);
     res = RegEnumKeyA( hkcr, 3, buffer, size );
     ok(res == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", res );
 
-- 
1.8.2.3


More information about the wine-devel mailing list