Sync to trunk (r44371)
[reactos.git] / reactos / dll / win32 / msi / action.c
index 6867e93..35a4d7f 100644 (file)
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
-/*
- * Prototypes
- */
-static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
-static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
-static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
-static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc, BOOL force);
-
 /*
  * consts and values used
  */
@@ -62,13 +54,8 @@ static const WCHAR szCreateFolders[] =
     {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
 static const WCHAR szCostFinalize[] =
     {'C','o','s','t','F','i','n','a','l','i','z','e',0};
-const WCHAR szInstallFiles[] =
-    {'I','n','s','t','a','l','l','F','i','l','e','s',0};
-const WCHAR szDuplicateFiles[] =
-    {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
 static const WCHAR szWriteRegistryValues[] =
-    {'W','r','i','t','e','R','e','g','i','s','t','r','y',
-            'V','a','l','u','e','s',0};
+    {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
 static const WCHAR szCostInitialize[] =
     {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
 static const WCHAR szFileCost[] = 
@@ -82,12 +69,7 @@ static const WCHAR szLaunchConditions[] =
 static const WCHAR szProcessComponents[] = 
     {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
 static const WCHAR szRegisterTypeLibraries[] = 
-    {'R','e','g','i','s','t','e','r','T','y','p','e',
-            'L','i','b','r','a','r','i','e','s',0};
-const WCHAR szRegisterClassInfo[] = 
-    {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
-const WCHAR szRegisterProgIdInfo[] = 
-    {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
+    {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
 static const WCHAR szCreateShortcuts[] = 
     {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
 static const WCHAR szPublishProduct[] = 
@@ -103,8 +85,7 @@ static const WCHAR szRegisterProduct[] =
 static const WCHAR szInstallExecute[] = 
     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
 static const WCHAR szInstallExecuteAgain[] = 
-    {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
-            'A','g','a','i','n',0};
+    {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
 static const WCHAR szInstallFinalize[] = 
     {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
 static const WCHAR szForceReboot[] = 
@@ -114,8 +95,7 @@ static const WCHAR szResolveSource[] =
 static const WCHAR szAppSearch[] = 
     {'A','p','p','S','e','a','r','c','h',0};
 static const WCHAR szAllocateRegistrySpace[] = 
-    {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
-            'S','p','a','c','e',0};
+    {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
 static const WCHAR szBindImage[] = 
     {'B','i','n','d','I','m','a','g','e',0};
 static const WCHAR szCCPSearch[] = 
@@ -126,58 +106,40 @@ static const WCHAR szDisableRollback[] =
     {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
 static const WCHAR szExecuteAction[] = 
     {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
-const WCHAR szFindRelatedProducts[] = 
-    {'F','i','n','d','R','e','l','a','t','e','d',
-            'P','r','o','d','u','c','t','s',0};
 static const WCHAR szInstallAdminPackage[] = 
-    {'I','n','s','t','a','l','l','A','d','m','i','n',
-            'P','a','c','k','a','g','e',0};
+    {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
 static const WCHAR szInstallSFPCatalogFile[] = 
-    {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
-            'F','i','l','e',0};
+    {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
 static const WCHAR szIsolateComponents[] = 
     {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
-const WCHAR szMigrateFeatureStates[] = 
-    {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
-            'S','t','a','t','e','s',0};
-const WCHAR szMoveFiles[] = 
+static const WCHAR szMigrateFeatureStates[] =
+    {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
+static const WCHAR szMoveFiles[] =
     {'M','o','v','e','F','i','l','e','s',0};
 static const WCHAR szMsiPublishAssemblies[] = 
-    {'M','s','i','P','u','b','l','i','s','h',
-            'A','s','s','e','m','b','l','i','e','s',0};
+    {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
 static const WCHAR szMsiUnpublishAssemblies[] = 
-    {'M','s','i','U','n','p','u','b','l','i','s','h',
-            'A','s','s','e','m','b','l','i','e','s',0};
+    {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
 static const WCHAR szInstallODBC[] = 
     {'I','n','s','t','a','l','l','O','D','B','C',0};
 static const WCHAR szInstallServices[] = 
     {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
-const WCHAR szPatchFiles[] = 
+static const WCHAR szPatchFiles[] =
     {'P','a','t','c','h','F','i','l','e','s',0};
 static const WCHAR szPublishComponents[] = 
     {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
 static const WCHAR szRegisterComPlus[] =
     {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
-const WCHAR szRegisterExtensionInfo[] =
-    {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
-            'I','n','f','o',0};
 static const WCHAR szRegisterFonts[] =
     {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
-const WCHAR szRegisterMIMEInfo[] =
-    {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
 static const WCHAR szRegisterUser[] =
     {'R','e','g','i','s','t','e','r','U','s','e','r',0};
-const WCHAR szRemoveDuplicateFiles[] =
-    {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
-            'F','i','l','e','s',0};
+static const WCHAR szRemoveDuplicateFiles[] =
+    {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
 static const WCHAR szRemoveEnvironmentStrings[] =
-    {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
-            'S','t','r','i','n','g','s',0};
-const WCHAR szRemoveExistingProducts[] =
-    {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
-            'P','r','o','d','u','c','t','s',0};
-const WCHAR szRemoveFiles[] =
-    {'R','e','m','o','v','e','F','i','l','e','s',0};
+    {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
+static const WCHAR szRemoveExistingProducts[] =
+    {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
 static const WCHAR szRemoveFolders[] =
     {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
 static const WCHAR szRemoveIniValues[] =
@@ -185,8 +147,7 @@ static const WCHAR szRemoveIniValues[] =
 static const WCHAR szRemoveODBC[] =
     {'R','e','m','o','v','e','O','D','B','C',0};
 static const WCHAR szRemoveRegistryValues[] =
-    {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
-            'V','a','l','u','e','s',0};
+    {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
 static const WCHAR szRemoveShortcuts[] =
     {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
 static const WCHAR szRMCCPSearch[] =
@@ -202,42 +163,27 @@ static const WCHAR szStartServices[] =
 static const WCHAR szStopServices[] =
     {'S','t','o','p','S','e','r','v','i','c','e','s',0};
 static const WCHAR szUnpublishComponents[] =
-    {'U','n','p','u','b','l','i','s','h',
-            'C','o','m','p','o','n','e','n','t','s',0};
+    {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
 static const WCHAR szUnpublishFeatures[] =
     {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
-const WCHAR szUnregisterClassInfo[] =
-    {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
-            'I','n','f','o',0};
+static const WCHAR szUnregisterClassInfo[] =
+    {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
 static const WCHAR szUnregisterComPlus[] =
     {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
-const WCHAR szUnregisterExtensionInfo[] =
-    {'U','n','r','e','g','i','s','t','e','r',
-            'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
+static const WCHAR szUnregisterExtensionInfo[] =
+    {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
 static const WCHAR szUnregisterFonts[] =
     {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
-const WCHAR szUnregisterMIMEInfo[] =
+static const WCHAR szUnregisterMIMEInfo[] =
     {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
-const WCHAR szUnregisterProgIdInfo[] =
-    {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
-            'I','n','f','o',0};
+static const WCHAR szUnregisterProgIdInfo[] =
+    {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
 static const WCHAR szUnregisterTypeLibraries[] =
-    {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
-            'L','i','b','r','a','r','i','e','s',0};
+    {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
 static const WCHAR szValidateProductID[] =
     {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
 static const WCHAR szWriteEnvironmentStrings[] =
-    {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
-            'S','t','r','i','n','g','s',0};
-
-/* action handlers */
-typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
-
-struct _actions {
-    LPCWSTR action;
-    STANDARDACTIONHANDLER handler;
-};
-
+    {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
 
 /********************************************************
  * helper functions
@@ -288,7 +234,8 @@ static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
     msiobj_release(&row->hdr);
 }
 
-UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
+UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
+                             BOOL preserve_case )
 {
     LPCWSTR ptr,ptr2;
     BOOL quote;
@@ -323,6 +270,10 @@ UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
         prop = msi_alloc((len+1)*sizeof(WCHAR));
         memcpy(prop,ptr,len*sizeof(WCHAR));
         prop[len]=0;
+
+        if (!preserve_case)
+            struprW(prop);
+
         ptr2++;
        
         len = 0; 
@@ -396,9 +347,11 @@ 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 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 );
@@ -406,12 +359,56 @@ 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;
+    {
+        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, szZero )))
+        {
+            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;
 }
@@ -447,13 +444,12 @@ 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;
     UINT i, ret = ERROR_FUNCTION_FAILED;
 
-    product_code = msi_dup_property( package, szProdCode );
+    product_code = msi_dup_property( package, szProductCode );
     if (!product_code)
     {
         /* FIXME: the property ProductCode should be written into the DB somewhere */
@@ -475,6 +471,43 @@ static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si
     return ret;
 }
 
+static UINT msi_set_media_source_prop(MSIPACKAGE *package)
+{
+    MSIQUERY *view;
+    MSIRECORD *rec = NULL;
+    LPWSTR patch;
+    LPCWSTR prop;
+    UINT r;
+
+    static const WCHAR query[] = {'S','E','L','E','C','T',' ',
+        '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
+        '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
+        '`','S','o','u','r','c','e','`',' ','I','S',' ',
+        'N','O','T',' ','N','U','L','L',0};
+
+    r = MSI_DatabaseOpenViewW(package->db, query, &view);
+    if (r != ERROR_SUCCESS)
+        return r;
+
+    r = MSI_ViewExecute(view, 0);
+    if (r != ERROR_SUCCESS)
+        goto done;
+
+    if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
+    {
+        prop = MSI_RecordGetString(rec, 1);
+        patch = msi_dup_property(package, szPatch);
+        MSI_SetPropertyW(package, prop, patch);
+        msi_free(patch);
+    }
+
+done:
+    if (rec) msiobj_release(&rec->hdr);
+    msiobj_release(&view->hdr);
+
+    return r;
+}
+
 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
 {
     MSISUMMARYINFO *si;
@@ -485,20 +518,33 @@ static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db
     if (!si)
         return ERROR_FUNCTION_FAILED;
 
-    msi_check_patch_applicable( package, si );
+    if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
+    {
+        TRACE("Patch not applicable\n");
+        return ERROR_SUCCESS;
+    }
+
+    package->patch = msi_alloc(sizeof(MSIPATCHINFO));
+    if (!package->patch)
+        return ERROR_OUTOFMEMORY;
+
+    package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
+    if (!package->patch->patchcode)
+        return ERROR_OUTOFMEMORY;
 
     /* enumerate the substorage */
     str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
+    package->patch->transforms = str;
+
     substorage = msi_split_string( str, ';' );
     for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
         r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
-    msi_free( substorage );
-    msi_free( str );
-
-    /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
 
+    msi_free( substorage );
     msiobj_release( &si->hdr );
 
+    msi_set_media_source_prop(package);
+
     return r;
 }
 
@@ -537,7 +583,6 @@ static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
 /* get the PATCH property, and apply all the patches it specifies */
 static UINT msi_apply_patches( MSIPACKAGE *package )
 {
-    static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
     LPWSTR patch_list, *patches;
     UINT i, r = ERROR_SUCCESS;
 
@@ -648,167 +693,38 @@ static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
     return ERROR_SUCCESS;
 }
 
-/****************************************************
- * TOP level entry points 
- *****************************************************/
-
-UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
-                         LPCWSTR szCommandLine )
+static BOOL needs_ui_sequence(MSIPACKAGE *package)
 {
-    UINT rc;
-    BOOL ui = FALSE, ui_exists;
-    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};
-
-    MSI_SetPropertyW(package, szAction, szInstall);
-
-    package->script = msi_alloc_zero(sizeof(MSISCRIPT));
-
-    package->script->InWhatSequence = SEQUENCE_INSTALL;
-
-    if (szPackagePath)   
-    {
-        LPWSTR p, dir;
-        LPCWSTR file;
-
-        dir = strdupW(szPackagePath);
-        p = strrchrW(dir, '\\');
-        if (p)
-        {
-            *(++p) = 0;
-            file = szPackagePath + (p - dir);
-        }
-        else
-        {
-            msi_free(dir);
-            dir = msi_alloc(MAX_PATH*sizeof(WCHAR));
-            GetCurrentDirectoryW(MAX_PATH, dir);
-            lstrcatW(dir, cszbs);
-            file = szPackagePath;
-        }
-
-        msi_free( package->PackagePath );
-        package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
-        if (!package->PackagePath)
-        {
-            msi_free(dir);
-            return ERROR_OUTOFMEMORY;
-        }
-
-        lstrcpyW(package->PackagePath, dir);
-        lstrcatW(package->PackagePath, file);
-        msi_free(dir);
-
-        msi_set_sourcedir_props(package, FALSE);
-    }
-
-    msi_parse_command_line( package, szCommandLine );
-
-    msi_apply_transforms( package );
-    msi_apply_patches( package );
-
-    /* properties may have been added by a transform */
-    msi_clone_properties( package );
-
-    if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED )
-    {
-        package->script->InWhatSequence |= SEQUENCE_UI;
-        rc = ACTION_ProcessUISequence(package);
-        ui = TRUE;
-        ui_exists = ui_sequence_exists(package);
-        if (rc == ERROR_SUCCESS || !ui_exists)
-        {
-            package->script->InWhatSequence |= SEQUENCE_EXEC;
-            rc = ACTION_ProcessExecSequence(package,ui_exists);
-        }
-    }
-    else
-        rc = ACTION_ProcessExecSequence(package,FALSE);
-
-    package->script->CurrentlyScripting= FALSE;
-
-    /* process the ending type action */
-    if (rc == ERROR_SUCCESS)
-        ACTION_PerformActionSequence(package,-1,ui);
-    else if (rc == ERROR_INSTALL_USEREXIT) 
-        ACTION_PerformActionSequence(package,-2,ui);
-    else if (rc == ERROR_INSTALL_SUSPEND) 
-        ACTION_PerformActionSequence(package,-4,ui);
-    else  /* failed */
-        ACTION_PerformActionSequence(package,-3,ui);
-
-    /* finish up running custom actions */
-    ACTION_FinishCustomActions(package);
-    
-    return rc;
+    INT level = msi_get_property_int(package, szUILevel, 0);
+    return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
 }
 
-static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
+static UINT msi_set_context(MSIPACKAGE *package)
 {
-    UINT rc = ERROR_SUCCESS;
-    MSIRECORD * row = 0;
-    static const WCHAR ExecSeqQuery[] =
-        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-         '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
-         'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
-         '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
-
-    static const WCHAR UISeqQuery[] =
-        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-     '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
-     '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
-        ' ', '=',' ','%','i',0};
+    WCHAR val[10];
+    DWORD sz = 10;
+    DWORD num;
+    UINT r;
 
-    if (UI)
-        row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
-    else
-        row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
+    package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
 
-    if (row)
+    r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
+    if (r == ERROR_SUCCESS)
     {
-        LPCWSTR action, cond;
-
-        TRACE("Running the actions\n"); 
-
-        /* check conditions */
-        cond = MSI_RecordGetString(row,2);
-
-        /* this is a hack to skip errors in the condition code */
-        if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
-            goto end;
-
-        action = MSI_RecordGetString(row,1);
-        if (!action)
-        {
-            ERR("failed to fetch action\n");
-            rc = ERROR_FUNCTION_FAILED;
-            goto end;
-        }
-
-        if (UI)
-            rc = ACTION_PerformUIAction(package,action,-1);
-        else
-            rc = ACTION_PerformAction(package,action,-1,FALSE);
-end:
-        msiobj_release(&row->hdr);
+        num = atolW(val);
+        if (num == 1 || num == 2)
+            package->Context = MSIINSTALLCONTEXT_MACHINE;
     }
-    else
-        rc = ERROR_SUCCESS;
 
-    return rc;
+    MSI_SetPropertyW(package, szAllUsers, szOne);
+    return ERROR_SUCCESS;
 }
 
-typedef struct {
-    MSIPACKAGE* package;
-    BOOL UI;
-} iterate_action_param;
-
 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
 {
-    iterate_action_param *iap= (iterate_action_param*)param;
     UINT rc;
     LPCWSTR cond, action;
+    MSIPACKAGE *package = param;
 
     action = MSI_RecordGetString(row,1);
     if (!action)
@@ -821,21 +737,21 @@ static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
     cond = MSI_RecordGetString(row,2);
 
     /* this is a hack to skip errors in the condition code */
-    if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
+    if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
     {
         TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
         return ERROR_SUCCESS;
     }
 
-    if (iap->UI)
-        rc = ACTION_PerformUIAction(iap->package,action,-1);
+    if (needs_ui_sequence(package))
+        rc = ACTION_PerformUIAction(package, action, -1);
     else
-        rc = ACTION_PerformAction(iap->package,action,-1,FALSE);
+        rc = ACTION_PerformAction(package, action, -1, FALSE);
 
     msi_dialog_check_messages( NULL );
 
-    if (iap->package->CurrentInstallState != ERROR_SUCCESS )
-        rc = iap->package->CurrentInstallState;
+    if (package->CurrentInstallState != ERROR_SUCCESS)
+        rc = package->CurrentInstallState;
 
     if (rc == ERROR_FUNCTION_NOT_CALLED)
         rc = ERROR_SUCCESS;
@@ -857,23 +773,13 @@ UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
          '`','S','e','q','u','e','n','c','e','`',' ',
          '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
          '`','S','e','q','u','e','n','c','e','`',0};
-    iterate_action_param iap;
-
-    /*
-     * FIXME: probably should be checking UILevel in the
-     *       ACTION_PerformUIAction/ACTION_PerformAction
-     *       rather than saving the UI level here. Those
-     *       two functions can be merged too.
-     */
-    iap.package = package;
-    iap.UI = TRUE;
 
     TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
 
     r = MSI_OpenQuery( package->db, &view, query, szTable );
     if (r == ERROR_SUCCESS)
     {
-        r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
+        r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
         msiobj_release(&view->hdr);
     }
 
@@ -891,7 +797,6 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
          '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
          'O','R','D','E','R',' ', 'B','Y',' ',
          '`','S','e','q','u','e','n','c','e','`',0 };
-    MSIRECORD * row = 0;
     static const WCHAR IVQuery[] =
         {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
          ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
@@ -900,10 +805,6 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
          ' ','\'', 'I','n','s','t','a','l','l',
          'V','a','l','i','d','a','t','e','\'', 0};
     INT seq = 0;
-    iterate_action_param iap;
-
-    iap.package = package;
-    iap.UI = FALSE;
 
     if (package->script->ExecuteSequenceRun)
     {
@@ -916,7 +817,7 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
     /* get the sequence number */
     if (UIran)
     {
-        row = MSI_QueryGetRecord(package->db, IVQuery);
+        MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
         if( !row )
             return ERROR_FUNCTION_FAILED;
         seq = MSI_RecordGetInteger(row,1);
@@ -928,7 +829,7 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
     {
         TRACE("Running the actions\n");
 
-        rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
+        rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
         msiobj_release(&view->hdr);
     }
 
@@ -947,18 +848,13 @@ static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
          '`','S','e','q','u','e','n','c','e','`',' ',
          '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
          '`','S','e','q','u','e','n','c','e','`',0};
-    iterate_action_param iap;
-
-    iap.package = package;
-    iap.UI = TRUE;
 
     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
-    
     if (rc == ERROR_SUCCESS)
     {
         TRACE("Running the actions\n"); 
 
-        rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
+        rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
         msiobj_release(&view->hdr);
     }
 
@@ -984,67 +880,13 @@ static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
     return ret;
 }
 
-/* 
- * A lot of actions are really important even if they don't do anything
- * explicit... Lots of properties are set at the beginning of the installation
- * CostFinalize does a bunch of work to translate the directories and such
- * 
- * But until I get write access to the database that is hard, so I am going to
- * hack it to see if I can get something to run.
- */
-UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
-{
-    UINT rc = ERROR_SUCCESS; 
-    BOOL handled;
-
-    TRACE("Performing action (%s)\n",debugstr_w(action));
-
-    handled = ACTION_HandleStandardAction(package, action, &rc, force);
-
-    if (!handled)
-        handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
-
-    if (!handled)
-    {
-        WARN("unhandled msi action %s\n",debugstr_w(action));
-        rc = ERROR_FUNCTION_NOT_CALLED;
-    }
-
-    return rc;
-}
-
-UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
-{
-    UINT rc = ERROR_SUCCESS;
-    BOOL handled = FALSE;
-
-    TRACE("Performing action (%s)\n",debugstr_w(action));
-
-    handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
-
-    if (!handled)
-        handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
-
-    if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
-        handled = TRUE;
-
-    if (!handled)
-    {
-        WARN("unhandled msi action %s\n",debugstr_w(action));
-        rc = ERROR_FUNCTION_NOT_CALLED;
-    }
-
-    return rc;
-}
-
-
 /*
  * Actual Action Handlers
  */
 
 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
 {
-    MSIPACKAGE *package = (MSIPACKAGE*)param;
+    MSIPACKAGE *package = param;
     LPCWSTR dir;
     LPWSTR full_path;
     MSIRECORD *uirow;
@@ -1168,7 +1010,7 @@ static UINT load_component( MSIRECORD *row, LPVOID param )
     comp->KeyPath = msi_dup_record_field( row, 6 );
 
     comp->Installed = INSTALLSTATE_UNKNOWN;
-    msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
+    msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
 
     return ERROR_SUCCESS;
 }
@@ -1226,7 +1068,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;
 
@@ -1264,7 +1106,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',' ',
@@ -1302,7 +1144,7 @@ static UINT load_feature(MSIRECORD * row, LPVOID param)
     feature->Attributes = MSI_RecordGetInteger(row,8);
 
     feature->Installed = INSTALLSTATE_UNKNOWN;
-    msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
+    msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
 
     list_add_tail( &package->features, &feature->entry );
 
@@ -1323,7 +1165,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 ) );
@@ -1416,7 +1258,7 @@ done:
 
 static UINT load_file(MSIRECORD *row, LPVOID param)
 {
-    MSIPACKAGE* package = (MSIPACKAGE*)param;
+    MSIPACKAGE* package = param;
     LPCWSTR component;
     MSIFILE *file;
 
@@ -1432,7 +1274,12 @@ static UINT load_file(MSIRECORD *row, LPVOID param)
     file->Component = get_loaded_component( package, component );
 
     if (!file->Component)
-        ERR("Unfound Component %s\n",debugstr_w(component));
+    {
+        WARN("Component not found: %s\n", debugstr_w(component));
+        msi_free(file->File);
+        msi_free(file);
+        return ERROR_SUCCESS;
+    }
 
     file->FileName = msi_dup_record_field( row, 3 );
     reduce_to_longfilename( file->FileName );
@@ -1451,7 +1298,12 @@ static UINT load_file(MSIRECORD *row, LPVOID param)
     /* if the compressed bits are not set in the file attributes,
      * then read the information from the package word count property
      */
-    if (file->Attributes & msidbFileAttributesCompressed)
+    if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
+    {
+        file->IsCompressed = FALSE;
+    }
+    else if (file->Attributes &
+             (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
     {
         file->IsCompressed = TRUE;
     }
@@ -1461,7 +1313,7 @@ static UINT load_file(MSIRECORD *row, LPVOID param)
     }
     else
     {
-        file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
+        file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
     }
 
     load_file_hash(package, file);
@@ -1498,7 +1350,6 @@ static UINT load_all_files(MSIPACKAGE *package)
 static UINT load_folder( MSIRECORD *row, LPVOID param )
 {
     MSIPACKAGE *package = param;
-    static const WCHAR szDot[] = { '.',0 };
     static WCHAR szEmpty[] = { 0 };
     LPWSTR p, tgt_short, tgt_long, src_short, src_long;
     MSIFOLDER *folder;
@@ -1596,15 +1447,14 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package)
 {
     static const WCHAR szCosting[] =
         {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
-    static const WCHAR szZero[] = { '0', 0 };
 
     MSI_SetPropertyW(package, szCosting, szZero);
     MSI_SetPropertyW(package, cszRootDrive, c_colon);
 
+    load_all_folders( package );
     load_all_components( package );
     load_all_features( package );
     load_all_files( package );
-    load_all_folders( package );
 
     return ERROR_SUCCESS;
 }
@@ -1644,65 +1494,51 @@ static UINT ACTION_FileCost(MSIPACKAGE *package)
 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
 {
     MSICOMPONENT *comp;
+    INSTALLSTATE state;
+    UINT r;
 
-    LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
-    {
-        INSTALLSTATE res;
+    state = MsiQueryProductStateW(package->ProductCode);
 
+    LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
+    {
         if (!comp->ComponentId)
             continue;
 
-        res = MsiGetComponentPathW( package->ProductCode,
-                                    comp->ComponentId, NULL, NULL);
-        if (res < 0)
-            res = INSTALLSTATE_ABSENT;
-        comp->Installed = res;
+        if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
+            comp->Installed = INSTALLSTATE_ABSENT;
+        else
+        {
+            r = MsiQueryComponentStateW(package->ProductCode, NULL,
+                                        package->Context, comp->ComponentId,
+                                        &comp->Installed);
+            if (r != ERROR_SUCCESS)
+                comp->Installed = INSTALLSTATE_ABSENT;
+        }
     }
 }
 
-/* scan for and update current install states */
-static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
+static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
 {
-    MSICOMPONENT *comp;
     MSIFEATURE *feature;
+    INSTALLSTATE state;
+
+    state = MsiQueryProductStateW(package->ProductCode);
 
     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
-        ComponentList *cl;
-        INSTALLSTATE res = INSTALLSTATE_ABSENT;
-
-        LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
+        if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
+            feature->Installed = INSTALLSTATE_ABSENT;
+        else
         {
-            comp= cl->component;
-
-            if (!comp->ComponentId)
-            {
-                res = INSTALLSTATE_ABSENT;
-                break;
-            }
-
-            if (res == INSTALLSTATE_ABSENT)
-                res = comp->Installed;
-            else
-            {
-                if (res == comp->Installed)
-                    continue;
-
-                if (res != INSTALLSTATE_DEFAULT && res != INSTALLSTATE_LOCAL &&
-                    res != INSTALLSTATE_SOURCE)
-                {
-                    res = INSTALLSTATE_INCOMPLETE;
-                }
-            }
+            feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
+                                                       feature->Feature);
         }
-        feature->Installed = res;
     }
 }
 
-static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property, 
-                                    INSTALLSTATE state)
+static BOOL process_state_property(MSIPACKAGE* package, int level,
+                                   LPCWSTR property, INSTALLSTATE state)
 {
-    static const WCHAR all[]={'A','L','L',0};
     LPWSTR override;
     MSIFEATURE *feature;
 
@@ -1712,8 +1548,14 @@ static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
 
     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
-        if (strcmpiW(override,all)==0)
-            msi_feature_set_state( feature, state );
+        if (lstrcmpW(property, szRemove) &&
+            (feature->Level <= 0 || feature->Level > level))
+            continue;
+
+        if (!strcmpW(property, szReinstall)) state = feature->Installed;
+
+        if (strcmpiW(override, szAll)==0)
+            msi_feature_set_state(package, feature, state);
         else
         {
             LPWSTR ptr = override;
@@ -1724,7 +1566,7 @@ static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
                 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
                     || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
                 {
-                    msi_feature_set_state( feature, state );
+                    msi_feature_set_state(package, feature, state);
                     break;
                 }
                 if (ptr2)
@@ -1744,17 +1586,15 @@ static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
 
 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
 {
-    int install_level;
+    int level;
     static const WCHAR szlevel[] =
         {'I','N','S','T','A','L','L','L','E','V','E','L',0};
     static const WCHAR szAddLocal[] =
         {'A','D','D','L','O','C','A','L',0};
     static const WCHAR szAddSource[] =
         {'A','D','D','S','O','U','R','C','E',0};
-    static const WCHAR szRemove[] =
-        {'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;
@@ -1764,50 +1604,49 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
 
     TRACE("Checking Install Level\n");
 
-    install_level = msi_get_property_int( package, szlevel, 1 );
+    level = msi_get_property_int(package, szlevel, 1);
 
     /* 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
      * 10) FILEADDSOURCE
      * 11) FILEADDDEFAULT
-     * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
-     * ignored for all the features. seems strange, especially since it is not
-     * documented anywhere, but it is how it works.
      *
      * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
      * REMOVE are the big ones, since we don't handle administrative installs
      * yet anyway.
      */
-    override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
-    override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
-    override |= process_state_property(package,szAddSource,INSTALLSTATE_SOURCE);
-    override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
+    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_UNKNOWN);
+    override |= process_state_property(package, level, szAdvertise, INSTALLSTATE_ADVERTISED);
 
     if (!override)
     {
         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
         {
             BOOL feature_state = ((feature->Level > 0) &&
-                             (feature->Level <= install_level));
+                                  (feature->Level <= level));
 
             if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
             {
                 if (feature->Attributes & msidbFeatureAttributesFavorSource)
-                    msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
+                    msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
                 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
-                    msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
+                    msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
                 else
-                    msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
+                    msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
             }
         }
 
@@ -1816,21 +1655,15 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
         {
             FeatureList *fl;
 
-            if (feature->Level > 0 && feature->Level <= install_level)
+            if (feature->Level > 0 && feature->Level <= level)
                 continue;
 
             LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
-                msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
+                msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
         }
     }
     else
-    {
-        /* set the Preselected Property */
-        static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
-        static const WCHAR szOne[] = { '1', 0 };
-
-        MSI_SetPropertyW(package,szPreselected,szOne);
-    }
+        MSI_SetPropertyW(package, szPreselected, szOne);
 
     /*
      * now we want to enable or disable components base on feature
@@ -1840,8 +1673,11 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
     {
         ComponentList *cl;
 
-        TRACE("Examining Feature %s (Installed %i, Action %i)\n",
-              debugstr_w(feature->Feature), feature->Installed, feature->Action);
+        TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
+              debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
+
+        if (!feature->Level)
+            continue;
 
         /* features with components that have compressed files are made local */
         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
@@ -1850,7 +1686,7 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
                 cl->component->ForceLocalState &&
                 feature->Action == INSTALLSTATE_SOURCE)
             {
-                msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
+                msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
                 break;
             }
         }
@@ -1902,34 +1738,34 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
         {
             if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
                  !component->ForceLocalState)
-                msi_component_set_state( component, INSTALLSTATE_SOURCE );
+                msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
             else
-                msi_component_set_state( component, INSTALLSTATE_LOCAL );
+                msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
             continue;
         }
 
         /* if any feature is local, the component must be local too */
         if (component->hasLocalFeature)
         {
-            msi_component_set_state( component, INSTALLSTATE_LOCAL );
+            msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
             continue;
         }
 
         if (component->hasSourceFeature)
         {
-            msi_component_set_state( component, INSTALLSTATE_SOURCE );
+            msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
             continue;
         }
 
         if (component->hasAdvertiseFeature)
         {
-            msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
+            msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
             continue;
         }
 
         TRACE("nobody wants component %s\n", debugstr_w(component->Component));
         if (component->anyAbsent)
-            msi_component_set_state(component, INSTALLSTATE_ABSENT);
+            msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
     }
 
     LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
@@ -1937,7 +1773,7 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
         if (component->Action == INSTALLSTATE_DEFAULT)
         {
             TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
-            msi_component_set_state( component, INSTALLSTATE_LOCAL );
+            msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
         }
 
         TRACE("Result: Component %s (Installed %i, Action %i)\n",
@@ -1950,7 +1786,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;
@@ -1975,7 +1811,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;
 
@@ -2003,7 +1839,7 @@ static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
 {
     static const WCHAR name_fmt[] =
         {'%','u','.','%','u','.','%','u','.','%','u',0};
-    static WCHAR name[] = {'\\',0};
+    static const WCHAR name[] = {'\\',0};
     VS_FIXEDFILEINFO *lpVer;
     WCHAR filever[0x100];
     LPVOID version;
@@ -2080,7 +1916,6 @@ static UINT msi_check_file_install_states( MSIPACKAGE *package )
         {
             file->state = msifs_missing;
             comp->Cost += file->FileSize;
-            comp->Installed = INSTALLSTATE_INCOMPLETE;
             continue;
         }
 
@@ -2094,7 +1929,6 @@ static UINT msi_check_file_install_states( MSIPACKAGE *package )
             {
                 file->state = msifs_overwrite;
                 comp->Cost += file->FileSize;
-                comp->Installed = INSTALLSTATE_INCOMPLETE;
             }
             else
                 file->state = msifs_present;
@@ -2127,16 +1961,11 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
         {'I','N','S','T','A','L','L','L','E','V','E','L',0};
     static const WCHAR szOutOfDiskSpace[] =
         {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
-    static const WCHAR szOne[] = { '1', 0 };
-    static const WCHAR szZero[] = { '0', 0 };
     MSICOMPONENT *comp;
     UINT rc;
     MSIQUERY * view;
     LPWSTR level;
 
-    if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
-        return ERROR_SUCCESS;
-
     TRACE("Building Directory properties\n");
 
     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
@@ -2149,6 +1978,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
 
     /* read components states from the registry */
     ACTION_GetComponentInstallStates(package);
+    ACTION_GetFeatureInstallStates(package);
 
     TRACE("File calculations\n");
     msi_check_file_install_states( package );
@@ -2171,6 +2001,8 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
             TRACE("Disabling component %s\n", debugstr_w(comp->Component));
             comp->Enabled = FALSE;
         }
+        else
+            comp->Enabled = TRUE;
     }
 
     MSI_SetPropertyW(package,szCosting,szOne);
@@ -2183,8 +2015,6 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
     /* FIXME: check volume disk space */
     MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
 
-    ACTION_UpdateFeatureInstallStates(package);
-
     return MSI_SetFeatureStates(package);
 }
 
@@ -2312,7 +2142,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};
@@ -2381,8 +2211,7 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
     {
         case -1: 
             {
-                static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
-                LPWSTR all_users = msi_dup_property( package, szALLUSER );
+                LPWSTR all_users = msi_dup_property( package, szAllUsers );
                 if (all_users && all_users[0] == '1')
                 {
                     root_key = HKEY_LOCAL_MACHINE;
@@ -2437,7 +2266,6 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
         value_data = parse_value(package, value, &type, &size); 
     else
     {
-        static const WCHAR szEmpty[] = {0};
         value_data = (LPSTR)strdupW(szEmpty);
         size = sizeof(szEmpty);
         type = REG_SZ;
@@ -2561,7 +2389,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;
@@ -2790,29 +2618,16 @@ static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
         ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
 }
 
-/*
- * Ok further analysis makes me think that this work is
- * actually done in the PublishComponents and PublishFeatures
- * step, and not here.  It appears like the keypath and all that is
- * resolved in this step, however actually written in the Publish steps.
- * But we will leave it here for now because it is unclear
- */
 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
 {
     WCHAR squished_pc[GUID_SIZE];
     WCHAR squished_cc[GUID_SIZE];
     UINT rc;
     MSICOMPONENT *comp;
-    HKEY hkey=0,hkey2=0;
+    HKEY hkey;
 
     TRACE("\n");
 
-    /* writes the Component and Features values to the registry */
-
-    rc = MSIREG_OpenComponents(&hkey);
-    if (rc != ERROR_SUCCESS)
-        return rc;
-
     squash_guid(package->ProductCode,squished_pc);
     ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
 
@@ -2829,7 +2644,6 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
         msi_free(comp->FullKeypath);
         comp->FullKeypath = resolve_keypath( package, comp );
 
-        /* do the refcounting */
         ACTION_RefCountComponent( package, comp );
 
         TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
@@ -2837,20 +2651,22 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
                             debugstr_w(squished_cc),
                             debugstr_w(comp->FullKeypath),
                             comp->RefCount);
-        /*
-         * Write the keypath out if the component is to be registered
-         * and delete the key if the component is to be unregistered
-         */
-        if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
-        {
-            rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
-            if (rc != ERROR_SUCCESS)
-                continue;
 
+        if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL) ||
+            ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE))
+        {
             if (!comp->FullKeypath)
                 continue;
 
-            msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
+            if (package->Context == MSIINSTALLCONTEXT_MACHINE)
+                rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
+                                                     &hkey, TRUE);
+            else
+                rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
+                                                     &hkey, TRUE);
+
+            if (rc != ERROR_SUCCESS)
+                continue;
 
             if (comp->Attributes & msidbComponentAttributesPermanent)
             {
@@ -2859,35 +2675,56 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
                       '0','0','0','0','0','0','0','0','0','0','0','0',
                       '0','0','0','0','0','0','0','0',0 };
 
-                msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
+                msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
             }
 
-            RegCloseKey(hkey2);
-
-            rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, &hkey2, TRUE);
-            if (rc != ERROR_SUCCESS)
-                continue;
-
-            msi_reg_set_val_str(hkey2, squished_pc, comp->FullKeypath);
-            RegCloseKey(hkey2);
-        }
-        else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
-        {
-            DWORD res;
+            if (comp->Action == INSTALLSTATE_LOCAL)
+                msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
+            else
+            {
+                MSIFILE *file;
+                MSIRECORD *row;
+                LPWSTR ptr, ptr2;
+                WCHAR source[MAX_PATH];
+                WCHAR base[MAX_PATH];
+                LPWSTR sourcepath;
+
+                static const WCHAR fmt[] = {'%','0','2','d','\\',0};
+                static const WCHAR query[] = {
+                    'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
+                    '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
+                    '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
+                    '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
+                    '`','D','i','s','k','I','d','`',0};
+
+                file = get_loaded_file(package, comp->KeyPath);
+                if (!file)
+                    continue;
 
-            rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
-            if (rc != ERROR_SUCCESS)
-                continue;
+                row = MSI_QueryGetRecord(package->db, query, file->Sequence);
+                sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
+                ptr2 = strrchrW(source, '\\') + 1;
+                msiobj_release(&row->hdr);
 
-            RegDeleteValueW(hkey2,squished_pc);
+                lstrcpyW(base, package->PackagePath);
+                ptr = strrchrW(base, '\\');
+                *(ptr + 1) = '\0';
 
-            /* if the key is empty delete it */
-            res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
-            RegCloseKey(hkey2);
-            if (res == ERROR_NO_MORE_ITEMS)
-                RegDeleteKeyW(hkey,squished_cc);
+                sourcepath = resolve_file_source(package, file);
+                ptr = sourcepath + lstrlenW(base);
+                lstrcpyW(ptr2, ptr);
+                msi_free(sourcepath);
 
-            MSIREG_DeleteUserDataComponentKey(comp->ComponentId);
+                msi_reg_set_val_str(hkey, squished_pc, source);
+            }
+            RegCloseKey(hkey);
+        }
+        else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT))
+        {
+            if (package->Context == MSIINSTALLCONTEXT_MACHINE)
+                MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
+            else
+                MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
         }
 
         /* UI stuff */
@@ -2898,8 +2735,8 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
         ui_actiondata(package,szProcessComponents,uirow);
         msiobj_release( &uirow->hdr );
     }
-    RegCloseKey(hkey);
-    return rc;
+
+    return ERROR_SUCCESS;
 }
 
 typedef struct {
@@ -2938,7 +2775,7 @@ static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
 
     TRACE("trying %s\n", debugstr_w(tl_struct->path));
     res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
-    if (!SUCCEEDED(res))
+    if (FAILED(res))
     {
         msi_free(tl_struct->path);
         tl_struct->path = NULL;
@@ -2964,12 +2801,15 @@ 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;
     typelib_struct tl_struct;
+    ITypeLib *tlib;
     HMODULE module;
+    HRESULT hr;
+
     static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
 
     component = MSI_RecordGetString(row,3);
@@ -3017,7 +2857,7 @@ static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
             res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
             msi_free(help);
 
-            if (!SUCCEEDED(res))
+            if (FAILED(res))
                 ERR("Failed to register type library %s\n",
                         debugstr_w(tl_struct.path));
             else
@@ -3038,7 +2878,16 @@ static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
         msi_free(tl_struct.source);
     }
     else
-        ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
+    {
+        hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
+        if (FAILED(hr))
+        {
+            ERR("Failed to load type library: %08x\n", hr);
+            return ERROR_FUNCTION_FAILED;
+        }
+
+        ITypeLib_Release(tlib);
+    }
 
     return ERROR_SUCCESS;
 }
@@ -3068,7 +2917,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;
@@ -3222,23 +3071,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_PublishProduct(MSIRECORD *row, LPVOID param)
+static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
 {
-    MSIPACKAGE* package = (MSIPACKAGE*)param;
+    MSIPACKAGE* package = param;
     HANDLE the_file;
     LPWSTR FilePath;
     LPCWSTR FileName;
@@ -3295,230 +3140,323 @@ static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
     return ERROR_SUCCESS;
 }
 
-static BOOL msi_check_publish(MSIPACKAGE *package)
+static UINT msi_publish_icons(MSIPACKAGE *package)
 {
-    MSIFEATURE *feature;
+    UINT r;
+    MSIQUERY *view;
 
-    LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
+    static const WCHAR query[]= {
+        'S','E','L','E','C','T',' ','*',' ',
+        'F','R','O','M',' ','`','I','c','o','n','`',0};
+
+    r = MSI_DatabaseOpenViewW(package->db, query, &view);
+    if (r == ERROR_SUCCESS)
     {
-        if (feature->ActionRequest == INSTALLSTATE_LOCAL)
-            return TRUE;
+        MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
+        msiobj_release(&view->hdr);
     }
 
-    return FALSE;
+    return ERROR_SUCCESS;
 }
 
-/*
- * 99% of the work done here is only done for 
- * advertised installs. However this is where the
- * Icon table is processed and written out
- * so that is what I am going to do here.
- */
-static UINT ACTION_PublishProduct(MSIPACKAGE *package)
+static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
 {
-    UINT rc;
-    LPWSTR packname;
-    MSIQUERY * view;
-    MSISOURCELISTINFO *info;
-    MSIMEDIADISK *disk;
-    static const WCHAR Query[]=
-        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-         '`','I','c','o','n','`',0};
-    /* for registry stuff */
-    HKEY hkey=0;
-    HKEY hukey=0;
-    HKEY hudkey=0, props=0;
+    UINT r;
     HKEY source;
-    static const WCHAR szProductLanguage[] =
-        {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
-    static const WCHAR szARPProductIcon[] =
-        {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
-    static const WCHAR szProductVersion[] =
-        {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
-    static const WCHAR szSourceList[] =
-        {'S','o','u','r','c','e','L','i','s','t',0};
-    static const WCHAR szEmpty[] = {0};
-    DWORD langid;
     LPWSTR buffer;
-    DWORD size;
-    MSIHANDLE hDb, hSumInfo;
+    MSIMEDIADISK *disk;
+    MSISOURCELISTINFO *info;
 
-    /* FIXME: also need to publish if the product is in advertise mode */
-    if (!msi_check_publish(package))
-        return ERROR_SUCCESS;
+    r = RegCreateKeyW(hkey, szSourceList, &source);
+    if (r != ERROR_SUCCESS)
+        return r;
+
+    RegCloseKey(source);
 
-    /* write out icon files */
+    buffer = strrchrW(package->PackagePath, '\\') + 1;
+    r = MsiSourceListSetInfoW(package->ProductCode, NULL,
+                              package->Context, MSICODE_PRODUCT,
+                              INSTALLPROPERTY_PACKAGENAMEW, buffer);
+    if (r != ERROR_SUCCESS)
+        return r;
 
-    rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
-    if (rc == ERROR_SUCCESS)
-    {
-        MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
-        msiobj_release(&view->hdr);
-    }
+    r = MsiSourceListSetInfoW(package->ProductCode, NULL,
+                              package->Context, MSICODE_PRODUCT,
+                              INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
+    if (r != ERROR_SUCCESS)
+        return r;
 
-    /* ok there is a lot more done here but i need to figure out what */
+    r = MsiSourceListSetInfoW(package->ProductCode, NULL,
+                              package->Context, MSICODE_PRODUCT,
+                              INSTALLPROPERTY_DISKPROMPTW, szEmpty);
+    if (r != ERROR_SUCCESS)
+        return r;
 
-    if (package->Context == MSIINSTALLCONTEXT_MACHINE)
+    LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
     {
-        rc = MSIREG_OpenLocalClassesProductKey(package->ProductCode, &hukey, TRUE);
-        if (rc != ERROR_SUCCESS)
-            goto end;
-
-        rc = MSIREG_OpenLocalSystemInstallProps(package->ProductCode, &props, TRUE);
-        if (rc != ERROR_SUCCESS)
-            goto end;
+        if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
+            msi_set_last_used_source(package->ProductCode, NULL, info->context,
+                                     info->options, info->value);
+        else
+            MsiSourceListSetInfoW(package->ProductCode, NULL,
+                                  info->context, info->options,
+                                  info->property, info->value);
     }
-    else
-    {
-        rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
-        if (rc != ERROR_SUCCESS)
-            goto end;
-
-        rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
-        if (rc != ERROR_SUCCESS)
-            goto end;
 
-        rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &props, TRUE);
-        if (rc != ERROR_SUCCESS)
-            goto end;
+    LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
+    {
+        MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
+                                   disk->context, disk->options,
+                                   disk->disk_id, disk->volume_label, disk->disk_prompt);
     }
 
-    rc = RegCreateKeyW(hukey, szSourceList, &source);
-    if (rc != ERROR_SUCCESS)
-        goto end;
-
-    RegCloseKey(source);
+    return ERROR_SUCCESS;
+}
 
-    rc = MSIREG_OpenUserDataProductKey(package->ProductCode,&hudkey,TRUE);
-    if (rc != ERROR_SUCCESS)
-        goto end;
+static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
+{
+    MSIHANDLE hdb, suminfo;
+    WCHAR guids[MAX_PATH];
+    WCHAR packcode[SQUISH_GUID_SIZE];
+    LPWSTR buffer;
+    LPWSTR ptr;
+    DWORD langid;
+    DWORD size;
+    UINT r;
 
-    buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
-    msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
+    static const WCHAR szProductLanguage[] =
+        {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
+    static const WCHAR szARPProductIcon[] =
+        {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
+    static const WCHAR szProductVersion[] =
+        {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
+    static const WCHAR szAssignment[] =
+        {'A','s','s','i','g','n','m','e','n','t',0};
+    static const WCHAR szAdvertiseFlags[] =
+        {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
+    static const WCHAR szClients[] =
+        {'C','l','i','e','n','t','s',0};
+    static const WCHAR szColon[] = {':',0};
+
+    buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
+    msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
     msi_free(buffer);
 
-    langid = msi_get_property_int( package, szProductLanguage, 0 );
-    msi_reg_set_val_dword( hukey, INSTALLPROPERTY_LANGUAGEW, langid );
-
-    packname = strrchrW( package->PackagePath, '\\' ) + 1;
-    msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGENAMEW, packname );
+    langid = msi_get_property_int(package, szProductLanguage, 0);
+    msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
 
     /* FIXME */
-    msi_reg_set_val_dword( hukey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0 );
-    msi_reg_set_val_dword( props, INSTALLPROPERTY_INSTANCETYPEW, 0 );
+    msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
 
-    buffer = msi_dup_property( package, szARPProductIcon );
+    buffer = msi_dup_property(package, szARPProductIcon);
     if (buffer)
     {
         LPWSTR path = build_icon_path(package,buffer);
-        msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
-        msi_free( path );
+        msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
+        msi_free(path);
+        msi_free(buffer);
     }
-    msi_free(buffer);
 
-    buffer = msi_dup_property( package, szProductVersion );
+    buffer = msi_dup_property(package, szProductVersion);
     if (buffer)
     {
         DWORD verdword = msi_version_str_to_dword(buffer);
-        msi_reg_set_val_dword( hukey, INSTALLPROPERTY_VERSIONW, verdword );
+        msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
+        msi_free(buffer);
     }
-    msi_free(buffer);
 
-    buffer = strrchrW( package->PackagePath, '\\') + 1;
-    rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
-                                package->Context, MSICODE_PRODUCT,
-                                INSTALLPROPERTY_PACKAGENAMEW, buffer );
-    if (rc != ERROR_SUCCESS)
-        goto end;
+    msi_reg_set_val_dword(hkey, szAssignment, 0);
+    msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
+    msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
+    msi_reg_set_val_str(hkey, szClients, szColon);
 
-    rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
-                                package->Context, MSICODE_PRODUCT,
-                                INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty );
-    if (rc != ERROR_SUCCESS)
-        goto end;
+    hdb = alloc_msihandle(&package->db->hdr);
+    if (!hdb)
+        return ERROR_NOT_ENOUGH_MEMORY;
 
-    rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
-                                package->Context, MSICODE_PRODUCT,
-                                INSTALLPROPERTY_DISKPROMPTW, szEmpty );
-    if (rc != ERROR_SUCCESS)
-        goto end;
+    r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
+    MsiCloseHandle(hdb);
+    if (r != ERROR_SUCCESS)
+        goto done;
 
-    /* FIXME: Need to write more keys to the user registry */
-  
-    hDb= alloc_msihandle( &package->db->hdr );
-    if (!hDb) {
-        rc = ERROR_NOT_ENOUGH_MEMORY;
-        goto end;
-    }
-    rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo); 
-    MsiCloseHandle(hDb);
-    if (rc == ERROR_SUCCESS)
+    size = MAX_PATH;
+    r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
+                                   NULL, guids, &size);
+    if (r != ERROR_SUCCESS)
+        goto done;
+
+    ptr = strchrW(guids, ';');
+    if (ptr) *ptr = 0;
+    squash_guid(guids, packcode);
+    msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
+
+done:
+    MsiCloseHandle(suminfo);
+    return ERROR_SUCCESS;
+}
+
+static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
+{
+    UINT r;
+    HKEY hkey;
+    LPWSTR upgrade;
+    WCHAR squashed_pc[SQUISH_GUID_SIZE];
+
+    static const WCHAR szUpgradeCode[] =
+        {'U','p','g','r','a','d','e','C','o','d','e',0};
+
+    upgrade = msi_dup_property(package, szUpgradeCode);
+    if (!upgrade)
+        return ERROR_SUCCESS;
+
+    if (package->Context == MSIINSTALLCONTEXT_MACHINE)
     {
-        WCHAR guidbuffer[0x200];
-        size = 0x200;
-        rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
-                                        guidbuffer, &size);
-        if (rc == ERROR_SUCCESS)
-        {
-            /* for now we only care about the first guid */
-            LPWSTR ptr = strchrW(guidbuffer,';');
-            if (ptr) *ptr = 0;
-            msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, guidbuffer );
-        }
-        else
-        {
-            ERR("Unable to query Revision_Number...\n");
-            rc = ERROR_SUCCESS;
-        }
-        MsiCloseHandle(hSumInfo);
+        r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
+        if (r != ERROR_SUCCESS)
+            goto done;
     }
     else
     {
-        ERR("Unable to open Summary Information\n");
-        rc = ERROR_SUCCESS;
-    }
-
-    /* publish the SourceList info */
-    LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
-    {
-        if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
-            msi_set_last_used_source(package->ProductCode, NULL, info->context,
-                                     info->options, info->value);
-        else
-            MsiSourceListSetInfoW(package->ProductCode, NULL,
-                                  info->context, info->options,
-                                  info->property, info->value);
+        r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
+        if (r != ERROR_SUCCESS)
+            goto done;
     }
 
-    LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
-    {
-        MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
-                                   disk->context, disk->options,
-                                   disk->disk_id, disk->volume_label, disk->disk_prompt);
-    }
+    squash_guid(package->ProductCode, squashed_pc);
+    msi_reg_set_val_str(hkey, squashed_pc, NULL);
 
-end:
     RegCloseKey(hkey);
-    RegCloseKey(hukey);
-    RegCloseKey(hudkey);
-    RegCloseKey(props);
 
-    return rc;
+done:
+    msi_free(upgrade);
+    return r;
 }
 
-static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
+static BOOL msi_check_publish(MSIPACKAGE *package)
 {
-    MSIPACKAGE *package = (MSIPACKAGE*)param;
-    LPCWSTR component,section,key,value,identifier,filename,dirproperty;
-    LPWSTR deformated_section, deformated_key, deformated_value;
-    LPWSTR folder, fullname = NULL;
-    MSIRECORD * uirow;
-    INT action;
-    MSICOMPONENT *comp;
-    static const WCHAR szWindowsFolder[] =
-          {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
+    MSIFEATURE *feature;
 
-    component = MSI_RecordGetString(row, 8);
+    LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
+    {
+        if (feature->ActionRequest == INSTALLSTATE_LOCAL)
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+static BOOL msi_check_unpublish(MSIPACKAGE *package)
+{
+    MSIFEATURE *feature;
+
+    LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
+    {
+        if (feature->ActionRequest != INSTALLSTATE_ABSENT)
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
+{
+    WCHAR patch_squashed[GUID_SIZE];
+    HKEY patches;
+    LONG res;
+    UINT r = ERROR_FUNCTION_FAILED;
+
+    res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
+                          &patches, NULL);
+    if (res != ERROR_SUCCESS)
+        return ERROR_FUNCTION_FAILED;
+
+    squash_guid(package->patch->patchcode, patch_squashed);
+
+    res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
+                         (const BYTE *)patch_squashed,
+                         (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
+    if (res != ERROR_SUCCESS)
+        goto done;
+
+    res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
+                         (const BYTE *)package->patch->transforms,
+                         (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
+    if (res == ERROR_SUCCESS)
+        r = ERROR_SUCCESS;
+
+done:
+    RegCloseKey(patches);
+    return r;
+}
+
+/*
+ * 99% of the work done here is only done for 
+ * advertised installs. However this is where the
+ * Icon table is processed and written out
+ * so that is what I am going to do here.
+ */
+static UINT ACTION_PublishProduct(MSIPACKAGE *package)
+{
+    UINT rc;
+    HKEY hukey=0;
+    HKEY hudkey=0;
+
+    /* FIXME: also need to publish if the product is in advertise mode */
+    if (!msi_check_publish(package))
+        return ERROR_SUCCESS;
+
+    rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
+                               &hukey, TRUE);
+    if (rc != ERROR_SUCCESS)
+        goto end;
+
+    rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
+                                       NULL, &hudkey, TRUE);
+    if (rc != ERROR_SUCCESS)
+        goto end;
+
+    rc = msi_publish_upgrade_code(package);
+    if (rc != ERROR_SUCCESS)
+        goto end;
+
+    if (package->patch)
+    {
+        rc = msi_publish_patch(package, hukey, hudkey);
+        if (rc != ERROR_SUCCESS)
+            goto end;
+    }
+
+    rc = msi_publish_product_properties(package, hukey);
+    if (rc != ERROR_SUCCESS)
+        goto end;
+
+    rc = msi_publish_sourcelist(package, hukey);
+    if (rc != ERROR_SUCCESS)
+        goto end;
+
+    rc = msi_publish_icons(package);
+
+end:
+    RegCloseKey(hukey);
+    RegCloseKey(hudkey);
+
+    return rc;
+}
+
+static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
+{
+    MSIPACKAGE *package = param;
+    LPCWSTR component, section, key, value, identifier, dirproperty;
+    LPWSTR deformated_section, deformated_key, deformated_value;
+    LPWSTR folder, filename, fullname = NULL;
+    LPCWSTR filenameptr;
+    MSIRECORD * uirow;
+    INT action;
+    MSICOMPONENT *comp;
+    static const WCHAR szWindowsFolder[] =
+          {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
+
+    component = MSI_RecordGetString(row, 8);
     comp = get_loaded_component(package,component);
 
     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
@@ -3534,7 +3472,6 @@ static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
     comp->Action = INSTALLSTATE_LOCAL;
 
     identifier = MSI_RecordGetString(row,1); 
-    filename = MSI_RecordGetString(row,2);
     dirproperty = MSI_RecordGetString(row,3);
     section = MSI_RecordGetString(row,4);
     key = MSI_RecordGetString(row,5);
@@ -3545,6 +3482,12 @@ static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
     deformat_string(package,key,&deformated_key);
     deformat_string(package,value,&deformated_value);
 
+    filename = msi_dup_record_field(row, 2);
+    if (filename && (filenameptr = strchrW(filename, '|')))
+        filenameptr++;
+    else
+        filenameptr = filename;
+
     if (dirproperty)
     {
         folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
@@ -3560,7 +3503,7 @@ static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
         goto cleanup;
     }
 
-    fullname = build_directory_name(2, folder, filename);
+    fullname = build_directory_name(2, folder, filenameptr);
 
     if (action == 0)
     {
@@ -3595,7 +3538,9 @@ static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
     MSI_RecordSetStringW(uirow,4,deformated_value);
     ui_actiondata(package,szWriteIniValues,uirow);
     msiobj_release( &uirow->hdr );
+
 cleanup:
+    msi_free(filename);
     msi_free(fullname);
     msi_free(folder);
     msi_free(deformated_key);
@@ -3626,7 +3571,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;
@@ -3663,7 +3608,11 @@ static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
                     &si, &info);
 
     if (brc)
+    {
+        CloseHandle(info.hThread);
         msi_dialog_check_messages(info.hProcess);
+        CloseHandle(info.hProcess);
+    }
 
     msi_free(FullName);
 
@@ -3708,22 +3657,19 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
 {
     MSIFEATURE *feature;
     UINT rc;
-    HKEY hkey=0;
-    HKEY hukey=0;
-    HKEY userdata=0;
+    HKEY hkey;
+    HKEY userdata = NULL;
 
     if (!msi_check_publish(package))
         return ERROR_SUCCESS;
 
-    rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
-    if (rc != ERROR_SUCCESS)
-        goto end;
-
-    rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
+    rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
+                                &hkey, TRUE);
     if (rc != ERROR_SUCCESS)
         goto end;
 
-    rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, &userdata, TRUE);
+    rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
+                                        &userdata, TRUE);
     if (rc != ERROR_SUCCESS)
         goto end;
 
@@ -3776,7 +3722,6 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
             strcatW(data,feature->Feature_Parent);
         }
 
-        msi_reg_set_val_str( hkey, feature->Feature, data );
         msi_reg_set_val_str( userdata, feature->Feature, data );
         msi_free(data);
 
@@ -3785,10 +3730,9 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
             size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
         if (!absent)
         {
-            static const WCHAR emptyW[] = {0};
             size += sizeof(WCHAR);
-            RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
-                           (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : emptyW),size);
+            RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
+                           (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
         }
         else
         {
@@ -3798,7 +3742,7 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
             data[1] = 0;
             if (feature->Feature_Parent)
                 strcpyW( &data[1], feature->Feature_Parent );
-            RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
+            RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
                        (LPBYTE)data,size);
             msi_free(data);
         }
@@ -3813,7 +3757,7 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
 
 end:
     RegCloseKey(hkey);
-    RegCloseKey(hukey);
+    RegCloseKey(userdata);
     return rc;
 }
 
@@ -3824,14 +3768,16 @@ static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
 
     TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
 
-    r = MSIREG_OpenUserFeaturesKey(package->ProductCode, &hkey, FALSE);
+    r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
+                               &hkey, FALSE);
     if (r == ERROR_SUCCESS)
     {
         RegDeleteValueW(hkey, feature->Feature);
         RegCloseKey(hkey);
     }
 
-    r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, &hkey, FALSE);
+    r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
+                                       &hkey, FALSE);
     if (r == ERROR_SUCCESS)
     {
         RegDeleteValueW(hkey, feature->Feature);
@@ -3841,19 +3787,6 @@ static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
     return ERROR_SUCCESS;
 }
 
-static BOOL msi_check_unpublish(MSIPACKAGE *package)
-{
-    MSIFEATURE *feature;
-
-    LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
-    {
-        if (feature->ActionRequest != INSTALLSTATE_ABSENT)
-            return FALSE;
-    }
-
-    return TRUE;
-}
-
 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
 {
     MSIFEATURE *feature;
@@ -3869,73 +3802,39 @@ static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
     return ERROR_SUCCESS;
 }
 
-static UINT msi_get_local_package_name( LPWSTR path )
-{
-    static const WCHAR szInstaller[] = {
-        '\\','I','n','s','t','a','l','l','e','r','\\',0};
-    static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
-    DWORD time, len, i;
-    HANDLE handle;
-
-    time = GetTickCount();
-    GetWindowsDirectoryW( path, MAX_PATH );
-    lstrcatW( path, szInstaller );
-    CreateDirectoryW( path, NULL );
-
-    len = lstrlenW(path);
-    for (i=0; i<0x10000; i++)
-    {
-        snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
-        handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
-                              CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
-        if (handle != INVALID_HANDLE_VALUE)
-        {
-            CloseHandle(handle);
-            break;
-        }
-        if (GetLastError() != ERROR_FILE_EXISTS &&
-            GetLastError() != ERROR_SHARING_VIOLATION)
-            return ERROR_FUNCTION_FAILED;
-    }
-
-    return ERROR_SUCCESS;
-}
-
-static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
+static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
 {
-    WCHAR packagefile[MAX_PATH];
-    HKEY props;
-    UINT r;
-
-    r = msi_get_local_package_name( packagefile );
-    if (r != ERROR_SUCCESS)
-        return r;
-
-    TRACE("Copying to local package %s\n",debugstr_w(packagefile));
-
-    r = CopyFileW( package->db->path, packagefile, FALSE);
-
-    if (!r)
-    {
-        ERR("Unable to copy package (%s -> %s) (error %d)\n",
-            debugstr_w(package->db->path), debugstr_w(packagefile), GetLastError());
-        return ERROR_FUNCTION_FAILED;
-    }
-
-    msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
-
-    r = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &props, TRUE);
-    if (r != ERROR_SUCCESS)
-        return r;
+    LPWSTR prop, val, key;
+    SYSTEMTIME systime;
+    DWORD size, langid;
+    WCHAR date[9];
+    LPWSTR buffer;
 
-    msi_reg_set_val_str(props, INSTALLPROPERTY_LOCALPACKAGEW, packagefile);
-    RegCloseKey(props);
-    return ERROR_SUCCESS;
-}
+    static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
+    static const WCHAR szWindowsInstaller[] =
+        {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
+    static const WCHAR modpath_fmt[] =
+        {'M','s','i','E','x','e','c','.','e','x','e',' ',
+         '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
+    static const WCHAR szModifyPath[] =
+        {'M','o','d','i','f','y','P','a','t','h',0};
+    static const WCHAR szUninstallString[] =
+        {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
+    static const WCHAR szEstimatedSize[] =
+        {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
+    static const WCHAR szProductLanguage[] =
+        {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
+    static const WCHAR szProductVersion[] =
+        {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
+    static const WCHAR szProductName[] =
+        {'P','r','o','d','u','c','t','N','a','m','e',0};
+    static const WCHAR szDisplayName[] =
+        {'D','i','s','p','l','a','y','N','a','m','e',0};
+    static const WCHAR szDisplayVersion[] =
+        {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
+    static const WCHAR szManufacturer[] =
+        {'M','a','n','u','f','a','c','t','u','r','e','r',0};
 
-static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
-{
-    LPWSTR prop, val, key;
     static const LPCSTR propval[] = {
         "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
         "ARPCONTACT",             "Contact",
@@ -3955,177 +3854,128 @@ static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
     };
     const LPCSTR *p = propval;
 
-    while( *p )
+    while (*p)
     {
-        prop = strdupAtoW( *p++ );
-        key = strdupAtoW( *p++ );
-        val = msi_dup_property( package, prop );
-        msi_reg_set_val_str( hkey, key, val );
+        prop = strdupAtoW(*p++);
+        key = strdupAtoW(*p++);
+        val = msi_dup_property(package, prop);
+        msi_reg_set_val_str(hkey, key, val);
         msi_free(val);
         msi_free(key);
         msi_free(prop);
     }
-    return ERROR_SUCCESS;
-}
-
-static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
-{
-    HKEY hkey=0;
-    HKEY hudkey=0, props=0;
-    LPWSTR buffer = NULL;
-    UINT rc;
-    DWORD size, langid;
-    static const WCHAR szWindowsInstaller[] = 
-        {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
-    static const WCHAR szUpgradeCode[] = 
-        {'U','p','g','r','a','d','e','C','o','d','e',0};
-    static const WCHAR modpath_fmt[] = 
-        {'M','s','i','E','x','e','c','.','e','x','e',' ',
-         '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
-    static const WCHAR szModifyPath[] = 
-        {'M','o','d','i','f','y','P','a','t','h',0};
-    static const WCHAR szUninstallString[] = 
-        {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
-    static const WCHAR szEstimatedSize[] = 
-        {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
-    static const WCHAR szProductLanguage[] =
-        {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
-    static const WCHAR szProductVersion[] =
-        {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
-    static const WCHAR szProductName[] =
-        {'P','r','o','d','u','c','t','N','a','m','e',0};
-    static const WCHAR szDisplayName[] =
-        {'D','i','s','p','l','a','y','N','a','m','e',0};
-    static const WCHAR szDisplayVersion[] =
-        {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
-    static const WCHAR szManufacturer[] =
-        {'M','a','n','u','f','a','c','t','u','r','e','r',0};
-
-    SYSTEMTIME systime;
-    static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
-    LPWSTR upgrade_code;
-    WCHAR szDate[9];
-
-    /* FIXME: also need to publish if the product is in advertise mode */
-    if (!msi_check_publish(package))
-        return ERROR_SUCCESS;
-
-    rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
-    if (rc != ERROR_SUCCESS)
-        return rc;
-
-    if (package->Context == MSIINSTALLCONTEXT_MACHINE)
-    {
-        rc = MSIREG_OpenLocalSystemInstallProps(package->ProductCode, &props, TRUE);
-        if (rc != ERROR_SUCCESS)
-            return rc;
-    }
-    else
-    {
-        rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &props, TRUE);
-        if (rc != ERROR_SUCCESS)
-            return rc;
-    }
 
-    /* dump all the info i can grab */
-    /* FIXME: Flesh out more information */
+    msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
 
-    msi_write_uninstall_property_vals( package, hkey );
-
-    msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
-    
-    msi_make_package_local( package, hkey );
-
-    /* do ModifyPath and UninstallString */
-    size = deformat_string(package,modpath_fmt,&buffer);
-    RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
-    RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
+    size = deformat_string(package, modpath_fmt, &buffer);
+    RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
+    RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
     msi_free(buffer);
 
     /* FIXME: Write real Estimated Size when we have it */
-    msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
+    msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
 
-    buffer = msi_dup_property( package, szProductName );
-    msi_reg_set_val_str( props, szDisplayName, buffer );
+    buffer = msi_dup_property(package, szProductName);
+    msi_reg_set_val_str(hkey, szDisplayName, buffer);
     msi_free(buffer);
 
-    buffer = msi_dup_property( package, cszSourceDir );
-    msi_reg_set_val_str( props, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
+    buffer = msi_dup_property(package, cszSourceDir);
+    msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
     msi_free(buffer);
 
-    buffer = msi_dup_property( package, szManufacturer );
-    msi_reg_set_val_str( props, INSTALLPROPERTY_PUBLISHERW, buffer);
+    buffer = msi_dup_property(package, szManufacturer);
+    msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
     msi_free(buffer);
-   
+
     GetLocalTime(&systime);
-    sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
-    msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
-    msi_reg_set_val_str( props, INSTALLPROPERTY_INSTALLDATEW, szDate );
-   
-    langid = msi_get_property_int( package, szProductLanguage, 0 );
-    msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
-
-    buffer = msi_dup_property( package, szProductVersion );
-    msi_reg_set_val_str( props, szDisplayVersion, buffer );
+    sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
+    msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
+
+    langid = msi_get_property_int(package, szProductLanguage, 0);
+    msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
+
+    buffer = msi_dup_property(package, szProductVersion);
+    msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
     if (buffer)
     {
         DWORD verdword = msi_version_str_to_dword(buffer);
 
-        msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
-        msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONW, verdword );
-        msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
-        msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
-        msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
-        msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
+        msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
+        msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
+        msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
+        msi_free(buffer);
     }
-    msi_free(buffer);
-    
-    /* Handle Upgrade Codes */
-    upgrade_code = msi_dup_property( package, szUpgradeCode );
-    if (upgrade_code)
-    {
-        HKEY hkey2;
-        WCHAR squashed[33];
-        MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
-        squash_guid(package->ProductCode,squashed);
-        msi_reg_set_val_str( hkey2, squashed, NULL );
-        RegCloseKey(hkey2);
-        MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
-        squash_guid(package->ProductCode,squashed);
-        msi_reg_set_val_str( hkey2, squashed, NULL );
-        RegCloseKey(hkey2);
 
-        msi_free(upgrade_code);
-    }
+    return ERROR_SUCCESS;
+}
 
-    RegCloseKey(hkey);
+static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
+{
+    WCHAR squashed_pc[SQUISH_GUID_SIZE];
+    LPWSTR upgrade_code;
+    HKEY hkey, props;
+    HKEY upgrade;
+    UINT rc;
+
+    static const WCHAR szUpgradeCode[] = {
+        'U','p','g','r','a','d','e','C','o','d','e',0};
 
-    rc = MSIREG_OpenUserDataProductKey(package->ProductCode, &hudkey, TRUE);
+    /* FIXME: also need to publish if the product is in advertise mode */
+    if (!msi_check_publish(package))
+        return ERROR_SUCCESS;
+
+    rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
     if (rc != ERROR_SUCCESS)
         return rc;
 
-    RegCloseKey(hudkey);
-
-    msi_reg_set_val_dword( props, szWindowsInstaller, 1 );
-    RegCloseKey(props);
+    rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
+                                 NULL, &props, TRUE);
+    if (rc != ERROR_SUCCESS)
+        goto done;
 
-    return ERROR_SUCCESS;
-}
+    msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
+    msi_free( package->db->localfile );
+    package->db->localfile = NULL;
 
-static UINT ACTION_InstallExecute(MSIPACKAGE *package)
-{
-    return execute_script(package,INSTALL_SCRIPT);
-}
+    rc = msi_publish_install_properties(package, hkey);
+    if (rc != ERROR_SUCCESS)
+        goto done;
+
+    rc = msi_publish_install_properties(package, props);
+    if (rc != ERROR_SUCCESS)
+        goto done;
+
+    upgrade_code = msi_dup_property(package, szUpgradeCode);
+    if (upgrade_code)
+    {
+        MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
+        squash_guid(package->ProductCode, squashed_pc);
+        msi_reg_set_val_str(upgrade, squashed_pc, NULL);
+        RegCloseKey(upgrade);
+        msi_free(upgrade_code);
+    }
+
+done:
+    RegCloseKey(hkey);
+
+    return ERROR_SUCCESS;
+}
+
+static UINT ACTION_InstallExecute(MSIPACKAGE *package)
+{
+    return execute_script(package,INSTALL_SCRIPT);
+}
 
 static UINT msi_unpublish_product(MSIPACKAGE *package)
 {
+    LPWSTR upgrade;
     LPWSTR remove = NULL;
     LPWSTR *features = NULL;
     BOOL full_uninstall = TRUE;
     MSIFEATURE *feature;
 
-    static const WCHAR szRemove[] = {'R','E','M','O','V','E',0};
-    static const WCHAR szAll[] = {'A','L','L',0};
+    static const WCHAR szUpgradeCode[] =
+        {'U','p','g','r','a','d','e','C','o','d','e',0};
 
     remove = msi_dup_property(package, szRemove);
     if (!remove)
@@ -4154,11 +4004,27 @@ static UINT msi_unpublish_product(MSIPACKAGE *package)
         goto done;
 
     MSIREG_DeleteProductKey(package->ProductCode);
-    MSIREG_DeleteUserProductKey(package->ProductCode);
     MSIREG_DeleteUserDataProductKey(package->ProductCode);
-    MSIREG_DeleteUserFeaturesKey(package->ProductCode);
     MSIREG_DeleteUninstallKey(package->ProductCode);
 
+    if (package->Context == MSIINSTALLCONTEXT_MACHINE)
+    {
+        MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
+        MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
+    }
+    else
+    {
+        MSIREG_DeleteUserProductKey(package->ProductCode);
+        MSIREG_DeleteUserFeaturesKey(package->ProductCode);
+    }
+
+    upgrade = msi_dup_property(package, szUpgradeCode);
+    if (upgrade)
+    {
+        MSIREG_DeleteUserUpgradeCodesKey(upgrade);
+        msi_free(upgrade);
+    }
+
 done:
     msi_free(remove);
     msi_free(features);
@@ -4323,7 +4189,8 @@ static UINT ACTION_RegisterUser(MSIPACKAGE *package)
     if (!productid)
         return ERROR_SUCCESS;
 
-    rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &hkey, TRUE);
+    rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
+                                 NULL, &hkey, TRUE);
     if (rc != ERROR_SUCCESS)
         goto end;
 
@@ -4356,7 +4223,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;
@@ -4452,7 +4319,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;
@@ -4593,7 +4460,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;
@@ -4706,7 +4573,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;
@@ -4803,7 +4670,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;
@@ -4869,7 +4736,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;
@@ -5021,7 +4888,6 @@ static UINT ACTION_InstallODBC( MSIPACKAGE *package )
 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
 {
     LPCWSTR cptr = *name;
-    LPCWSTR ptr = *value;
 
     static const WCHAR prefix[] = {'[','~',']',0};
     static const int prefix_len = 3;
@@ -5052,6 +4918,9 @@ static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
         return ERROR_FUNCTION_FAILED;
     }
 
+    if (*value)
+    {
+        LPCWSTR ptr = *value;
     if (!strncmpW(ptr, prefix, prefix_len))
     {
         *flags |= ENV_MOD_APPEND;
@@ -5066,9 +4935,9 @@ static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
             /* the "[~]" will be removed by deformat_string */;
         }
     }
+    }
 
-    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))
@@ -5077,6 +4946,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;
 }
 
@@ -5099,17 +4971,17 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
          'C','o','n','t','r','o','l','\\',
          'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
          'E','n','v','i','r','o','n','m','e','n','t',0};
-    static const WCHAR semicolon[] = {';',0};
 
     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;
 
-    deformat_string(package, value, &deformatted);
-    if (!deformatted)
+    if (value && !deformat_string(package, value, &deformatted))
     {
         res = ERROR_OUTOFMEMORY;
         goto done;
@@ -5167,7 +5039,7 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
             goto done;
         }
 
-        size =  (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
+        size += (lstrlenW(value) + 1) * sizeof(WCHAR);
         newval =  msi_alloc(size);
         ptr = newval;
         if (!newval)
@@ -5183,7 +5055,7 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
             if (flags & ENV_MOD_PREFIX)
             {
                 lstrcpyW(newval, value);
-                lstrcatW(newval, semicolon);
+                lstrcatW(newval, szSemiColon);
                 ptr = newval + lstrlenW(value) + 1;
             }
 
@@ -5191,12 +5063,12 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
 
             if (flags & ENV_MOD_APPEND)
             {
-                lstrcatW(newval, semicolon);
+                lstrcatW(newval, szSemiColon);
                 lstrcatW(newval, value);
             }
         }
     }
-    else
+    else if (value)
     {
         size = (lstrlenW(value) + 1) * sizeof(WCHAR);
         newval = msi_alloc(size);
@@ -5209,8 +5081,13 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
         lstrcpyW(newval, value);
     }
 
+    if (newval)
+    {
     TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
     res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
+    }
+    else
+        res = ERROR_SUCCESS;
 
 done:
     if (env) RegCloseKey(env);
@@ -5418,7 +5295,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);
@@ -5436,15 +5313,14 @@ static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
 {
     MSIPACKAGE *package = param;
     MSICOMPONENT *comp;
-    LPCWSTR sourcename, destname;
+    LPCWSTR sourcename;
+    LPWSTR destname = NULL;
     LPWSTR sourcedir = NULL, destdir = NULL;
     LPWSTR source = NULL, dest = NULL;
     int options;
     DWORD size;
     BOOL ret, wildcards;
 
-    static const WCHAR backslash[] = {'\\',0};
-
     comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
     if (!comp || !comp->Enabled ||
         !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
@@ -5454,7 +5330,6 @@ static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
     }
 
     sourcename = MSI_RecordGetString(rec, 3);
-    destname = MSI_RecordGetString(rec, 4);
     options = MSI_RecordGetInteger(rec, 7);
 
     sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
@@ -5483,17 +5358,26 @@ static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
 
         lstrcpyW(source, sourcedir);
         if (source[lstrlenW(source) - 1] != '\\')
-            lstrcatW(source, backslash);
+            lstrcatW(source, szBackSlash);
         lstrcatW(source, sourcename);
     }
 
     wildcards = strchrW(source, '*') || strchrW(source, '?');
 
-    if (!destname && !wildcards)
+    if (MSI_RecordIsNull(rec, 4))
     {
-        destname = strdupW(sourcename);
-        if (!destname)
-            goto done;
+        if (!wildcards)
+        {
+            destname = strdupW(sourcename);
+            if (!destname)
+                goto done;
+        }
+    }
+    else
+    {
+        destname = strdupW(MSI_RecordGetString(rec, 4));
+        if (destname)
+            reduce_to_longfilename(destname);
     }
 
     size = 0;
@@ -5507,7 +5391,7 @@ static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
 
     lstrcpyW(dest, destdir);
     if (dest[lstrlenW(dest) - 1] != '\\')
-        lstrcatW(dest, backslash);
+        lstrcatW(dest, szBackSlash);
 
     if (destname)
         lstrcatW(dest, destname);
@@ -5530,6 +5414,7 @@ static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
 done:
     msi_free(sourcedir);
     msi_free(destdir);
+    msi_free(destname);
     msi_free(source);
     msi_free(dest);
 
@@ -5555,6 +5440,18 @@ static UINT ACTION_MoveFiles( MSIPACKAGE *package )
     return rc;
 }
 
+typedef struct tagMSIASSEMBLY
+{
+    struct list entry;
+    MSICOMPONENT *component;
+    MSIFEATURE *feature;
+    MSIFILE *file;
+    LPWSTR manifest;
+    LPWSTR application;
+    DWORD attributes;
+    BOOL installed;
+} MSIASSEMBLY;
+
 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
                                               DWORD dwReserved);
 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
@@ -5597,14 +5494,32 @@ static BOOL init_functionpointers(void)
     return TRUE;
 }
 
-static UINT install_assembly(LPWSTR path)
+static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
+                             LPWSTR path)
 {
     IAssemblyCache *cache;
     HRESULT hr;
     UINT r = ERROR_FUNCTION_FAILED;
 
-    if (!init_functionpointers() || !pCreateAssemblyCache)
-        return ERROR_FUNCTION_FAILED;
+    TRACE("installing assembly: %s\n", debugstr_w(path));
+
+    if (assembly->feature)
+        msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
+
+    if (assembly->manifest)
+        FIXME("Manifest unhandled\n");
+
+    if (assembly->application)
+    {
+        FIXME("Assembly should be privately installed\n");
+        return ERROR_SUCCESS;
+    }
+
+    if (assembly->attributes == msidbAssemblyAttributesWin32)
+    {
+        FIXME("Win32 assemblies not handled\n");
+        return ERROR_SUCCESS;
+    }
 
     hr = pCreateAssemblyCache(&cache, 0);
     if (FAILED(hr))
@@ -5621,101 +5536,364 @@ done:
     return r;
 }
 
-static UINT ITERATE_PublishAssembly( MSIRECORD *rec, LPVOID param )
+typedef struct tagASSEMBLY_LIST
 {
-    MSIPACKAGE *package = param;
-    MSICOMPONENT *comp;
-    MSIFEATURE *feature;
-    MSIFILE *file;
-    WCHAR path[MAX_PATH];
-    LPCWSTR app;
-    DWORD attr;
-    UINT r;
+    MSIPACKAGE *package;
+    IAssemblyCache *cache;
+    struct list *assemblies;
+} ASSEMBLY_LIST;
+
+typedef struct tagASSEMBLY_NAME
+{
+    LPWSTR name;
+    LPWSTR version;
+    LPWSTR culture;
+    LPWSTR pubkeytoken;
+} ASSEMBLY_NAME;
+
+static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
+{
+    ASSEMBLY_NAME *asmname = param;
+    LPCWSTR name = MSI_RecordGetString(rec, 2);
+    LPWSTR val = msi_dup_record_field(rec, 3);
+
+    static const WCHAR Name[] = {'N','a','m','e',0};
+    static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
+    static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
+    static const WCHAR PublicKeyToken[] = {
+        'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
+
+    if (!strcmpiW(name, Name))
+        asmname->name = val;
+    else if (!strcmpiW(name, Version))
+        asmname->version = val;
+    else if (!strcmpiW(name, Culture))
+        asmname->culture = val;
+    else if (!strcmpiW(name, PublicKeyToken))
+        asmname->pubkeytoken = val;
+    else
+        msi_free(val);
 
-    comp = get_loaded_component(package, MSI_RecordGetString(rec, 1));
-    if (!comp || !comp->Enabled ||
-        !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
+    return ERROR_SUCCESS;
+}
+
+static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
+{
+    if (!*str)
     {
-        ERR("Component not set for install, not publishing assembly\n");
+        *size = lstrlenW(append) + 1;
+        *str = msi_alloc((*size) * sizeof(WCHAR));
+        lstrcpyW(*str, append);
+        return;
+    }
+
+    (*size) += lstrlenW(append);
+    *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
+    lstrcatW(*str, append);
+}
+
+static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache,
+                                     MSICOMPONENT *comp)
+{
+    ASSEMBLY_INFO asminfo;
+    ASSEMBLY_NAME name;
+    MSIQUERY *view;
+    LPWSTR disp;
+    DWORD size;
+    BOOL found;
+    UINT r;
+
+    static const WCHAR separator[] = {',',' ',0};
+    static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
+    static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
+    static const WCHAR PublicKeyToken[] = {
+        'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
+    static const WCHAR query[] = {
+        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+        '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
+        'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
+        '=','\'','%','s','\'',0};
+
+    disp = NULL;
+    found = FALSE;
+    ZeroMemory(&name, sizeof(ASSEMBLY_NAME));
+    ZeroMemory(&asminfo, sizeof(ASSEMBLY_INFO));
+
+    r = MSI_OpenQuery(db, &view, query, comp->Component);
+    if (r != ERROR_SUCCESS)
         return ERROR_SUCCESS;
+
+    MSI_IterateRecords(view, NULL, parse_assembly_name, &name);
+    msiobj_release(&view->hdr);
+
+    if (!name.name)
+    {
+        ERR("No assembly name specified!\n");
+        goto done;
     }
 
-    feature = find_feature_by_name(package, MSI_RecordGetString(rec, 2));
-    if (feature)
-        msi_feature_set_state(feature, INSTALLSTATE_LOCAL);
+    append_str(&disp, &size, name.name);
 
-    if (MSI_RecordGetString(rec, 3))
-        FIXME("Manifest unhandled\n");
+    if (name.version)
+    {
+        append_str(&disp, &size, separator);
+        append_str(&disp, &size, Version);
+        append_str(&disp, &size, name.version);
+    }
 
-    app = MSI_RecordGetString(rec, 4);
-    if (app)
+    if (name.culture)
     {
-        FIXME("Assembly should be privately installed\n");
-        return ERROR_SUCCESS;
+        append_str(&disp, &size, separator);
+        append_str(&disp, &size, Culture);
+        append_str(&disp, &size, name.culture);
     }
 
-    attr = MSI_RecordGetInteger(rec, 5);
-    if (attr == msidbAssemblyAttributesWin32)
+    if (name.pubkeytoken)
     {
-        FIXME("Win32 assemblies not handled\n");
+        append_str(&disp, &size, separator);
+        append_str(&disp, &size, PublicKeyToken);
+        append_str(&disp, &size, name.pubkeytoken);
+    }
+
+    asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
+    IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE,
+                                     disp, &asminfo);
+    found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
+
+done:
+    msi_free(disp);
+    msi_free(name.name);
+    msi_free(name.version);
+    msi_free(name.culture);
+    msi_free(name.pubkeytoken);
+
+    return found;
+}
+
+static UINT load_assembly(MSIRECORD *rec, LPVOID param)
+{
+    ASSEMBLY_LIST *list = param;
+    MSIASSEMBLY *assembly;
+
+    assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
+    if (!assembly)
+        return ERROR_OUTOFMEMORY;
+
+    assembly->component = get_loaded_component(list->package, MSI_RecordGetString(rec, 1));
+
+    if (!assembly->component || !assembly->component->Enabled ||
+        !(assembly->component->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
+    {
+        TRACE("Component not set for install, not publishing assembly\n");
+        msi_free(assembly);
         return ERROR_SUCCESS;
     }
 
-    /* FIXME: extract all files belonging to this component */
-    file = msi_find_file(package, comp->KeyPath);
+    assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
+    assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
 
-    GetTempPathW(MAX_PATH, path);
+    if (!assembly->file)
+    {
+        ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
+        return ERROR_FUNCTION_FAILED;
+    }
+
+    assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
+    assembly->application = strdupW(MSI_RecordGetString(rec, 4));
+    assembly->attributes = MSI_RecordGetInteger(rec, 5);
 
-    if (file->IsCompressed)
+    if (assembly->application)
     {
-        r = msi_extract_file(package, file, path);
-        if (r != ERROR_SUCCESS)
+        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))
         {
-            ERR("Failed to extract temporary assembly\n");
-            return r;
+            assembly->installed = TRUE;
         }
-
-        PathAddBackslashW(path);
-        lstrcatW(path, file->FileName);
     }
     else
+        assembly->installed = check_assembly_installed(list->package->db,
+                                                       list->cache,
+                                                       assembly->component);
+
+    list_add_head(list->assemblies, &assembly->entry);
+    return ERROR_SUCCESS;
+}
+
+static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
+{
+    IAssemblyCache *cache = NULL;
+    ASSEMBLY_LIST list;
+    MSIQUERY *view;
+    HRESULT hr;
+    UINT r;
+
+    static const WCHAR query[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+         '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
+
+    r = MSI_DatabaseOpenViewW(package->db, query, &view);
+    if (r != ERROR_SUCCESS)
+        return ERROR_SUCCESS;
+
+    hr = pCreateAssemblyCache(&cache, 0);
+    if (FAILED(hr))
+        return ERROR_FUNCTION_FAILED;
+
+    list.package = package;
+    list.cache = cache;
+    list.assemblies = assemblies;
+
+    r = MSI_IterateRecords(view, NULL, load_assembly, &list);
+    msiobj_release(&view->hdr);
+
+    IAssemblyCache_Release(cache);
+
+    return r;
+}
+
+static void free_assemblies(struct list *assemblies)
+{
+    struct list *item, *cursor;
+
+    LIST_FOR_EACH_SAFE(item, cursor, assemblies)
     {
-        PathAddBackslashW(path);
-        lstrcatW(path, file->FileName);
+        MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
+
+        list_remove(&assembly->entry);
+        msi_free(assembly->application);
+        msi_free(assembly->manifest);
+        msi_free(assembly);
+    }
+}
+
+static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
+{
+    MSIASSEMBLY *assembly;
 
-        if (!CopyFileW(file->SourcePath, path, FALSE))
+    LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
+    {
+        if (!lstrcmpW(assembly->file->File, file))
         {
-            ERR("Failed to copy temporary assembly: %d\n", GetLastError());
-            return ERROR_FUNCTION_FAILED;
+            *out = assembly;
+            return TRUE;
         }
     }
 
-    r = install_assembly(path);
-    if (r != ERROR_SUCCESS)
-        ERR("Failed to install assembly\n");
+    return FALSE;
+}
 
-    /* FIXME: write Installer assembly reg values */
+static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
+                               LPWSTR *path, DWORD *attrs, PVOID user)
+{
+    MSIASSEMBLY *assembly;
+    WCHAR temppath[MAX_PATH];
+    struct list *assemblies = user;
+    UINT r;
 
-    return r;
+    if (!find_assembly(assemblies, file, &assembly))
+        return FALSE;
+
+    GetTempPathW(MAX_PATH, temppath);
+    PathAddBackslashW(temppath);
+    lstrcatW(temppath, assembly->file->FileName);
+
+    if (action == MSICABEXTRACT_BEGINEXTRACT)
+    {
+        if (assembly->installed)
+            return FALSE;
+
+        *path = strdupW(temppath);
+        *attrs = assembly->file->Attributes;
+    }
+    else if (action == MSICABEXTRACT_FILEEXTRACTED)
+    {
+        assembly->installed = TRUE;
+
+        r = install_assembly(package, assembly, temppath);
+        if (r != ERROR_SUCCESS)
+            ERR("Failed to install assembly\n");
+    }
+
+    return TRUE;
 }
 
 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
 {
-    UINT rc;
-    MSIQUERY *view;
+    UINT r;
+    struct list assemblies = LIST_INIT(assemblies);
+    MSIASSEMBLY *assembly;
+    MSIMEDIAINFO *mi;
 
-    static const WCHAR ExecSeqQuery[] =
-        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-         '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
+    if (!init_functionpointers() || !pCreateAssemblyCache)
+        return ERROR_FUNCTION_FAILED;
 
-    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
-    if (rc != ERROR_SUCCESS)
-        return ERROR_SUCCESS;
+    r = load_assemblies(package, &assemblies);
+    if (r != ERROR_SUCCESS)
+        goto done;
 
-    rc = MSI_IterateRecords(view, NULL, ITERATE_PublishAssembly, package);
-    msiobj_release(&view->hdr);
+    if (list_empty(&assemblies))
+        goto done;
 
-    return rc;
+    mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
+    if (!mi)
+    {
+        r = ERROR_OUTOFMEMORY;
+        goto done;
+    }
+
+    LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
+    {
+        if (assembly->installed && !mi->is_continuous)
+            continue;
+
+        if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
+            (assembly->file->IsCompressed && !mi->is_extracted))
+        {
+            MSICABDATA data;
+
+            r = ready_media(package, assembly->file, mi);
+            if (r != ERROR_SUCCESS)
+            {
+                ERR("Failed to ready media\n");
+                break;
+            }
+
+            data.mi = mi;
+            data.package = package;
+            data.cb = installassembly_cb;
+            data.user = &assemblies;
+
+            if (assembly->file->IsCompressed &&
+                !msi_cabextract(package, mi, &data))
+            {
+                ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
+                r = ERROR_FUNCTION_FAILED;
+                break;
+            }
+        }
+
+        if (!assembly->file->IsCompressed)
+        {
+            LPWSTR source = resolve_file_source(package, assembly->file);
+
+            r = install_assembly(package, assembly, source);
+            if (r != ERROR_SUCCESS)
+                ERR("Failed to install assembly\n");
+
+            msi_free(source);
+        }
+
+        /* FIXME: write Installer assembly reg values */
+    }
+
+done:
+    free_assemblies(&assemblies);
+    return r;
 }
 
 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
@@ -5915,7 +6093,15 @@ static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
     return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
 }
 
-static const struct _actions StandardActions[] = {
+typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
+
+static const struct
+{
+    const WCHAR *action;
+    UINT (*handler)(MSIPACKAGE *);
+}
+StandardActions[] =
+{
     { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
     { szAppSearch, ACTION_AppSearch },
     { szBindImage, ACTION_BindImage },
@@ -6043,3 +6229,207 @@ static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
     }
     return ret;
 }
+
+UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
+{
+    UINT rc = ERROR_SUCCESS;
+    BOOL handled;
+
+    TRACE("Performing action (%s)\n", debugstr_w(action));
+
+    handled = ACTION_HandleStandardAction(package, action, &rc, force);
+
+    if (!handled)
+        handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
+
+    if (!handled)
+    {
+        WARN("unhandled msi action %s\n", debugstr_w(action));
+        rc = ERROR_FUNCTION_NOT_CALLED;
+    }
+
+    return rc;
+}
+
+UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
+{
+    UINT rc = ERROR_SUCCESS;
+    BOOL handled = FALSE;
+
+    TRACE("Performing action (%s)\n", debugstr_w(action));
+
+    handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
+
+    if (!handled)
+        handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
+
+    if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
+        handled = TRUE;
+
+    if (!handled)
+    {
+        WARN("unhandled msi action %s\n", debugstr_w(action));
+        rc = ERROR_FUNCTION_NOT_CALLED;
+    }
+
+    return rc;
+}
+
+static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
+{
+    UINT rc = ERROR_SUCCESS;
+    MSIRECORD *row;
+
+    static const WCHAR ExecSeqQuery[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+         '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
+         'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
+         '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
+    static const WCHAR UISeqQuery[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+     '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
+     '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
+        ' ', '=',' ','%','i',0};
+
+    if (needs_ui_sequence(package))
+        row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
+    else
+        row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
+
+    if (row)
+    {
+        LPCWSTR action, cond;
+
+        TRACE("Running the actions\n");
+
+        /* check conditions */
+        cond = MSI_RecordGetString(row, 2);
+
+        /* this is a hack to skip errors in the condition code */
+        if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
+        {
+            msiobj_release(&row->hdr);
+            return ERROR_SUCCESS;
+        }
+
+        action = MSI_RecordGetString(row, 1);
+        if (!action)
+        {
+            ERR("failed to fetch action\n");
+            msiobj_release(&row->hdr);
+            return ERROR_FUNCTION_FAILED;
+        }
+
+        if (needs_ui_sequence(package))
+            rc = ACTION_PerformUIAction(package, action, -1);
+        else
+            rc = ACTION_PerformAction(package, action, -1, FALSE);
+
+        msiobj_release(&row->hdr);
+    }
+
+    return rc;
+}
+
+/****************************************************
+ * TOP level entry points
+ *****************************************************/
+
+UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
+                         LPCWSTR szCommandLine )
+{
+    UINT rc;
+    BOOL ui_exists;
+
+    static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
+    static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
+
+    MSI_SetPropertyW(package, szAction, szInstall);
+
+    package->script->InWhatSequence = SEQUENCE_INSTALL;
+
+    if (szPackagePath)
+    {
+        LPWSTR p, dir;
+        LPCWSTR file;
+
+        dir = strdupW(szPackagePath);
+        p = strrchrW(dir, '\\');
+        if (p)
+        {
+            *(++p) = 0;
+            file = szPackagePath + (p - dir);
+        }
+        else
+        {
+            msi_free(dir);
+            dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
+            GetCurrentDirectoryW(MAX_PATH, dir);
+            lstrcatW(dir, szBackSlash);
+            file = szPackagePath;
+        }
+
+        msi_free( package->PackagePath );
+        package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
+        if (!package->PackagePath)
+        {
+            msi_free(dir);
+            return ERROR_OUTOFMEMORY;
+        }
+
+        lstrcpyW(package->PackagePath, dir);
+        lstrcatW(package->PackagePath, file);
+        msi_free(dir);
+
+        msi_set_sourcedir_props(package, FALSE);
+    }
+
+    msi_parse_command_line( package, szCommandLine, FALSE );
+
+    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 );
+
+    if (needs_ui_sequence( package))
+    {
+        package->script->InWhatSequence |= SEQUENCE_UI;
+        rc = ACTION_ProcessUISequence(package);
+        ui_exists = ui_sequence_exists(package);
+        if (rc == ERROR_SUCCESS || !ui_exists)
+        {
+            package->script->InWhatSequence |= SEQUENCE_EXEC;
+            rc = ACTION_ProcessExecSequence(package, ui_exists);
+        }
+    }
+    else
+        rc = ACTION_ProcessExecSequence(package, FALSE);
+
+    package->script->CurrentlyScripting = FALSE;
+
+    /* process the ending type action */
+    if (rc == ERROR_SUCCESS)
+        ACTION_PerformActionSequence(package, -1);
+    else if (rc == ERROR_INSTALL_USEREXIT)
+        ACTION_PerformActionSequence(package, -2);
+    else if (rc == ERROR_INSTALL_SUSPEND)
+        ACTION_PerformActionSequence(package, -4);
+    else  /* failed */
+        ACTION_PerformActionSequence(package, -3);
+
+    /* finish up running custom actions */
+    ACTION_FinishCustomActions(package);
+
+    if (rc == ERROR_SUCCESS && package->need_reboot)
+        return ERROR_SUCCESS_REBOOT_REQUIRED;
+
+    return rc;
+}