msi: Correctly [un]register progids when associated class and extensions change state.
This commit is contained in:
parent
28ecbec88d
commit
a547027b01
|
@ -698,45 +698,6 @@ static UINT load_classes_and_such( MSIPACKAGE *package )
|
|||
return load_all_mimes( package );
|
||||
}
|
||||
|
||||
static void mark_progid_for_install( MSIPACKAGE* package, MSIPROGID *progid )
|
||||
{
|
||||
MSIPROGID *child;
|
||||
|
||||
if (!progid)
|
||||
return;
|
||||
|
||||
if (progid->InstallMe)
|
||||
return;
|
||||
|
||||
progid->InstallMe = TRUE;
|
||||
|
||||
/* all children if this is a parent also install */
|
||||
LIST_FOR_EACH_ENTRY( child, &package->progids, MSIPROGID, entry )
|
||||
{
|
||||
if (child->Parent == progid)
|
||||
mark_progid_for_install( package, child );
|
||||
}
|
||||
}
|
||||
|
||||
static void mark_progid_for_uninstall( MSIPACKAGE *package, MSIPROGID *progid )
|
||||
{
|
||||
MSIPROGID *child;
|
||||
|
||||
if (!progid)
|
||||
return;
|
||||
|
||||
if (!progid->InstallMe)
|
||||
return;
|
||||
|
||||
progid->InstallMe = FALSE;
|
||||
|
||||
LIST_FOR_EACH_ENTRY( child, &package->progids, MSIPROGID, entry )
|
||||
{
|
||||
if (child->Parent == progid)
|
||||
mark_progid_for_uninstall( package, child );
|
||||
}
|
||||
}
|
||||
|
||||
static UINT register_appid(const MSIAPPID *appid, LPCWSTR app )
|
||||
{
|
||||
static const WCHAR szRemoteServerName[] =
|
||||
|
@ -843,7 +804,6 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
|
|||
TRACE("Registering class %s (%p)\n", debugstr_w(cls->clsid), cls);
|
||||
|
||||
cls->action = INSTALLSTATE_LOCAL;
|
||||
mark_progid_for_install( package, cls->ProgID );
|
||||
|
||||
RegCreateKeyW( hkey, cls->clsid, &hkey2 );
|
||||
|
||||
|
@ -1001,7 +961,6 @@ UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
|
|||
TRACE("Unregistering class %s (%p)\n", debugstr_w(cls->clsid), cls);
|
||||
|
||||
cls->action = INSTALLSTATE_ABSENT;
|
||||
mark_progid_for_uninstall( package, cls->ProgID );
|
||||
|
||||
res = RegDeleteTreeW( hkey, cls->clsid );
|
||||
if (res != ERROR_SUCCESS)
|
||||
|
@ -1089,6 +1048,35 @@ static UINT register_progid( const MSIPROGID* progid )
|
|||
return rc;
|
||||
}
|
||||
|
||||
static const MSICLASS *get_progid_class( const MSIPROGID *progid )
|
||||
{
|
||||
while (progid)
|
||||
{
|
||||
if (progid->Parent) progid = progid->Parent;
|
||||
if (progid->Class) return progid->Class;
|
||||
if (!progid->Parent) break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL has_class_installed( const MSIPROGID *progid )
|
||||
{
|
||||
const MSICLASS *class = get_progid_class( progid );
|
||||
if (!class || !class->ProgID) return FALSE;
|
||||
return (class->action == INSTALLSTATE_LOCAL);
|
||||
}
|
||||
|
||||
static BOOL has_one_extension_installed( const MSIPACKAGE *package, const MSIPROGID *progid )
|
||||
{
|
||||
const MSIEXTENSION *extension;
|
||||
LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry )
|
||||
{
|
||||
if (extension->ProgID == progid && !list_empty( &extension->verbs ) &&
|
||||
extension->action == INSTALLSTATE_LOCAL) return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
|
||||
{
|
||||
MSIPROGID *progid;
|
||||
|
@ -1101,16 +1089,11 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
|
|||
|
||||
LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
|
||||
{
|
||||
/* check if this progid is to be installed */
|
||||
if (progid->Class && progid->Class->action == INSTALLSTATE_LOCAL)
|
||||
progid->InstallMe = TRUE;
|
||||
|
||||
if (!progid->InstallMe)
|
||||
if (!has_class_installed( progid ) && !has_one_extension_installed( package, progid ))
|
||||
{
|
||||
TRACE("progid %s not scheduled to be installed\n", debugstr_w(progid->ProgID));
|
||||
continue;
|
||||
}
|
||||
|
||||
TRACE("Registering progid %s\n", debugstr_w(progid->ProgID));
|
||||
|
||||
register_progid( progid );
|
||||
|
@ -1123,6 +1106,36 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static BOOL has_class_removed( const MSIPROGID *progid )
|
||||
{
|
||||
const MSICLASS *class = get_progid_class( progid );
|
||||
if (!class || !class->ProgID) return FALSE;
|
||||
return (class->action == INSTALLSTATE_ABSENT);
|
||||
}
|
||||
|
||||
static BOOL has_extensions( const MSIPACKAGE *package, const MSIPROGID *progid )
|
||||
{
|
||||
const MSIEXTENSION *extension;
|
||||
LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry )
|
||||
{
|
||||
if (extension->ProgID == progid && !list_empty( &extension->verbs )) return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL has_all_extensions_removed( const MSIPACKAGE *package, const MSIPROGID *progid )
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
const MSIEXTENSION *extension;
|
||||
LIST_FOR_EACH_ENTRY( extension, &package->extensions, MSIEXTENSION, entry )
|
||||
{
|
||||
if (extension->ProgID == progid && !list_empty( &extension->verbs ) &&
|
||||
extension->action == INSTALLSTATE_ABSENT) ret = TRUE;
|
||||
else ret = FALSE;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
|
||||
{
|
||||
MSIPROGID *progid;
|
||||
|
@ -1136,16 +1149,12 @@ UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
|
|||
|
||||
LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
|
||||
{
|
||||
/* check if this progid is to be removed */
|
||||
if (progid->Class && progid->Class->action != INSTALLSTATE_LOCAL)
|
||||
progid->InstallMe = FALSE;
|
||||
|
||||
if (progid->InstallMe)
|
||||
if (!has_class_removed( progid ) ||
|
||||
(has_extensions( package, progid ) && !has_all_extensions_removed( package, progid )))
|
||||
{
|
||||
TRACE("progid %s not scheduled to be removed\n", debugstr_w(progid->ProgID));
|
||||
continue;
|
||||
}
|
||||
|
||||
TRACE("Unregistering progid %s\n", debugstr_w(progid->ProgID));
|
||||
|
||||
res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid->ProgID );
|
||||
|
@ -1289,12 +1298,6 @@ UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
|
|||
|
||||
ext->action = INSTALLSTATE_LOCAL;
|
||||
|
||||
/* this is only registered if the extension has at least 1 verb
|
||||
* according to MSDN
|
||||
*/
|
||||
if (ext->ProgID && !list_empty( &ext->verbs ) )
|
||||
mark_progid_for_install( package, ext->ProgID );
|
||||
|
||||
extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) );
|
||||
if (extension)
|
||||
{
|
||||
|
@ -1393,9 +1396,6 @@ UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
|
|||
|
||||
ext->action = INSTALLSTATE_ABSENT;
|
||||
|
||||
if (ext->ProgID && !list_empty( &ext->verbs ))
|
||||
mark_progid_for_uninstall( package, ext->ProgID );
|
||||
|
||||
extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) );
|
||||
if (extension)
|
||||
{
|
||||
|
|
|
@ -642,7 +642,6 @@ struct tagMSIPROGID
|
|||
LPWSTR Description;
|
||||
LPWSTR IconPath;
|
||||
/* not in the table, set during installation */
|
||||
BOOL InstallMe;
|
||||
MSIPROGID *CurVer;
|
||||
MSIPROGID *VersionInd;
|
||||
};
|
||||
|
|
|
@ -1372,7 +1372,14 @@ static const char rpi_class_dat[] =
|
|||
static const char rpi_extension_dat[] =
|
||||
"Extension\tComponent_\tProgId_\tMIME_\tFeature_\n"
|
||||
"s255\ts72\tS255\tS64\ts38\n"
|
||||
"Extension\tExtension\tComponent_\n";
|
||||
"Extension\tExtension\tComponent_\n"
|
||||
"winetest\tprogid\tWinetest.Extension\t\tprogid\n";
|
||||
|
||||
static const char rpi_verb_dat[] =
|
||||
"Extension_\tVerb\tSequence\tCommand\tArgument\n"
|
||||
"s255\ts32\tI2\tL255\tL255\n"
|
||||
"Verb\tExtension_\tVerb\n"
|
||||
"winetest\tOpen\t1\t&Open\t/argument\n";
|
||||
|
||||
static const char rpi_progid_dat[] =
|
||||
"ProgId\tProgId_Parent\tClass_\tDescription\tIcon_\tIconIndex\n"
|
||||
|
@ -1386,7 +1393,8 @@ static const char rpi_progid_dat[] =
|
|||
"Winetest.NoProgIdClass.1\t\t{57C413FB-CA02-498A-81F6-7E769BDB7C97}\tdescription\t\t\n"
|
||||
"Winetest.NoProgIdClass\tWinetest.NoProgIdClass.1\t\tdescription\t\t\n"
|
||||
"Winetest.Orphaned\t\t\tdescription\t\t\n"
|
||||
"Winetest.Orphaned2\t\t\tdescription\t\t\n";
|
||||
"Winetest.Orphaned2\t\t\tdescription\t\t\n"
|
||||
"Winetest.Extension\t\t\tdescription\t\t\n";
|
||||
|
||||
static const char rpi_install_exec_seq_dat[] =
|
||||
"Action\tCondition\tSequence\n"
|
||||
|
@ -1400,10 +1408,12 @@ static const char rpi_install_exec_seq_dat[] =
|
|||
"InstallInitialize\t\t1500\n"
|
||||
"ProcessComponents\t\t1600\n"
|
||||
"RemoveFiles\t\t1700\n"
|
||||
"InstallFiles\t\t2000\n"
|
||||
"UnregisterClassInfo\t\t3000\n"
|
||||
"UnregisterExtensionInfo\t\t3200\n"
|
||||
"UnregisterProgIdInfo\t\t3400\n"
|
||||
"InstallFiles\t\t3600\n"
|
||||
"RegisterClassInfo\t\t4000\n"
|
||||
"RegisterExtensionInfo\t\t4200\n"
|
||||
"RegisterProgIdInfo\t\t4400\n"
|
||||
"RegisterProduct\t\t5000\n"
|
||||
"PublishFeatures\t\t5100\n"
|
||||
|
@ -1984,6 +1994,7 @@ static const msi_table rpi_tables[] =
|
|||
ADD_TABLE(rpi_appid),
|
||||
ADD_TABLE(rpi_class),
|
||||
ADD_TABLE(rpi_extension),
|
||||
ADD_TABLE(rpi_verb),
|
||||
ADD_TABLE(rpi_progid),
|
||||
ADD_TABLE(rpi_install_exec_seq),
|
||||
ADD_TABLE(media),
|
||||
|
@ -6371,19 +6382,23 @@ static void test_register_progid_info(void)
|
|||
RegCloseKey(hkey);
|
||||
|
||||
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.NoProgIdClass.1", &hkey);
|
||||
todo_wine ok(res == ERROR_FILE_NOT_FOUND, "key created\n");
|
||||
ok(res == ERROR_FILE_NOT_FOUND, "key created\n");
|
||||
if (res == ERROR_SUCCESS) RegCloseKey(hkey);
|
||||
|
||||
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.NoProgIdClass", &hkey);
|
||||
ok(res == ERROR_FILE_NOT_FOUND, "key created\n");
|
||||
|
||||
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Orphaned", &hkey);
|
||||
todo_wine ok(res == ERROR_SUCCESS, "key deleted\n");
|
||||
ok(res == ERROR_SUCCESS, "key deleted\n");
|
||||
if (res == ERROR_SUCCESS) RegCloseKey(hkey);
|
||||
|
||||
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Orphaned2", &hkey);
|
||||
ok(res == ERROR_FILE_NOT_FOUND, "key created\n");
|
||||
|
||||
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Extension", &hkey);
|
||||
ok(res == ERROR_SUCCESS, "key not created\n");
|
||||
RegCloseKey(hkey);
|
||||
|
||||
r = MsiInstallProductA(msifile, "REMOVE=ALL");
|
||||
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
|
||||
|
||||
|
@ -6415,12 +6430,15 @@ static void test_register_progid_info(void)
|
|||
ok(res == ERROR_FILE_NOT_FOUND, "key not removed\n");
|
||||
|
||||
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Orphaned", &hkey);
|
||||
todo_wine ok(res == ERROR_SUCCESS, "key deleted\n");
|
||||
ok(res == ERROR_SUCCESS, "key deleted\n");
|
||||
if (res == ERROR_SUCCESS) RegCloseKey(hkey);
|
||||
|
||||
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Orphaned2", &hkey);
|
||||
ok(res == ERROR_FILE_NOT_FOUND, "key not removed\n");
|
||||
|
||||
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Extension", &hkey);
|
||||
ok(res == ERROR_FILE_NOT_FOUND, "key not removed\n");
|
||||
|
||||
ok(!delete_pf("msitest\\progid.txt", TRUE), "file not removed\n");
|
||||
ok(!delete_pf("msitest", FALSE), "directory not removed\n");
|
||||
|
||||
|
|
Loading…
Reference in New Issue