mirror of
https://github.com/reactos/wine.git
synced 2024-11-25 04:39:45 +00:00
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 );
|
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 UINT register_appid(const MSIAPPID *appid, LPCWSTR app )
|
||||||
{
|
{
|
||||||
static const WCHAR szRemoteServerName[] =
|
static const WCHAR szRemoteServerName[] =
|
||||||
@ -843,7 +804,6 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
|
|||||||
TRACE("Registering class %s (%p)\n", debugstr_w(cls->clsid), cls);
|
TRACE("Registering class %s (%p)\n", debugstr_w(cls->clsid), cls);
|
||||||
|
|
||||||
cls->action = INSTALLSTATE_LOCAL;
|
cls->action = INSTALLSTATE_LOCAL;
|
||||||
mark_progid_for_install( package, cls->ProgID );
|
|
||||||
|
|
||||||
RegCreateKeyW( hkey, cls->clsid, &hkey2 );
|
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);
|
TRACE("Unregistering class %s (%p)\n", debugstr_w(cls->clsid), cls);
|
||||||
|
|
||||||
cls->action = INSTALLSTATE_ABSENT;
|
cls->action = INSTALLSTATE_ABSENT;
|
||||||
mark_progid_for_uninstall( package, cls->ProgID );
|
|
||||||
|
|
||||||
res = RegDeleteTreeW( hkey, cls->clsid );
|
res = RegDeleteTreeW( hkey, cls->clsid );
|
||||||
if (res != ERROR_SUCCESS)
|
if (res != ERROR_SUCCESS)
|
||||||
@ -1089,6 +1048,35 @@ static UINT register_progid( const MSIPROGID* progid )
|
|||||||
return rc;
|
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)
|
UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
|
||||||
{
|
{
|
||||||
MSIPROGID *progid;
|
MSIPROGID *progid;
|
||||||
@ -1101,16 +1089,11 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
|
|||||||
|
|
||||||
LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
|
LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
|
||||||
{
|
{
|
||||||
/* check if this progid is to be installed */
|
if (!has_class_installed( progid ) && !has_one_extension_installed( package, progid ))
|
||||||
if (progid->Class && progid->Class->action == INSTALLSTATE_LOCAL)
|
|
||||||
progid->InstallMe = TRUE;
|
|
||||||
|
|
||||||
if (!progid->InstallMe)
|
|
||||||
{
|
{
|
||||||
TRACE("progid %s not scheduled to be installed\n", debugstr_w(progid->ProgID));
|
TRACE("progid %s not scheduled to be installed\n", debugstr_w(progid->ProgID));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("Registering progid %s\n", debugstr_w(progid->ProgID));
|
TRACE("Registering progid %s\n", debugstr_w(progid->ProgID));
|
||||||
|
|
||||||
register_progid( progid );
|
register_progid( progid );
|
||||||
@ -1123,6 +1106,36 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
|
|||||||
return ERROR_SUCCESS;
|
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 )
|
UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
|
||||||
{
|
{
|
||||||
MSIPROGID *progid;
|
MSIPROGID *progid;
|
||||||
@ -1136,16 +1149,12 @@ UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
|
|||||||
|
|
||||||
LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
|
LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
|
||||||
{
|
{
|
||||||
/* check if this progid is to be removed */
|
if (!has_class_removed( progid ) ||
|
||||||
if (progid->Class && progid->Class->action != INSTALLSTATE_LOCAL)
|
(has_extensions( package, progid ) && !has_all_extensions_removed( package, progid )))
|
||||||
progid->InstallMe = FALSE;
|
|
||||||
|
|
||||||
if (progid->InstallMe)
|
|
||||||
{
|
{
|
||||||
TRACE("progid %s not scheduled to be removed\n", debugstr_w(progid->ProgID));
|
TRACE("progid %s not scheduled to be removed\n", debugstr_w(progid->ProgID));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("Unregistering progid %s\n", debugstr_w(progid->ProgID));
|
TRACE("Unregistering progid %s\n", debugstr_w(progid->ProgID));
|
||||||
|
|
||||||
res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid->ProgID );
|
res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid->ProgID );
|
||||||
@ -1289,12 +1298,6 @@ UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
|
|||||||
|
|
||||||
ext->action = INSTALLSTATE_LOCAL;
|
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) );
|
extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) );
|
||||||
if (extension)
|
if (extension)
|
||||||
{
|
{
|
||||||
@ -1393,9 +1396,6 @@ UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
|
|||||||
|
|
||||||
ext->action = INSTALLSTATE_ABSENT;
|
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) );
|
extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) );
|
||||||
if (extension)
|
if (extension)
|
||||||
{
|
{
|
||||||
|
@ -642,7 +642,6 @@ struct tagMSIPROGID
|
|||||||
LPWSTR Description;
|
LPWSTR Description;
|
||||||
LPWSTR IconPath;
|
LPWSTR IconPath;
|
||||||
/* not in the table, set during installation */
|
/* not in the table, set during installation */
|
||||||
BOOL InstallMe;
|
|
||||||
MSIPROGID *CurVer;
|
MSIPROGID *CurVer;
|
||||||
MSIPROGID *VersionInd;
|
MSIPROGID *VersionInd;
|
||||||
};
|
};
|
||||||
|
@ -1372,7 +1372,14 @@ static const char rpi_class_dat[] =
|
|||||||
static const char rpi_extension_dat[] =
|
static const char rpi_extension_dat[] =
|
||||||
"Extension\tComponent_\tProgId_\tMIME_\tFeature_\n"
|
"Extension\tComponent_\tProgId_\tMIME_\tFeature_\n"
|
||||||
"s255\ts72\tS255\tS64\ts38\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[] =
|
static const char rpi_progid_dat[] =
|
||||||
"ProgId\tProgId_Parent\tClass_\tDescription\tIcon_\tIconIndex\n"
|
"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.1\t\t{57C413FB-CA02-498A-81F6-7E769BDB7C97}\tdescription\t\t\n"
|
||||||
"Winetest.NoProgIdClass\tWinetest.NoProgIdClass.1\t\tdescription\t\t\n"
|
"Winetest.NoProgIdClass\tWinetest.NoProgIdClass.1\t\tdescription\t\t\n"
|
||||||
"Winetest.Orphaned\t\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[] =
|
static const char rpi_install_exec_seq_dat[] =
|
||||||
"Action\tCondition\tSequence\n"
|
"Action\tCondition\tSequence\n"
|
||||||
@ -1400,10 +1408,12 @@ static const char rpi_install_exec_seq_dat[] =
|
|||||||
"InstallInitialize\t\t1500\n"
|
"InstallInitialize\t\t1500\n"
|
||||||
"ProcessComponents\t\t1600\n"
|
"ProcessComponents\t\t1600\n"
|
||||||
"RemoveFiles\t\t1700\n"
|
"RemoveFiles\t\t1700\n"
|
||||||
"InstallFiles\t\t2000\n"
|
|
||||||
"UnregisterClassInfo\t\t3000\n"
|
"UnregisterClassInfo\t\t3000\n"
|
||||||
|
"UnregisterExtensionInfo\t\t3200\n"
|
||||||
"UnregisterProgIdInfo\t\t3400\n"
|
"UnregisterProgIdInfo\t\t3400\n"
|
||||||
|
"InstallFiles\t\t3600\n"
|
||||||
"RegisterClassInfo\t\t4000\n"
|
"RegisterClassInfo\t\t4000\n"
|
||||||
|
"RegisterExtensionInfo\t\t4200\n"
|
||||||
"RegisterProgIdInfo\t\t4400\n"
|
"RegisterProgIdInfo\t\t4400\n"
|
||||||
"RegisterProduct\t\t5000\n"
|
"RegisterProduct\t\t5000\n"
|
||||||
"PublishFeatures\t\t5100\n"
|
"PublishFeatures\t\t5100\n"
|
||||||
@ -1984,6 +1994,7 @@ static const msi_table rpi_tables[] =
|
|||||||
ADD_TABLE(rpi_appid),
|
ADD_TABLE(rpi_appid),
|
||||||
ADD_TABLE(rpi_class),
|
ADD_TABLE(rpi_class),
|
||||||
ADD_TABLE(rpi_extension),
|
ADD_TABLE(rpi_extension),
|
||||||
|
ADD_TABLE(rpi_verb),
|
||||||
ADD_TABLE(rpi_progid),
|
ADD_TABLE(rpi_progid),
|
||||||
ADD_TABLE(rpi_install_exec_seq),
|
ADD_TABLE(rpi_install_exec_seq),
|
||||||
ADD_TABLE(media),
|
ADD_TABLE(media),
|
||||||
@ -6371,19 +6382,23 @@ static void test_register_progid_info(void)
|
|||||||
RegCloseKey(hkey);
|
RegCloseKey(hkey);
|
||||||
|
|
||||||
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.NoProgIdClass.1", &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);
|
if (res == ERROR_SUCCESS) RegCloseKey(hkey);
|
||||||
|
|
||||||
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.NoProgIdClass", &hkey);
|
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.NoProgIdClass", &hkey);
|
||||||
ok(res == ERROR_FILE_NOT_FOUND, "key created\n");
|
ok(res == ERROR_FILE_NOT_FOUND, "key created\n");
|
||||||
|
|
||||||
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Orphaned", &hkey);
|
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);
|
if (res == ERROR_SUCCESS) RegCloseKey(hkey);
|
||||||
|
|
||||||
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Orphaned2", &hkey);
|
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Orphaned2", &hkey);
|
||||||
ok(res == ERROR_FILE_NOT_FOUND, "key created\n");
|
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");
|
r = MsiInstallProductA(msifile, "REMOVE=ALL");
|
||||||
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
|
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");
|
ok(res == ERROR_FILE_NOT_FOUND, "key not removed\n");
|
||||||
|
|
||||||
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Orphaned", &hkey);
|
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);
|
if (res == ERROR_SUCCESS) RegCloseKey(hkey);
|
||||||
|
|
||||||
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Orphaned2", &hkey);
|
res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Orphaned2", &hkey);
|
||||||
ok(res == ERROR_FILE_NOT_FOUND, "key not removed\n");
|
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\\progid.txt", TRUE), "file not removed\n");
|
||||||
ok(!delete_pf("msitest", FALSE), "directory not removed\n");
|
ok(!delete_pf("msitest", FALSE), "directory not removed\n");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user