Hans Leidekker : msi: Support registry key names that exceed 255 characters .

Alexandre Julliard julliard at winehq.org
Mon Jun 11 15:08:08 CDT 2012


Module: wine
Branch: master
Commit: 0ed61000d3b7b7a94ab5e3455d0e97294d80442d
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=0ed61000d3b7b7a94ab5e3455d0e97294d80442d

Author: Hans Leidekker <hans at codeweavers.com>
Date:   Mon Jun 11 15:36:51 2012 +0200

msi: Support registry key names that exceed 255 characters.

---

 dlls/msi/action.c       |  101 ++++++++++++++++++++++++++++++++++++-----------
 dlls/msi/tests/action.c |   75 ++++++++++++++++++++++++++++++++++-
 2 files changed, 152 insertions(+), 24 deletions(-)

diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index e7b2921..b256439 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -2582,6 +2582,38 @@ static WCHAR *get_keypath( MSICOMPONENT *comp, HKEY root, const WCHAR *path )
     return strdupW( path );
 }
 
+static HKEY open_key( HKEY root, const WCHAR *path, BOOL create )
+{
+    REGSAM access = KEY_ALL_ACCESS;
+    WCHAR *subkey, *p, *q;
+    HKEY hkey, ret = NULL;
+    LONG res;
+
+    if (is_wow64) access |= KEY_WOW64_64KEY;
+
+    if (!(subkey = strdupW( path ))) return NULL;
+    p = subkey;
+    if ((q = strchrW( p, '\\' ))) *q = 0;
+    if (create)
+        res = RegCreateKeyExW( root, subkey, 0, NULL, 0, access, NULL, &hkey, NULL );
+    else
+        res = RegOpenKeyExW( root, subkey, 0, access, &hkey );
+    if (res)
+    {
+        TRACE("failed to open key %s (%d)\n", debugstr_w(subkey), res);
+        msi_free( subkey );
+        return NULL;
+    }
+    if (q && q[1])
+    {
+        ret = open_key( hkey, q + 1, create );
+        RegCloseKey( hkey );
+    }
+    else ret = hkey;
+    msi_free( subkey );
+    return ret;
+}
+
 static BOOL is_special_entry( const WCHAR *name )
 {
      return (name && (name[0] == '*' || name[0] == '+') && !name[1]);
@@ -2640,7 +2672,7 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
 
     keypath = get_keypath( comp, root_key, deformated );
     msi_free( deformated );
-    if (RegCreateKeyExW( root_key, keypath, 0, NULL, 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, NULL, &hkey, NULL ))
+    if (!(hkey = open_key( root_key, keypath, TRUE )))
     {
         ERR("Could not create key %s\n", debugstr_w(keypath));
         msi_free(uikey);
@@ -2711,44 +2743,67 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
     return rc;
 }
 
-static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *value )
+static void delete_key( HKEY root, const WCHAR *path )
+{
+    REGSAM access = 0;
+    WCHAR *subkey, *p;
+    HKEY hkey;
+    LONG res;
+
+    if (is_wow64) access |= KEY_WOW64_64KEY;
+
+    if (!(subkey = strdupW( path ))) return;
+    for (;;)
+    {
+        if ((p = strrchrW( subkey, '\\' ))) *p = 0;
+        hkey = open_key( root, subkey, FALSE );
+        if (!hkey) break;
+        if (p && p[1])
+            res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
+        else
+            res = RegDeleteKeyExW( root, subkey, access, 0 );
+        if (res)
+        {
+            TRACE("failed to delete key %s (%d)\n", debugstr_w(subkey), res);
+            break;
+        }
+        if (p && p[1]) RegCloseKey( hkey );
+        else break;
+    }
+    msi_free( subkey );
+}
+
+static void delete_value( HKEY root, const WCHAR *path, const WCHAR *value )
 {
     LONG res;
     HKEY hkey;
     DWORD num_subkeys, num_values;
 
-    if (!(res = RegOpenKeyExW( root, keypath, 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, &hkey )))
+    if ((hkey = open_key( root, path, FALSE )))
     {
         if ((res = RegDeleteValueW( hkey, value )))
-        {
             TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
-        }
+
         res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
                                 NULL, NULL, NULL, NULL );
         RegCloseKey( hkey );
         if (!res && !num_subkeys && !num_values)
         {
-            TRACE("removing empty key %s\n", debugstr_w(keypath));
-            RegDeleteKeyExW( root, keypath, KEY_WOW64_64KEY, 0 );
+            TRACE("removing empty key %s\n", debugstr_w(path));
+            delete_key( root, path );
         }
-        return;
     }
-    TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
 }
 
-static void delete_reg_key( HKEY root, const WCHAR *keypath )
+static void delete_tree( HKEY root, const WCHAR *path )
 {
+    LONG res;
     HKEY hkey;
-    LONG res = RegOpenKeyExW( root, keypath, 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, &hkey );
-    if (res)
-    {
-        TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res);
-        return;
-    }
+
+    if (!(hkey = open_key( root, path, FALSE ))) return;
     res = RegDeleteTreeW( hkey, NULL );
-    if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(keypath), res);
-    res = RegDeleteKeyExW( root, keypath, KEY_WOW64_64KEY, 0 );
-    if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res);
+    if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res);
+    delete_key( root, path );
     RegCloseKey( hkey );
 }
 
@@ -2807,8 +2862,8 @@ static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID para
 
     keypath = get_keypath( comp, hkey_root, deformated_key );
     msi_free( deformated_key );
-    if (delete_key) delete_reg_key( hkey_root, keypath );
-    else delete_reg_value( hkey_root, keypath, deformated_name );
+    if (delete_key) delete_tree( hkey_root, keypath );
+    else delete_value( hkey_root, keypath, deformated_name );
     msi_free( keypath );
 
     uirow = MSI_CreateRecord( 2 );
@@ -2872,8 +2927,8 @@ static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param
 
     keypath = get_keypath( comp, hkey_root, deformated_key );
     msi_free( deformated_key );
-    if (delete_key) delete_reg_key( hkey_root, keypath );
-    else delete_reg_value( hkey_root, keypath, deformated_name );
+    if (delete_key) delete_tree( hkey_root, keypath );
+    else delete_value( hkey_root, keypath, deformated_name );
     msi_free( keypath );
 
     uirow = MSI_CreateRecord( 2 );
diff --git a/dlls/msi/tests/action.c b/dlls/msi/tests/action.c
index 0bd65a0..82afd18 100644
--- a/dlls/msi/tests/action.c
+++ b/dlls/msi/tests/action.c
@@ -490,7 +490,8 @@ static const char wrv_registry_dat[] =
     "regdata\t2\tSOFTWARE\\Wine\\msitest\tValue\t[~]one[~]two[~]three\taugustus\n"
     "regdata1\t2\tSOFTWARE\\Wine\\msitest\t*\t\taugustus\n"
     "regdata2\t2\tSOFTWARE\\Wine\\msitest\t*\t#%\taugustus\n"
-    "regdata3\t2\tSOFTWARE\\Wine\\msitest\t*\t#x\taugustus\n";
+    "regdata3\t2\tSOFTWARE\\Wine\\msitest\t*\t#x\taugustus\n"
+    "regdata4\t2\tSOFTWARE\\Wine\\msitest\\VisualStudio\\10.0\\AD7Metrics\\Exception\\{049EC4CC-30D2-4032-9256-EE18EB41B62B}\\Common Language Runtime Exceptions\\System.Workflow.ComponentModel.Serialization\\System.Workflow.ComponentModel.Serialization.WorkflowMarkupSerializationException\tlong\tkey\taugustus\n";
 
 static const char cf_directory_dat[] =
     "Directory\tDirectory_Parent\tDefaultDir\n"
@@ -1818,6 +1819,75 @@ static const msi_table pa_tables[] =
     ADD_TABLE(property)
 };
 
+/* based on RegDeleteTreeW from dlls/advapi32/registry.c */
+static LSTATUS action_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey, REGSAM access)
+{
+    LONG ret;
+    DWORD dwMaxSubkeyLen, dwMaxValueLen;
+    DWORD dwMaxLen, dwSize;
+    char szNameBuf[MAX_PATH], *lpszName = szNameBuf;
+    HKEY hSubKey = hKey;
+
+    if(lpszSubKey)
+    {
+        ret = RegOpenKeyExA(hKey, lpszSubKey, 0, access, &hSubKey);
+        if (ret) return ret;
+    }
+
+    ret = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, NULL,
+            &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
+    if (ret) goto cleanup;
+
+    dwMaxSubkeyLen++;
+    dwMaxValueLen++;
+    dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
+    if (dwMaxLen > sizeof(szNameBuf))
+    {
+        /* Name too big: alloc a buffer for it */
+        if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen)))
+        {
+            ret = ERROR_NOT_ENOUGH_MEMORY;
+            goto cleanup;
+        }
+    }
+
+    /* Recursively delete all the subkeys */
+    while (TRUE)
+    {
+        dwSize = dwMaxLen;
+        if (RegEnumKeyExA(hSubKey, 0, lpszName, &dwSize, NULL,
+                          NULL, NULL, NULL)) break;
+
+        ret = action_RegDeleteTreeA(hSubKey, lpszName, access);
+        if (ret) goto cleanup;
+    }
+
+    if (lpszSubKey)
+    {
+        if (pRegDeleteKeyExA)
+            ret = pRegDeleteKeyExA(hKey, lpszSubKey, access, 0);
+        else
+            ret = RegDeleteKeyA(hKey, lpszSubKey);
+    }
+    else
+        while (TRUE)
+        {
+            dwSize = dwMaxLen;
+            if (RegEnumValueA(hKey, 0, lpszName, &dwSize,
+                  NULL, NULL, NULL, NULL)) break;
+
+            ret = RegDeleteValueA(hKey, lpszName);
+            if (ret) goto cleanup;
+        }
+
+cleanup:
+    if (lpszName != szNameBuf)
+        HeapFree(GetProcessHeap(), 0, lpszName);
+    if(lpszSubKey)
+        RegCloseKey(hSubKey);
+    return ret;
+}
+
 /* cabinet definitions */
 
 /* make the max size large so there is only one cab file */
@@ -4586,6 +4656,9 @@ static void test_write_registry_values(void)
     res = RegQueryValueExA(hkey, "", NULL, NULL, NULL, NULL);
     ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
 
+    res = action_RegDeleteTreeA(hkey, "VisualStudio", KEY_ALL_ACCESS);
+    ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
+
     RegDeleteValueA(hkey, "Value");
     RegCloseKey(hkey);
     RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");




More information about the wine-cvs mailing list