msi: Support registry key names that exceed 255 characters.
This commit is contained in:
parent
fc2c8a215f
commit
0ed61000d3
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue