sync msi to wine 1.1.31
[reactos.git] / reactos / dll / win32 / msi / action.c
index 3a32a06..46249c2 100644 (file)
@@ -401,9 +401,13 @@ static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
 
 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
 {
-    WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
-    LPWSTR prod_code, patch_product;
-    UINT ret;
+    static const WCHAR szProductCode[] =
+        { 'P','r','o','d','u','c','t','C','o','d','e',0 };
+    static const WCHAR szSystemLanguageID[] =
+        { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
+
+    LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
+    UINT ret = ERROR_FUNCTION_FAILED;
 
     prod_code = msi_dup_property( package, szProductCode );
     patch_product = msi_get_suminfo_product( patch );
@@ -411,12 +415,57 @@ static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch
     TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
 
     if ( strstrW( patch_product, prod_code ) )
-        ret = ERROR_SUCCESS;
-    else
-        ret = ERROR_FUNCTION_FAILED;
+    {
+        static const WCHAR zero[] = {'0',0};
+        MSISUMMARYINFO *si;
+        const WCHAR *p;
+
+        si = MSI_GetSummaryInformationW( patch, 0 );
+        if (!si)
+        {
+            ERR("no summary information!\n");
+            goto end;
+        }
+
+        template = msi_suminfo_dup_string( si, PID_TEMPLATE );
+        if (!template)
+        {
+            ERR("no template property!\n");
+            msiobj_release( &si->hdr );
+            goto end;
+        }
+
+        if (!template[0])
+        {
+            ret = ERROR_SUCCESS;
+            msiobj_release( &si->hdr );
+            goto end;
+        }
+
+        langid = msi_dup_property( package, szSystemLanguageID );
+        if (!langid)
+        {
+            msiobj_release( &si->hdr );
+            goto end;
+        }
+
+        p = strchrW( template, ';' );
+        if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, zero )))
+        {
+            TRACE("applicable transform\n");
+            ret = ERROR_SUCCESS;
+        }
+
+        /* FIXME: check platform */
+
+        msiobj_release( &si->hdr );
+    }
 
+end:
     msi_free( patch_product );
     msi_free( prod_code );
+    msi_free( template );
+    msi_free( langid );
 
     return ret;
 }
@@ -452,7 +501,7 @@ static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
     return ERROR_SUCCESS;
 }
 
-static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
+UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
 {
     static const WCHAR szProdCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
     LPWSTR guid_list, *guids, product_code;
@@ -740,6 +789,9 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
     static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
     static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
     static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
+    static const WCHAR szReinstall[] = {'R','E','I','N','S','T','A','L','L',0};
+    static const WCHAR szInstalled[] = {'I','n','s','t','a','l','l','e','d',0};
+    static const WCHAR szAll[] = {'A','L','L',0};
 
     MSI_SetPropertyW(package, szAction, szInstall);
 
@@ -788,6 +840,12 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
     msi_apply_transforms( package );
     msi_apply_patches( package );
 
+    if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
+    {
+        TRACE("setting reinstall property\n");
+        MSI_SetPropertyW( package, szReinstall, szAll );
+    }
+
     /* properties may have been added by a transform */
     msi_clone_properties( package );
     msi_set_context( package );
@@ -822,6 +880,9 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
     /* finish up running custom actions */
     ACTION_FinishCustomActions(package);
     
+    if (rc == ERROR_SUCCESS && package->need_reboot)
+        return ERROR_SUCCESS_REBOOT_REQUIRED;
+
     return rc;
 }
 
@@ -887,7 +948,7 @@ typedef struct {
 
 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
 {
-    iterate_action_param *iap= (iterate_action_param*)param;
+    iterate_action_param *iap = param;
     UINT rc;
     LPCWSTR cond, action;
 
@@ -1125,7 +1186,7 @@ UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT scrip
 
 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
 {
-    MSIPACKAGE *package = (MSIPACKAGE*)param;
+    MSIPACKAGE *package = param;
     LPCWSTR dir;
     LPWSTR full_path;
     MSIRECORD *uirow;
@@ -1307,7 +1368,7 @@ static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
 
 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
 {
-    _ilfs* ilfs= (_ilfs*)param;
+    _ilfs* ilfs = param;
     LPCWSTR component;
     MSICOMPONENT *comp;
 
@@ -1345,7 +1406,7 @@ static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
 
 static UINT load_feature(MSIRECORD * row, LPVOID param)
 {
-    MSIPACKAGE* package = (MSIPACKAGE*)param;
+    MSIPACKAGE* package = param;
     MSIFEATURE* feature;
     static const WCHAR Query1[] = 
         {'S','E','L','E','C','T',' ',
@@ -1404,7 +1465,7 @@ static UINT load_feature(MSIRECORD * row, LPVOID param)
 
 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
 {
-    MSIPACKAGE* package = (MSIPACKAGE*)param;
+    MSIPACKAGE* package = param;
     MSIFEATURE *parent, *child;
 
     child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
@@ -1497,7 +1558,7 @@ done:
 
 static UINT load_file(MSIRECORD *row, LPVOID param)
 {
-    MSIPACKAGE* package = (MSIPACKAGE*)param;
+    MSIPACKAGE* package = param;
     LPCWSTR component;
     MSIFILE *file;
 
@@ -1782,6 +1843,7 @@ static BOOL process_state_property(MSIPACKAGE* package, int level,
 {
     static const WCHAR all[]={'A','L','L',0};
     static const WCHAR remove[] = {'R','E','M','O','V','E',0};
+    static const WCHAR reinstall[] = {'R','E','I','N','S','T','A','L','L',0};
     LPWSTR override;
     MSIFEATURE *feature;
 
@@ -1795,6 +1857,8 @@ static BOOL process_state_property(MSIPACKAGE* package, int level,
             (feature->Level <= 0 || feature->Level > level))
             continue;
 
+        if (!strcmpW(property, reinstall)) state = feature->Installed;
+
         if (strcmpiW(override,all)==0)
             msi_feature_set_state(package, feature, state);
         else
@@ -1838,6 +1902,8 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
         {'R','E','M','O','V','E',0};
     static const WCHAR szReinstall[] =
         {'R','E','I','N','S','T','A','L','L',0};
+    static const WCHAR szAdvertise[] =
+        {'A','D','V','E','R','T','I','S','E',0};
     BOOL override = FALSE;
     MSICOMPONENT* component;
     MSIFEATURE *feature;
@@ -1852,12 +1918,13 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
     /* ok here is the _real_ rub
      * all these activation/deactivation things happen in order and things
      * later on the list override things earlier on the list.
-     * 1) INSTALLLEVEL processing
-     * 2) ADDLOCAL
-     * 3) REMOVE
-     * 4) ADDSOURCE
-     * 5) ADDDEFAULT
-     * 6) REINSTALL
+     * 0) INSTALLLEVEL processing
+     * 1) ADDLOCAL
+     * 2) REMOVE
+     * 3) ADDSOURCE
+     * 4) ADDDEFAULT
+     * 5) REINSTALL
+     * 6) ADVERTISE
      * 7) COMPADDLOCAL
      * 8) COMPADDSOURCE
      * 9) FILEADDLOCAL
@@ -1871,7 +1938,8 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
     override |= process_state_property(package, level, szAddLocal, INSTALLSTATE_LOCAL);
     override |= process_state_property(package, level, szRemove, INSTALLSTATE_ABSENT);
     override |= process_state_property(package, level, szAddSource, INSTALLSTATE_SOURCE);
-    override |= process_state_property(package, level, szReinstall, INSTALLSTATE_LOCAL);
+    override |= process_state_property(package, level, szReinstall, INSTALLSTATE_UNKNOWN);
+    override |= process_state_property(package, level, szAdvertise, INSTALLSTATE_ADVERTISED);
 
     if (!override)
     {
@@ -2033,7 +2101,7 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
 
 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
 {
-    MSIPACKAGE *package = (MSIPACKAGE*)param;
+    MSIPACKAGE *package = param;
     LPCWSTR name;
     LPWSTR path;
     MSIFOLDER *f;
@@ -2058,7 +2126,7 @@ static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
 
 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
 {
-    MSIPACKAGE *package = (MSIPACKAGE*)param;
+    MSIPACKAGE *package = param;
     LPCWSTR name;
     MSIFEATURE *feature;
 
@@ -2391,7 +2459,7 @@ static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
 
 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
 {
-    MSIPACKAGE *package = (MSIPACKAGE*)param;
+    MSIPACKAGE *package = param;
     static const WCHAR szHCR[] = 
         {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
          'R','O','O','T','\\',0};
@@ -2640,7 +2708,7 @@ static UINT ACTION_InstallValidate(MSIPACKAGE *package)
 
 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
 {
-    MSIPACKAGE* package = (MSIPACKAGE*)param;
+    MSIPACKAGE* package = param;
     LPCWSTR cond = NULL; 
     LPCWSTR message = NULL;
     UINT r;
@@ -3052,7 +3120,7 @@ static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
 
 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
 {
-    MSIPACKAGE* package = (MSIPACKAGE*)param;
+    MSIPACKAGE* package = param;
     LPCWSTR component;
     MSICOMPONENT *comp;
     MSIFILE *file;
@@ -3168,7 +3236,7 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
 
 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
 {
-    MSIPACKAGE *package = (MSIPACKAGE*)param;
+    MSIPACKAGE *package = param;
     LPWSTR target_file, target_folder, filename;
     LPCWSTR buffer, extension;
     MSICOMPONENT *comp;
@@ -3322,23 +3390,19 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
         return ERROR_SUCCESS;
 
     res = CoInitialize( NULL );
-    if (FAILED (res))
-    {
-        ERR("CoInitialize failed\n");
-        return ERROR_FUNCTION_FAILED;
-    }
 
     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
     msiobj_release(&view->hdr);
 
-    CoUninitialize();
+    if (SUCCEEDED(res))
+        CoUninitialize();
 
     return rc;
 }
 
 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
 {
-    MSIPACKAGE* package = (MSIPACKAGE*)param;
+    MSIPACKAGE* package = param;
     HANDLE the_file;
     LPWSTR FilePath;
     LPCWSTR FileName;
@@ -3503,9 +3567,6 @@ static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
     langid = msi_get_property_int(package, szProductLanguage, 0);
     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
 
-    ptr = strrchrW(package->PackagePath, '\\' ) + 1;
-    msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGENAMEW, ptr);
-
     /* FIXME */
     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
 
@@ -3668,7 +3729,7 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
     if (!msi_check_publish(package))
         return ERROR_SUCCESS;
 
-    rc = MSIREG_OpenProductKey(package->ProductCode, package->Context,
+    rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
                                &hukey, TRUE);
     if (rc != ERROR_SUCCESS)
         goto end;
@@ -3708,7 +3769,7 @@ end:
 
 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
 {
-    MSIPACKAGE *package = (MSIPACKAGE*)param;
+    MSIPACKAGE *package = param;
     LPCWSTR component, section, key, value, identifier, dirproperty;
     LPWSTR deformated_section, deformated_key, deformated_value;
     LPWSTR folder, filename, fullname = NULL;
@@ -3834,7 +3895,7 @@ static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
 
 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
 {
-    MSIPACKAGE *package = (MSIPACKAGE*)param;
+    MSIPACKAGE *package = param;
     LPCWSTR filename;
     LPWSTR FullName;
     MSIFILE *file;
@@ -4544,7 +4605,7 @@ static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
 
 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
 {
-    MSIPACKAGE *package = (MSIPACKAGE*)param;
+    MSIPACKAGE *package = param;
     LPCWSTR compgroupid=NULL;
     LPCWSTR feature=NULL;
     LPCWSTR text = NULL;
@@ -4640,7 +4701,7 @@ static UINT ACTION_PublishComponents(MSIPACKAGE *package)
 
 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
 {
-    MSIPACKAGE *package = (MSIPACKAGE*)param;
+    MSIPACKAGE *package = param;
     MSIRECORD *row;
     MSIFILE *file;
     SC_HANDLE hscm, service = NULL;
@@ -4781,7 +4842,7 @@ static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
 
 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
 {
-    MSIPACKAGE *package = (MSIPACKAGE *)param;
+    MSIPACKAGE *package = param;
     MSICOMPONENT *comp;
     SC_HANDLE scm, service = NULL;
     LPCWSTR name, *vector = NULL;
@@ -4894,7 +4955,7 @@ error:
 
 static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
 {
-    MSIPACKAGE *package = (MSIPACKAGE *)param;
+    MSIPACKAGE *package = param;
     MSICOMPONENT *comp;
     SERVICE_STATUS status;
     SERVICE_STATUS_PROCESS ssp;
@@ -4991,7 +5052,7 @@ static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
 
 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
 {
-    MSIPACKAGE *package = (MSIPACKAGE*)param;
+    MSIPACKAGE *package = param;
     LPWSTR driver, driver_path, ptr;
     WCHAR outpath[MAX_PATH];
     MSIFILE *driver_file, *setup_file;
@@ -5057,7 +5118,7 @@ static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
 
 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
 {
-    MSIPACKAGE *package = (MSIPACKAGE*)param;
+    MSIPACKAGE *package = param;
     LPWSTR translator, translator_path, ptr;
     WCHAR outpath[MAX_PATH];
     MSIFILE *translator_file, *setup_file;
@@ -5255,8 +5316,7 @@ static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
         }
     }
 
-    if (!*flags ||
-        check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
+    if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
         check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
         check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
         check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
@@ -5265,6 +5325,9 @@ static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
         return ERROR_FUNCTION_FAILED;
     }
 
+    if (!*flags)
+        *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
+
     return ERROR_SUCCESS;
 }
 
@@ -5292,6 +5355,8 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
     name = MSI_RecordGetString(rec, 2);
     value = MSI_RecordGetString(rec, 3);
 
+    TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
+
     res = env_set_flags(&name, &value, &flags);
     if (res != ERROR_SUCCESS)
        goto done;
@@ -5606,7 +5671,7 @@ static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
     {
         file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
 
-        msi_move_file((LPCWSTR)file->source, (LPCWSTR)file->dest, options);
+        msi_move_file(file->source, file->dest, options);
 
         list_remove(&file->entry);
         free_file_entry(file);
@@ -5866,7 +5931,7 @@ typedef struct tagASSEMBLY_NAME
 
 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
 {
-    ASSEMBLY_NAME *asmname = (ASSEMBLY_NAME *)param;
+    ASSEMBLY_NAME *asmname = param;
     LPCWSTR name = MSI_RecordGetString(rec, 2);
     LPWSTR val = msi_dup_record_field(rec, 3);
 
@@ -5876,13 +5941,13 @@ static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
     static const WCHAR PublicKeyToken[] = {
         'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
 
-    if (!lstrcmpW(name, Name))
+    if (!strcmpiW(name, Name))
         asmname->name = val;
-    else if (!lstrcmpW(name, Version))
+    else if (!strcmpiW(name, Version))
         asmname->version = val;
-    else if (!lstrcmpW(name, Culture))
+    else if (!strcmpiW(name, Culture))
         asmname->culture = val;
-    else if (!lstrcmpW(name, PublicKeyToken))
+    else if (!strcmpiW(name, PublicKeyToken))
         asmname->pubkeytoken = val;
     else
         msi_free(val);
@@ -5974,7 +6039,6 @@ static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache,
     found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
 
 done:
-    msiobj_release(&view->hdr);
     msi_free(disp);
     msi_free(name.name);
     msi_free(name.version);
@@ -5986,7 +6050,7 @@ done:
 
 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
 {
-    ASSEMBLY_LIST *list = (ASSEMBLY_LIST *)param;
+    ASSEMBLY_LIST *list = param;
     MSIASSEMBLY *assembly;
 
     assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
@@ -6015,9 +6079,24 @@ static UINT load_assembly(MSIRECORD *rec, LPVOID param)
     assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
     assembly->application = strdupW(MSI_RecordGetString(rec, 4));
     assembly->attributes = MSI_RecordGetInteger(rec, 5);
-    assembly->installed = check_assembly_installed(list->package->db,
-                                                   list->cache,
-                                                   assembly->component);
+
+    if (assembly->application)
+    {
+        WCHAR version[24];
+        DWORD size = sizeof(version)/sizeof(WCHAR);
+
+        /* FIXME: we should probably check the manifest file here */
+
+        if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
+            (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
+        {
+            assembly->installed = TRUE;
+        }
+    }
+    else
+        assembly->installed = check_assembly_installed(list->package->db,
+                                                       list->cache,
+                                                       assembly->component);
 
     list_add_head(list->assemblies, &assembly->entry);
     return ERROR_SUCCESS;
@@ -6091,7 +6170,7 @@ static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
 {
     MSIASSEMBLY *assembly;
     WCHAR temppath[MAX_PATH];
-    struct list *assemblies = (struct list *)user;
+    struct list *assemblies = user;
     UINT r;
 
     if (!find_assembly(assemblies, file, &assembly))