Hans Leidekker : msi: Implement the RemoveExistingProducts standard action.
Alexandre Julliard
julliard at winehq.org
Tue Jul 31 12:04:15 CDT 2012
Module: wine
Branch: master
Commit: f180de40dd7820753479f823b6cb08a34b479c66
URL: http://source.winehq.org/git/wine.git/?a=commit;h=f180de40dd7820753479f823b6cb08a34b479c66
Author: Hans Leidekker <hans at codeweavers.com>
Date: Tue Jul 31 12:25:42 2012 +0200
msi: Implement the RemoveExistingProducts standard action.
---
dlls/msi/action.c | 42 ++++++++++++++---
dlls/msi/tests/action.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 155 insertions(+), 7 deletions(-)
diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index d452c92..1ad3bc2 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -7045,23 +7045,51 @@ static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
{
+ static const WCHAR fmtW[] =
+ {'m','s','i','e','x','e','c',' ','/','i',' ','%','s',' ','R','E','M','O','V','E','=','%','s',0};
MSIPACKAGE *package = param;
- const WCHAR *property = MSI_RecordGetString( rec, 1 );
- WCHAR *value;
+ const WCHAR *property = MSI_RecordGetString( rec, 7 );
+ UINT len = sizeof(fmtW)/sizeof(fmtW[0]);
+ WCHAR *product, *features, *cmd;
+ STARTUPINFOW si;
+ PROCESS_INFORMATION info;
+ BOOL ret;
- if ((value = msi_dup_property( package->db, property )))
+ if (!(product = msi_dup_property( package->db, property ))) return ERROR_SUCCESS;
+
+ deformat_string( package, MSI_RecordGetString( rec, 6 ), &features );
+
+ len += strlenW( product );
+ if (features)
+ len += strlenW( features );
+ else
+ len += sizeof(szAll) / sizeof(szAll[0]);
+
+ if (!(cmd = msi_alloc( len * sizeof(WCHAR) )))
{
- FIXME("remove %s\n", debugstr_w(value));
- msi_free( value );
+ msi_free( product );
+ msi_free( features );
+ return ERROR_OUTOFMEMORY;
}
+ sprintfW( cmd, fmtW, product, features ? features : szAll );
+ msi_free( product );
+ msi_free( features );
+
+ memset( &si, 0, sizeof(STARTUPINFOW) );
+ ret = CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info );
+ msi_free( cmd );
+ if (!ret) return GetLastError();
+ CloseHandle( info.hThread );
+
+ WaitForSingleObject( info.hProcess, INFINITE );
+ CloseHandle( info.hProcess );
return ERROR_SUCCESS;
}
static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
{
static const WCHAR query[] = {
- 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
- 'F','R','O','M',' ','U','p','g','r','a','d','e',0};
+ 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
MSIQUERY *view;
UINT r;
diff --git a/dlls/msi/tests/action.c b/dlls/msi/tests/action.c
index 814b49c..1fcb82d 100644
--- a/dlls/msi/tests/action.c
+++ b/dlls/msi/tests/action.c
@@ -1461,6 +1461,76 @@ static const char pa_install_exec_seq_dat[] =
"PublishProduct\t\t5200\n"
"InstallFinalize\t\t6000\n";
+static const char rep_file_dat[] =
+ "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
+ "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
+ "File\tFile\n"
+ "rep.txt\trep\trep.txt\t1000\t\t\t8192\t1\n";
+
+static const char rep_feature_dat[] =
+ "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
+ "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
+ "Feature\tFeature\n"
+ "rep\t\t\trep feature\t1\t2\tMSITESTDIR\t0\n";
+
+static const char rep_feature_comp_dat[] =
+ "Feature_\tComponent_\n"
+ "s38\ts72\n"
+ "FeatureComponents\tFeature_\tComponent_\n"
+ "rep\trep\n";
+
+static const char rep_component_dat[] =
+ "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
+ "s72\tS38\ts72\ti2\tS255\tS72\n"
+ "Component\tComponent\n"
+ "rep\t{A24FAF2A-3B2E-41EF-AA78-331542E1A29D}\tMSITESTDIR\t0\t\trep.txt\n";
+
+static const char rep_upgrade_dat[] =
+ "UpgradeCode\tVersionMin\tVersionMax\tLanguage\tAttributes\tRemove\tActionProperty\n"
+ "s38\tS20\tS20\tS255\ti4\tS255\ts72\n"
+ "Upgrade\tUpgradeCode\tVersionMin\tVersionMax\tLanguage\tAttributes\n"
+ "{2967C1CC-34D4-42EE-8D96-CD6836F192BF}\t\t\t\t256\t\tPRODUCT\n";
+
+static const char rep_property_dat[] =
+ "Property\tValue\n"
+ "s72\tl0\n"
+ "Property\tProperty\n"
+ "HASUIRUN\t0\n"
+ "INSTALLLEVEL\t3\n"
+ "InstallMode\tTypical\n"
+ "Manufacturer\tWine\n"
+ "PIDTemplate\t###-#######\n"
+ "ProductCode\t{1699F0BB-0B61-4A89-AFE4-CFD60DFD76F3}\n"
+ "ProductLanguage\t1033\n"
+ "ProductName\tMSITEST\n"
+ "ProductVersion\t1.1.1\n"
+ "UpgradeCode\t{2967C1CC-34D4-42EE-8D96-CD6836F192BF}\n"
+ "PRODUCT\t2F41860D-7B4C-4DA7-BED9-B64F26594C56\n"
+ "MSIFASTINSTALL\t1\n";
+
+static const char rep_install_exec_seq_dat[] =
+ "Action\tCondition\tSequence\n"
+ "s72\tS255\tI2\n"
+ "InstallExecuteSequence\tAction\n"
+ "FindRelatedProducts\t\t100\n"
+ "CostInitialize\t\t800\n"
+ "FileCost\t\t900\n"
+ "CostFinalize\t\t1000\n"
+ "InstallValidate\t\t1400\n"
+ "RemoveExistingProducts\t\t1499\n"
+ "InstallInitialize\t\t1500\n"
+ "ProcessComponents\t\t1600\n"
+ "RemoveFiles\t\t1700\n"
+ "InstallFiles\t\t2000\n"
+ "UnregisterExtensionInfo\t\t3000\n"
+ "UnregisterMIMEInfo\t\t3500\n"
+ "RegisterExtensionInfo\t\t4000\n"
+ "RegisterMIMEInfo\t\t4500\n"
+ "RegisterProduct\t\t5000\n"
+ "PublishFeatures\t\t5100\n"
+ "PublishProduct\t\t5200\n"
+ "InstallFinalize\t\t6000\n";
+
typedef struct _msi_table
{
const char *filename;
@@ -1818,6 +1888,19 @@ static const msi_table pa_tables[] =
ADD_TABLE(property)
};
+static const msi_table rep_tables[] =
+{
+ ADD_TABLE(directory),
+ ADD_TABLE(rep_component),
+ ADD_TABLE(rep_feature),
+ ADD_TABLE(rep_feature_comp),
+ ADD_TABLE(rep_file),
+ ADD_TABLE(rep_upgrade),
+ ADD_TABLE(rep_property),
+ ADD_TABLE(rep_install_exec_seq),
+ ADD_TABLE(media)
+};
+
/* based on RegDeleteTreeW from dlls/advapi32/registry.c */
static LSTATUS action_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey, REGSAM access)
{
@@ -6125,6 +6208,42 @@ done:
DeleteFile(msifile);
}
+static void test_remove_existing_products(void)
+{
+ UINT r;
+
+ if (is_process_limited())
+ {
+ skip("process is limited\n");
+ return;
+ }
+
+ create_test_files();
+ create_file("msitest\\rep.txt", 1000);
+ create_database(msifile, rep_tables, sizeof(rep_tables) / sizeof(msi_table));
+
+ MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+ r = MsiInstallProductA(msifile, NULL);
+ if (r == ERROR_INSTALL_PACKAGE_REJECTED)
+ {
+ skip("Not enough rights to perform tests\n");
+ goto error;
+ }
+ ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+ r = MsiInstallProductA(msifile, "REMOVE=ALL");
+ ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
+
+ ok(!delete_pf("msitest\\rep.txt", TRUE), "file not removed\n");
+ ok(!delete_pf("msitest", FALSE), "directory not removed\n");
+
+error:
+ DeleteFileA("msitest\\rep.txt");
+ delete_test_files();
+ DeleteFile(msifile);
+}
+
START_TEST(action)
{
DWORD len;
@@ -6202,6 +6321,7 @@ START_TEST(action)
test_register_extension_info();
test_register_mime_info();
test_publish_assemblies();
+ test_remove_existing_products();
DeleteFileA(log_file);
More information about the wine-cvs
mailing list