[4/4] msi: Support registry key names that exceed 255 characters.
Hans Leidekker
hans at codeweavers.com
Mon Jun 11 08:36:51 CDT 2012
---
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");
--
1.7.5.4
More information about the wine-patches
mailing list