[3/3] msi: Correctly [un]register progids when associated class and extensions change state.
Hans Leidekker
hans at codeweavers.com
Thu Feb 27 04:03:48 CST 2014
---
dlls/msi/classes.c | 124 ++++++++++++++++++++++++------------------------
dlls/msi/msipriv.h | 1 -
dlls/msi/tests/action.c | 30 +++++++++---
3 files changed, 86 insertions(+), 69 deletions(-)
diff --git a/dlls/msi/classes.c b/dlls/msi/classes.c
index 3e096b3..a5139f8 100644
--- a/dlls/msi/classes.c
+++ b/dlls/msi/classes.c
@@ -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)
{
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index b664766..75d1920 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -642,7 +642,6 @@ struct tagMSIPROGID
LPWSTR Description;
LPWSTR IconPath;
/* not in the table, set during installation */
- BOOL InstallMe;
MSIPROGID *CurVer;
MSIPROGID *VersionInd;
};
diff --git a/dlls/msi/tests/action.c b/dlls/msi/tests/action.c
index 371860d..c6b45ec 100644
--- a/dlls/msi/tests/action.c
+++ b/dlls/msi/tests/action.c
@@ -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");
--
1.8.5.3
More information about the wine-patches
mailing list