Commit 0ed61000 authored by Hans Leidekker's avatar Hans Leidekker Committed by Alexandre Julliard

msi: Support registry key names that exceed 255 characters.

parent fc2c8a21
......@@ -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 );
......
......@@ -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");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment