[MSI] Apply Wine commit fdac39f by Hans Leidekker: Pass correct length to GetDateForm...
[reactos.git] / dll / win32 / msi / package.c
index c84c28a..3e0ae71 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#define NONAMELESSUNION
-#define NONAMELESSSTRUCT
-#define COBJMACROS
-
-#include <stdarg.h>
-#include "windef.h"
-#include "winbase.h"
-#include "winreg.h"
-#include "winnls.h"
-#include "shlwapi.h"
-#include "wingdi.h"
-#include "wine/debug.h"
-#include "msi.h"
-#include "msiquery.h"
-#include "objidl.h"
-#include "wincrypt.h"
-#include "winuser.h"
-#include "wininet.h"
-#include "winver.h"
-#include "urlmon.h"
-#include "shlobj.h"
-#include "wine/unicode.h"
-#include "objbase.h"
-#include "msidefs.h"
-#include "sddl.h"
-
 #include "msipriv.h"
-#include "msiserver.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
-
-static void remove_tracked_tempfiles( MSIPACKAGE *package )
-{
-    struct list *item, *cursor;
 
-    LIST_FOR_EACH_SAFE( item, cursor, &package->tempfiles )
-    {
-        MSITEMPFILE *temp = LIST_ENTRY( item, MSITEMPFILE, entry );
+#include <wininet.h>
 
-        list_remove( &temp->entry );
-        TRACE("deleting temp file %s\n", debugstr_w( temp->Path ));
-        DeleteFileW( temp->Path );
-        msi_free( temp->Path );
-        msi_free( temp );
-    }
-}
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
 static void free_feature( MSIFEATURE *feature )
 {
@@ -90,6 +49,26 @@ static void free_feature( MSIFEATURE *feature )
     msi_free( feature );
 }
 
+static void free_folder( MSIFOLDER *folder )
+{
+    struct list *item, *cursor;
+
+    LIST_FOR_EACH_SAFE( item, cursor, &folder->children )
+    {
+        FolderList *fl = LIST_ENTRY( item, FolderList, entry );
+        list_remove( &fl->entry );
+        msi_free( fl );
+    }
+    msi_free( folder->Parent );
+    msi_free( folder->Directory );
+    msi_free( folder->TargetDefault );
+    msi_free( folder->SourceLongPath );
+    msi_free( folder->SourceShortPath );
+    msi_free( folder->ResolvedTarget );
+    msi_free( folder->ResolvedSource );
+    msi_free( folder );
+}
+
 static void free_extension( MSIEXTENSION *ext )
 {
     struct list *item, *cursor;
@@ -121,14 +100,20 @@ static void free_assembly( MSIASSEMBLY *assembly )
     msi_free( assembly );
 }
 
-static void free_package_structures( MSIPACKAGE *package )
+void msi_free_action_script( MSIPACKAGE *package, UINT script )
 {
-    INT i;
-    struct list *item, *cursor;
+    UINT i;
+    for (i = 0; i < package->script->ActionCount[script]; i++)
+        msi_free( package->script->Actions[script][i] );
 
-    TRACE("Freeing package action data\n");
+    msi_free( package->script->Actions[script] );
+    package->script->Actions[script] = NULL;
+    package->script->ActionCount[script] = 0;
+}
 
-    remove_tracked_tempfiles(package);
+static void free_package_structures( MSIPACKAGE *package )
+{
+    struct list *item, *cursor;
 
     LIST_FOR_EACH_SAFE( item, cursor, &package->features )
     {
@@ -140,17 +125,24 @@ static void free_package_structures( MSIPACKAGE *package )
     LIST_FOR_EACH_SAFE( item, cursor, &package->folders )
     {
         MSIFOLDER *folder = LIST_ENTRY( item, MSIFOLDER, entry );
-
         list_remove( &folder->entry );
-        msi_free( folder->Parent );
-        msi_free( folder->Directory );
-        msi_free( folder->TargetDefault );
-        msi_free( folder->SourceLongPath );
-        msi_free( folder->SourceShortPath );
-        msi_free( folder->ResolvedTarget );
-        msi_free( folder->ResolvedSource );
-        msi_free( folder->Property );
-        msi_free( folder );
+        free_folder( folder );
+    }
+
+    LIST_FOR_EACH_SAFE( item, cursor, &package->files )
+    {
+        MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry );
+
+        list_remove( &file->entry );
+        msi_free( file->File );
+        msi_free( file->FileName );
+        msi_free( file->ShortName );
+        msi_free( file->LongName );
+        msi_free( file->Version );
+        msi_free( file->Language );
+        if (msi_is_global_assembly( file->Component )) DeleteFileW( file->TargetPath );
+        msi_free( file->TargetPath );
+        msi_free( file );
     }
 
     LIST_FOR_EACH_SAFE( item, cursor, &package->components )
@@ -168,19 +160,13 @@ static void free_package_structures( MSIPACKAGE *package )
         msi_free( comp );
     }
 
-    LIST_FOR_EACH_SAFE( item, cursor, &package->files )
+    LIST_FOR_EACH_SAFE( item, cursor, &package->filepatches )
     {
-        MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry );
+        MSIFILEPATCH *patch = LIST_ENTRY( item, MSIFILEPATCH, entry );
 
-        list_remove( &file->entry );
-        msi_free( file->File );
-        msi_free( file->FileName );
-        msi_free( file->ShortName );
-        msi_free( file->LongName );
-        msi_free( file->Version );
-        msi_free( file->Language );
-        msi_free( file->TargetPath );
-        msi_free( file );
+        list_remove( &patch->entry );
+        msi_free( patch->path );
+        msi_free( patch );
     }
 
     /* clean up extension, progid, class and verb structures */
@@ -265,27 +251,19 @@ static void free_package_structures( MSIPACKAGE *package )
 
     if (package->script)
     {
-        for (i = 0; i < TOTAL_SCRIPTS; i++)
+        INT i;
+        UINT j;
+
+        for (i = 0; i < SCRIPT_MAX; i++)
             msi_free_action_script( package, i );
 
-        for (i = 0; i < package->script->UniqueActionsCount; i++)
-            msi_free( package->script->UniqueActions[i] );
+        for (j = 0; j < package->script->UniqueActionsCount; j++)
+            msi_free( package->script->UniqueActions[j] );
 
         msi_free( package->script->UniqueActions );
         msi_free( package->script );
     }
 
-    LIST_FOR_EACH_SAFE( item, cursor, &package->patches )
-    {
-        MSIPATCHINFO *patch = LIST_ENTRY( item, MSIPATCHINFO, entry );
-
-        list_remove( &patch->entry );
-        msi_free( patch->patchcode );
-        msi_free( patch->transforms );
-        msi_free( patch->localfile );
-        msi_free( patch );
-    }
-
     LIST_FOR_EACH_SAFE( item, cursor, &package->binaries )
     {
         MSIBINARY *binary = LIST_ENTRY( item, MSIBINARY, entry );
@@ -300,22 +278,46 @@ static void free_package_structures( MSIPACKAGE *package )
         msi_free( binary );
     }
 
+    LIST_FOR_EACH_SAFE( item, cursor, &package->cabinet_streams )
+    {
+        MSICABINETSTREAM *cab = LIST_ENTRY( item, MSICABINETSTREAM, entry );
+
+        list_remove( &cab->entry );
+        IStorage_Release( cab->storage );
+        msi_free( cab->stream );
+        msi_free( cab );
+    }
+
+    LIST_FOR_EACH_SAFE( item, cursor, &package->patches )
+    {
+        MSIPATCHINFO *patch = LIST_ENTRY( item, MSIPATCHINFO, entry );
+
+        list_remove( &patch->entry );
+        if (patch->delete_on_close && !DeleteFileW( patch->localfile ))
+        {
+            ERR("failed to delete %s (%u)\n", debugstr_w(patch->localfile), GetLastError());
+        }
+        msi_free_patchinfo( patch );
+    }
+
     msi_free( package->BaseURL );
     msi_free( package->PackagePath );
     msi_free( package->ProductCode );
     msi_free( package->ActionFormat );
     msi_free( package->LastAction );
+    msi_free( package->LastActionTemplate );
     msi_free( package->langids );
 
     /* cleanup control event subscriptions */
-    ControlEvent_CleanupSubscriptions( package );
+    msi_event_cleanup_all_subscriptions( package );
 }
 
 static void MSI_FreePackage( MSIOBJECTHDR *arg)
 {
-    UINT i;
     MSIPACKAGE *package = (MSIPACKAGE *)arg;
 
+    msi_destroy_assembly_caches( package );
+
     if( package->dialog )
         msi_dialog_destroy( package->dialog );
 
@@ -323,28 +325,27 @@ static void MSI_FreePackage( MSIOBJECTHDR *arg)
     free_package_structures(package);
     CloseHandle( package->log_file );
 
-    for (i = 0; i < CLR_VERSION_MAX; i++)
-        if (package->cache_net[i]) IAssemblyCache_Release( package->cache_net[i] );
-    if (package->cache_sxs) IAssemblyCache_Release( package->cache_sxs );
+    if (package->delete_on_close) DeleteFileW( package->localfile );
+    msi_free( package->localfile );
+    MSI_ProcessMessage(NULL, INSTALLMESSAGE_TERMINATE, 0);
 }
 
 static UINT create_temp_property_table(MSIPACKAGE *package)
 {
-    MSIQUERY *view = NULL;
+    static const WCHAR query[] = {
+        'C','R','E','A','T','E',' ','T','A','B','L','E',' ',
+        '`','_','P','r','o','p','e','r','t','y','`',' ','(',' ',
+        '`','_','P','r','o','p','e','r','t','y','`',' ',
+        'C','H','A','R','(','5','6',')',' ','N','O','T',' ','N','U','L','L',' ',
+        'T','E','M','P','O','R','A','R','Y',',',' ',
+        '`','V','a','l','u','e','`',' ','C','H','A','R','(','9','8',')',' ',
+        'N','O','T',' ','N','U','L','L',' ','T','E','M','P','O','R','A','R','Y',
+        ' ','P','R','I','M','A','R','Y',' ','K','E','Y',' ',
+        '`','_','P','r','o','p','e','r','t','y','`',')',' ','H','O','L','D',0};
+    MSIQUERY *view;
     UINT rc;
 
-    static const WCHAR CreateSql[] = {
-       'C','R','E','A','T','E',' ','T','A','B','L','E',' ',
-       '`','_','P','r','o','p','e','r','t','y','`',' ','(',' ',
-       '`','_','P','r','o','p','e','r','t','y','`',' ',
-       'C','H','A','R','(','5','6',')',' ','N','O','T',' ','N','U','L','L',' ',
-       'T','E','M','P','O','R','A','R','Y',',',' ',
-       '`','V','a','l','u','e','`',' ','C','H','A','R','(','9','8',')',' ',
-       'N','O','T',' ','N','U','L','L',' ','T','E','M','P','O','R','A','R','Y',
-       ' ','P','R','I','M','A','R','Y',' ','K','E','Y',' ',
-       '`','_','P','r','o','p','e','r','t','y','`',')',' ','H','O','L','D',0};
-
-    rc = MSI_DatabaseOpenViewW(package->db, CreateSql, &view);
+    rc = MSI_DatabaseOpenViewW(package->db, query, &view);
     if (rc != ERROR_SUCCESS)
         return rc;
 
@@ -354,26 +355,24 @@ static UINT create_temp_property_table(MSIPACKAGE *package)
     return rc;
 }
 
-UINT msi_clone_properties(MSIPACKAGE *package)
+UINT msi_clone_properties( MSIDATABASE *db )
 {
-    MSIQUERY *view_select = NULL;
-    UINT rc;
-
     static const WCHAR query_select[] = {
-       'S','E','L','E','C','T',' ','*',' ',
-       'F','R','O','M',' ','`','P','r','o','p','e','r','t','y','`',0};
+        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+        '`','P','r','o','p','e','r','t','y','`',0};
     static const WCHAR query_insert[] = {
-       'I','N','S','E','R','T',' ','i','n','t','o',' ',
-       '`','_','P','r','o','p','e','r','t','y','`',' ',
-       '(','`','_','P','r','o','p','e','r','t','y','`',',',
-       '`','V','a','l','u','e','`',')',' ',
-       'V','A','L','U','E','S',' ','(','?',',','?',')',0};
+        'I','N','S','E','R','T',' ','I','N','T','O',' ',
+        '`','_','P','r','o','p','e','r','t','y','`',' ',
+        '(','`','_','P','r','o','p','e','r','t','y','`',',','`','V','a','l','u','e','`',')',' ',
+        'V','A','L','U','E','S',' ','(','?',',','?',')',0};
     static const WCHAR query_update[] = {
         'U','P','D','A','T','E',' ','`','_','P','r','o','p','e','r','t','y','`',' ',
         'S','E','T',' ','`','V','a','l','u','e','`',' ','=',' ','?',' ',
         'W','H','E','R','E',' ','`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','?',0};
+    MSIQUERY *view_select;
+    UINT rc;
 
-    rc = MSI_DatabaseOpenViewW( package->db, query_select, &view_select );
+    rc = MSI_DatabaseOpenViewW( db, query_select, &view_select );
     if (rc != ERROR_SUCCESS)
         return rc;
 
@@ -394,7 +393,7 @@ UINT msi_clone_properties(MSIPACKAGE *package)
         if (rc != ERROR_SUCCESS)
             break;
 
-        rc = MSI_DatabaseOpenViewW( package->db, query_insert, &view_insert );
+        rc = MSI_DatabaseOpenViewW( db, query_insert, &view_insert );
         if (rc != ERROR_SUCCESS)
         {
             msiobj_release( &rec_select->hdr );
@@ -410,7 +409,7 @@ UINT msi_clone_properties(MSIPACKAGE *package)
 
             TRACE("insert failed, trying update\n");
 
-            rc = MSI_DatabaseOpenViewW( package->db, query_update, &view_update );
+            rc = MSI_DatabaseOpenViewW( db, query_update, &view_update );
             if (rc != ERROR_SUCCESS)
             {
                 WARN("open view failed %u\n", rc);
@@ -446,16 +445,17 @@ UINT msi_clone_properties(MSIPACKAGE *package)
  */
 static UINT set_installed_prop( MSIPACKAGE *package )
 {
-    HKEY hkey = 0;
+    HKEY hkey;
     UINT r;
 
-    r = MSIREG_OpenUninstallKey( package, &hkey, FALSE );
+    if (!package->ProductCode) return ERROR_FUNCTION_FAILED;
+
+    r = MSIREG_OpenUninstallKey( package->ProductCode, package->platform, &hkey, FALSE );
     if (r == ERROR_SUCCESS)
     {
         RegCloseKey( hkey );
-        msi_set_property( package->db, szInstalled, szOne );
+        msi_set_property( package->db, szInstalled, szOne, -1 );
     }
-
     return r;
 }
 
@@ -496,7 +496,7 @@ static UINT set_user_sid_prop( MSIPACKAGE *package )
     if (!ConvertSidToStringSidW( psid, &sid_str ))
         goto done;
 
-    r = msi_set_property( package->db, szUserSID, sid_str );
+    r = msi_set_property( package->db, szUserSID, sid_str, -1 );
 
 done:
     LocalFree( sid_str );
@@ -609,10 +609,12 @@ static void set_msi_assembly_prop(MSIPACKAGE *package)
         return;
 
     size = GetFileVersionInfoSizeW(fusion, &handle);
-    if (!size) return;
+    if (!size)
+        goto done;
 
     version = msi_alloc(size);
-    if (!version) return;
+    if (!version)
+        goto done;
 
     if (!GetFileVersionInfoW(fusion, handle, size, version))
         goto done;
@@ -628,7 +630,7 @@ static void set_msi_assembly_prop(MSIPACKAGE *package)
     if (!val_len || !verstr)
         goto done;
 
-    msi_set_property(package->db, netasm, verstr);
+    msi_set_property( package->db, netasm, verstr, -1 );
 
 done:
     msi_free(fusion);
@@ -637,17 +639,15 @@ done:
 
 static VOID set_installer_properties(MSIPACKAGE *package)
 {
-    WCHAR pth[MAX_PATH];
     WCHAR *ptr;
     OSVERSIONINFOEXW OSVersion;
     MEMORYSTATUSEX msex;
     DWORD verval, len;
-    WCHAR verstr[10], bufstr[20];
+    WCHAR pth[MAX_PATH], verstr[11], bufstr[22];
     HDC dc;
     HKEY hkey;
     LPWSTR username, companyname;
     SYSTEM_INFO sys_info;
-    SYSTEMTIME systemtime;
     LANGID langid;
 
     static const WCHAR szCommonFilesFolder[] = {'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
@@ -662,27 +662,23 @@ static VOID set_installer_properties(MSIPACKAGE *package)
     static const WCHAR szDesktopFolder[] = {'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
     static const WCHAR szProgramMenuFolder[] = {'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0};
     static const WCHAR szAdminToolsFolder[] = {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
-    static const WCHAR szAppDataFolder[] = {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
     static const WCHAR szSystemFolder[] = {'S','y','s','t','e','m','F','o','l','d','e','r',0};
     static const WCHAR szSystem16Folder[] = {'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0};
     static const WCHAR szLocalAppDataFolder[] = {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
     static const WCHAR szMyPicturesFolder[] = {'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
     static const WCHAR szPersonalFolder[] = {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
-    static const WCHAR szWindowsFolder[] = {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
     static const WCHAR szWindowsVolume[] = {'W','i','n','d','o','w','s','V','o','l','u','m','e',0};
-    static const WCHAR szTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
     static const WCHAR szPrivileged[] = {'P','r','i','v','i','l','e','g','e','d',0};
     static const WCHAR szVersion9x[] = {'V','e','r','s','i','o','n','9','X',0};
     static const WCHAR szVersionNT[] = {'V','e','r','s','i','o','n','N','T',0};
     static const WCHAR szMsiNTProductType[] = {'M','s','i','N','T','P','r','o','d','u','c','t','T','y','p','e',0};
-    static const WCHAR szFormat[] = {'%','l','i',0};
+    static const WCHAR szFormat[] = {'%','u',0};
+    static const WCHAR szFormat2[] = {'%','u','.','%','u',0};
     static const WCHAR szWindowsBuild[] = {'W','i','n','d','o','w','s','B','u','i','l','d',0};
     static const WCHAR szServicePackLevel[] = {'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0};
-    static const WCHAR szSix[] = {'6',0 };
     static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 };
     static const WCHAR szVersionDatabase[] = { 'V','e','r','s','i','o','n','D','a','t','a','b','a','s','e',0 };
     static const WCHAR szPhysicalMemory[] = { 'P','h','y','s','i','c','a','l','M','e','m','o','r','y',0 };
-    static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0};
     static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0};
     static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0};
     static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0};
@@ -713,8 +709,6 @@ static VOID set_installer_properties(MSIPACKAGE *package)
     };
     static const WCHAR szUSERNAME[] = {'U','S','E','R','N','A','M','E',0};
     static const WCHAR szCOMPANYNAME[] = {'C','O','M','P','A','N','Y','N','A','M','E',0};
-    static const WCHAR szDate[] = {'D','a','t','e',0};
-    static const WCHAR szTime[] = {'T','i','m','e',0};
     static const WCHAR szUserLanguageID[] = {'U','s','e','r','L','a','n','g','u','a','g','e','I','D',0};
     static const WCHAR szSystemLangID[] = {'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0};
     static const WCHAR szProductState[] = {'P','r','o','d','u','c','t','S','t','a','t','e',0};
@@ -722,195 +716,193 @@ static VOID set_installer_properties(MSIPACKAGE *package)
     static const WCHAR szNetHoodFolder[] = {'N','e','t','H','o','o','d','F','o','l','d','e','r',0};
     static const WCHAR szPrintHoodFolder[] = {'P','r','i','n','t','H','o','o','d','F','o','l','d','e','r',0};
     static const WCHAR szRecentFolder[] = {'R','e','c','e','n','t','F','o','l','d','e','r',0};
+    static const WCHAR szComputerName[] = {'C','o','m','p','u','t','e','r','N','a','m','e',0};
 
     /*
      * Other things that probably should be set:
      *
-     * ComputerName VirtualMemory
-     * ShellAdvSupport DefaultUIFont PackagecodeChanging
-     * CaptionHeight BorderTop BorderSide TextHeight
-     * RedirectedDllSupport
+     * VirtualMemory ShellAdvSupport DefaultUIFont PackagecodeChanging
+     * CaptionHeight BorderTop BorderSide TextHeight RedirectedDllSupport
      */
 
     SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szCommonAppDataFolder, pth);
+    msi_set_property( package->db, szCommonAppDataFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_FAVORITES, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szFavoritesFolder, pth);
+    msi_set_property( package->db, szFavoritesFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szFontsFolder, pth);
+    msi_set_property( package->db, szFontsFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_SENDTO, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szSendToFolder, pth);
+    msi_set_property( package->db, szSendToFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_STARTMENU, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szStartMenuFolder, pth);
+    msi_set_property( package->db, szStartMenuFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_STARTUP, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szStartupFolder, pth);
+    msi_set_property( package->db, szStartupFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_TEMPLATES, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szTemplateFolder, pth);
+    msi_set_property( package->db, szTemplateFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szDesktopFolder, pth);
+    msi_set_property( package->db, szDesktopFolder, pth, -1 );
 
     /* FIXME: set to AllUsers profile path if ALLUSERS is set */
     SHGetFolderPathW(NULL, CSIDL_PROGRAMS, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szProgramMenuFolder, pth);
+    msi_set_property( package->db, szProgramMenuFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_ADMINTOOLS, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szAdminToolsFolder, pth);
+    msi_set_property( package->db, szAdminToolsFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szAppDataFolder, pth);
+    msi_set_property( package->db, szAppDataFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_SYSTEM, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szSystemFolder, pth);
-    msi_set_property(package->db, szSystem16Folder, pth);
+    msi_set_property( package->db, szSystemFolder, pth, -1 );
+    msi_set_property( package->db, szSystem16Folder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szLocalAppDataFolder, pth);
+    msi_set_property( package->db, szLocalAppDataFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_MYPICTURES, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szMyPicturesFolder, pth);
+    msi_set_property( package->db, szMyPicturesFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szPersonalFolder, pth);
+    msi_set_property( package->db, szPersonalFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szWindowsFolder, pth);
+    msi_set_property( package->db, szWindowsFolder, pth, -1 );
     
     SHGetFolderPathW(NULL, CSIDL_PRINTHOOD, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szPrintHoodFolder, pth);
+    msi_set_property( package->db, szPrintHoodFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_NETHOOD, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szNetHoodFolder, pth);
+    msi_set_property( package->db, szNetHoodFolder, pth, -1 );
 
     SHGetFolderPathW(NULL, CSIDL_RECENT, NULL, 0, pth);
     strcatW(pth, szBackSlash);
-    msi_set_property(package->db, szRecentFolder, pth);
+    msi_set_property( package->db, szRecentFolder, pth, -1 );
 
     /* Physical Memory is specified in MB. Using total amount. */
     msex.dwLength = sizeof(msex);
     GlobalMemoryStatusEx( &msex );
-    sprintfW( bufstr, szIntFormat, (int)(msex.ullTotalPhys / 1024 / 1024) );
-    msi_set_property(package->db, szPhysicalMemory, bufstr);
+    len = sprintfW( bufstr, szIntFormat, (int)(msex.ullTotalPhys / 1024 / 1024) );
+    msi_set_property( package->db, szPhysicalMemory, bufstr, len );
 
     SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, pth);
     ptr = strchrW(pth,'\\');
     if (ptr) *(ptr + 1) = 0;
-    msi_set_property(package->db, szWindowsVolume, pth);
+    msi_set_property( package->db, szWindowsVolume, pth, -1 );
     
-    GetTempPathW(MAX_PATH,pth);
-    msi_set_property(package->db, szTempFolder, pth);
+    len = GetTempPathW(MAX_PATH, pth);
+    msi_set_property( package->db, szTempFolder, pth, len );
 
     /* in a wine environment the user is always admin and privileged */
-    msi_set_property(package->db, szAdminUser, szOne);
-    msi_set_property(package->db, szPrivileged, szOne);
+    msi_set_property( package->db, szAdminUser, szOne, -1 );
+    msi_set_property( package->db, szPrivileged, szOne, -1 );
 
     /* set the os things */
     OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
     GetVersionExW((OSVERSIONINFOW *)&OSVersion);
     verval = OSVersion.dwMinorVersion + OSVersion.dwMajorVersion * 100;
-    sprintfW(verstr, szFormat, verval);
+    len = sprintfW( verstr, szFormat, verval );
     switch (OSVersion.dwPlatformId)
     {
         case VER_PLATFORM_WIN32_WINDOWS:    
-            msi_set_property(package->db, szVersion9x, verstr);
+            msi_set_property( package->db, szVersion9x, verstr, len );
             break;
         case VER_PLATFORM_WIN32_NT:
-            msi_set_property(package->db, szVersionNT, verstr);
-            sprintfW(verstr, szFormat,OSVersion.wProductType);
-            msi_set_property(package->db, szMsiNTProductType, verstr);
+            msi_set_property( package->db, szVersionNT, verstr, len );
+            len = sprintfW( bufstr, szFormat,OSVersion.wProductType );
+            msi_set_property( package->db, szMsiNTProductType, bufstr, len );
             break;
     }
-    sprintfW(verstr, szFormat, OSVersion.dwBuildNumber);
-    msi_set_property(package->db, szWindowsBuild, verstr);
-    /* just fudge this */
-    msi_set_property(package->db, szServicePackLevel, szSix);
+    len = sprintfW( bufstr, szFormat, OSVersion.dwBuildNumber );
+    msi_set_property( package->db, szWindowsBuild, bufstr, len );
+    len = sprintfW( bufstr, szFormat, OSVersion.wServicePackMajor );
+    msi_set_property( package->db, szServicePackLevel, bufstr, len );
 
-    sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);
-    msi_set_property( package->db, szVersionMsi, bufstr );
-    sprintfW( bufstr, szFormat, MSI_MAJORVERSION * 100);
-    msi_set_property( package->db, szVersionDatabase, bufstr );
+    len = sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION );
+    msi_set_property( package->db, szVersionMsi, bufstr, len );
+    len = sprintfW( bufstr, szFormat, MSI_MAJORVERSION * 100 );
+    msi_set_property( package->db, szVersionDatabase, bufstr, len );
 
     GetNativeSystemInfo( &sys_info );
-    sprintfW( bufstr, szIntFormat, sys_info.wProcessorLevel );
+    len = sprintfW( bufstr, szIntFormat, sys_info.wProcessorLevel );
+    msi_set_property( package->db, szIntel, bufstr, len );
     if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
     {
-        msi_set_property( package->db, szIntel, bufstr );
-
         GetSystemDirectoryW( pth, MAX_PATH );
         PathAddBackslashW( pth );
-        msi_set_property( package->db, szSystemFolder, pth );
+        msi_set_property( package->db, szSystemFolder, pth, -1 );
 
         SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES, NULL, 0, pth );
         PathAddBackslashW( pth );
-        msi_set_property( package->db, szProgramFilesFolder, pth );
+        msi_set_property( package->db, szProgramFilesFolder, pth, -1 );
 
         SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0, pth );
         PathAddBackslashW( pth );
-        msi_set_property( package->db, szCommonFilesFolder, pth );
+        msi_set_property( package->db, szCommonFilesFolder, pth, -1 );
     }
     else if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
     {
-        msi_set_property( package->db, szMsiAMD64, bufstr );
-        msi_set_property( package->db, szMsix64, bufstr );
-        msi_set_property( package->db, szVersionNT64, verstr );
+        msi_set_property( package->db, szMsiAMD64, bufstr, -1 );
+        msi_set_property( package->db, szMsix64, bufstr, -1 );
+        msi_set_property( package->db, szVersionNT64, verstr, -1 );
 
         GetSystemDirectoryW( pth, MAX_PATH );
         PathAddBackslashW( pth );
-        msi_set_property( package->db, szSystem64Folder, pth );
+        msi_set_property( package->db, szSystem64Folder, pth, -1 );
 
         GetSystemWow64DirectoryW( pth, MAX_PATH );
         PathAddBackslashW( pth );
-        msi_set_property( package->db, szSystemFolder, pth );
+        msi_set_property( package->db, szSystemFolder, pth, -1 );
 
         SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES, NULL, 0, pth );
         PathAddBackslashW( pth );
-        msi_set_property( package->db, szProgramFiles64Folder, pth );
+        msi_set_property( package->db, szProgramFiles64Folder, pth, -1 );
 
         SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILESX86, NULL, 0, pth );
         PathAddBackslashW( pth );
-        msi_set_property( package->db, szProgramFilesFolder, pth );
+        msi_set_property( package->db, szProgramFilesFolder, pth, -1 );
 
         SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0, pth );
         PathAddBackslashW( pth );
-        msi_set_property( package->db, szCommonFiles64Folder, pth );
+        msi_set_property( package->db, szCommonFiles64Folder, pth, -1 );
 
         SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMONX86, NULL, 0, pth );
         PathAddBackslashW( pth );
-        msi_set_property( package->db, szCommonFilesFolder, pth );
+        msi_set_property( package->db, szCommonFilesFolder, pth, -1 );
     }
 
     /* Screen properties. */
     dc = GetDC(0);
-    sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, HORZRES ) );
-    msi_set_property( package->db, szScreenX, bufstr );
-    sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, VERTRES ));
-    msi_set_property( package->db, szScreenY, bufstr );
-    sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, BITSPIXEL ));
-    msi_set_property( package->db, szColorBits, bufstr );
+    len = sprintfW( bufstr, szIntFormat, GetDeviceCaps(dc, HORZRES) );
+    msi_set_property( package->db, szScreenX, bufstr, len );
+    len = sprintfW( bufstr, szIntFormat, GetDeviceCaps(dc, VERTRES) );
+    msi_set_property( package->db, szScreenY, bufstr, len );
+    len = sprintfW( bufstr, szIntFormat, GetDeviceCaps(dc, BITSPIXEL) );
+    msi_set_property( package->db, szColorBits, bufstr, len );
     ReleaseDC(0, dc);
 
     /* USERNAME and COMPANYNAME */
@@ -922,10 +914,10 @@ static VOID set_installer_properties(MSIPACKAGE *package)
     {
         if (!username &&
             (username = msi_reg_get_val_str( hkey, szDefName )))
-            msi_set_property( package->db, szUSERNAME, username );
+            msi_set_property( package->db, szUSERNAME, username, -1 );
         if (!companyname &&
             (companyname = msi_reg_get_val_str( hkey, szDefCompany )))
-            msi_set_property( package->db, szCOMPANYNAME, companyname );
+            msi_set_property( package->db, szCOMPANYNAME, companyname, -1 );
         CloseHandle( hkey );
     }
     if ((!username || !companyname) &&
@@ -933,10 +925,10 @@ static VOID set_installer_properties(MSIPACKAGE *package)
     {
         if (!username &&
             (username = msi_reg_get_val_str( hkey, szRegisteredUser )))
-            msi_set_property( package->db, szUSERNAME, username );
+            msi_set_property( package->db, szUSERNAME, username, -1 );
         if (!companyname &&
             (companyname = msi_reg_get_val_str( hkey, szRegisteredOrganization )))
-            msi_set_property( package->db, szCOMPANYNAME, companyname );
+            msi_set_property( package->db, szCOMPANYNAME, companyname, -1 );
         CloseHandle( hkey );
     }
     msi_free( username );
@@ -945,113 +937,41 @@ static VOID set_installer_properties(MSIPACKAGE *package)
     if ( set_user_sid_prop( package ) != ERROR_SUCCESS)
         ERR("Failed to set the UserSID property\n");
 
-    /* Date and time properties */
-    GetSystemTime( &systemtime );
-    if (GetDateFormatW( LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systemtime,
-                        NULL, bufstr, sizeof(bufstr)/sizeof(bufstr[0]) ))
-        msi_set_property( package->db, szDate, bufstr );
-    else
-        ERR("Couldn't set Date property: GetDateFormat failed with error %d\n", GetLastError());
-
-    if (GetTimeFormatW( LOCALE_USER_DEFAULT,
-                        TIME_FORCE24HOURFORMAT | TIME_NOTIMEMARKER,
-                        &systemtime, NULL, bufstr,
-                        sizeof(bufstr)/sizeof(bufstr[0]) ))
-        msi_set_property( package->db, szTime, bufstr );
-    else
-        ERR("Couldn't set Time property: GetTimeFormat failed with error %d\n", GetLastError());
-
     set_msi_assembly_prop( package );
 
     langid = GetUserDefaultLangID();
-    sprintfW(bufstr, szIntFormat, langid);
-    msi_set_property( package->db, szUserLanguageID, bufstr );
+    len = sprintfW( bufstr, szIntFormat, langid );
+    msi_set_property( package->db, szUserLanguageID, bufstr, len );
 
     langid = GetSystemDefaultLangID();
-    sprintfW(bufstr, szIntFormat, langid);
-    msi_set_property( package->db, szSystemLangID, bufstr );
+    len = sprintfW( bufstr, szIntFormat, langid );
+    msi_set_property( package->db, szSystemLangID, bufstr, len );
 
-    sprintfW(bufstr, szIntFormat, MsiQueryProductStateW(package->ProductCode));
-    msi_set_property( package->db, szProductState, bufstr );
+    len = sprintfW( bufstr, szIntFormat, MsiQueryProductStateW(package->ProductCode) );
+    msi_set_property( package->db, szProductState, bufstr, len );
 
     len = 0;
-    if (!GetUserNameW( NULL, &len ) && GetLastError() == ERROR_MORE_DATA)
+    if (!GetUserNameW( NULL, &len ) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
     {
         WCHAR *username;
         if ((username = msi_alloc( len * sizeof(WCHAR) )))
         {
             if (GetUserNameW( username, &len ))
-                msi_set_property( package->db, szLogonUser, username );
+                msi_set_property( package->db, szLogonUser, username, len - 1 );
             msi_free( username );
         }
     }
-}
-
-static UINT msi_load_summary_properties( MSIPACKAGE *package )
-{
-    UINT rc;
-    MSIHANDLE suminfo;
-    MSIHANDLE hdb = alloc_msihandle( &package->db->hdr );
-    INT count;
-    DWORD len;
-    LPWSTR package_code;
-    static const WCHAR szPackageCode[] = {
-        'P','a','c','k','a','g','e','C','o','d','e',0};
-
-    if (!hdb) {
-        ERR("Unable to allocate handle\n");
-        return ERROR_OUTOFMEMORY;
-    }
-
-    rc = MsiGetSummaryInformationW( hdb, NULL, 0, &suminfo );
-    MsiCloseHandle(hdb);
-    if (rc != ERROR_SUCCESS)
-    {
-        ERR("Unable to open Summary Information\n");
-        return rc;
-    }
-
-    rc = MsiSummaryInfoGetPropertyW( suminfo, PID_PAGECOUNT, NULL,
-                                     &count, NULL, NULL, NULL );
-    if (rc != ERROR_SUCCESS)
-    {
-        WARN("Unable to query page count: %d\n", rc);
-        goto done;
-    }
-
-    /* load package code property */
     len = 0;
-    rc = MsiSummaryInfoGetPropertyW( suminfo, PID_REVNUMBER, NULL,
-                                     NULL, NULL, NULL, &len );
-    if (rc != ERROR_MORE_DATA)
+    if (!GetComputerNameW( NULL, &len ) && GetLastError() == ERROR_BUFFER_OVERFLOW)
     {
-        WARN("Unable to query revision number: %d\n", rc);
-        rc = ERROR_FUNCTION_FAILED;
-        goto done;
-    }
-
-    len++;
-    package_code = msi_alloc( len * sizeof(WCHAR) );
-    rc = MsiSummaryInfoGetPropertyW( suminfo, PID_REVNUMBER, NULL,
-                                     NULL, NULL, package_code, &len );
-    if (rc != ERROR_SUCCESS)
-    {
-        WARN("Unable to query rev number: %d\n", rc);
-        goto done;
+        WCHAR *computername;
+        if ((computername = msi_alloc( len * sizeof(WCHAR) )))
+        {
+            if (GetComputerNameW( computername, &len ))
+                msi_set_property( package->db, szComputerName, computername, len );
+            msi_free( computername );
+        }
     }
-
-    msi_set_property( package->db, szPackageCode, package_code );
-    msi_free( package_code );
-
-    /* load package attributes */
-    count = 0;
-    MsiSummaryInfoGetPropertyW( suminfo, PID_WORDCOUNT, NULL,
-                                &count, NULL, NULL, NULL );
-    package->WordCount = count;
-
-done:
-    MsiCloseHandle(suminfo);
-    return rc;
 }
 
 static MSIPACKAGE *msi_alloc_package( void )
@@ -1065,6 +985,7 @@ static MSIPACKAGE *msi_alloc_package( void )
         list_init( &package->components );
         list_init( &package->features );
         list_init( &package->files );
+        list_init( &package->filepatches );
         list_init( &package->tempfiles );
         list_init( &package->folders );
         list_init( &package->subscriptions );
@@ -1078,6 +999,7 @@ static MSIPACKAGE *msi_alloc_package( void )
         list_init( &package->sourcelist_media );
         list_init( &package->patches );
         list_init( &package->binaries );
+        list_init( &package->cabinet_streams );
     }
 
     return package;
@@ -1106,17 +1028,17 @@ void msi_adjust_privilege_properties( MSIPACKAGE *package )
     if (msi_get_property_int( package->db, szAllUsers, 0 ) == 2)
     {
         TRACE("resetting ALLUSERS property from 2 to 1\n");
-        msi_set_property( package->db, szAllUsers, szOne );
+        msi_set_property( package->db, szAllUsers, szOne, -1 );
     }
-    msi_set_property( package->db, szAdminUser, szOne );
+    msi_set_property( package->db, szAdminUser, szOne, -1 );
 }
 
 MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
 {
-    static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
-    static const WCHAR szpi[] = {'%','i',0};
+    static const WCHAR fmtW[] = {'%','u',0};
     MSIPACKAGE *package;
-    WCHAR uilevel[10];
+    WCHAR uilevel[11];
+    int len;
     UINT r;
 
     TRACE("%p\n", db);
@@ -1127,24 +1049,27 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
         msiobj_addref( &db->hdr );
         package->db = db;
 
+        package->LastAction = NULL;
+        package->LastActionTemplate = NULL;
+        package->LastActionResult = MSI_NULL_INTEGER;
         package->WordCount = 0;
         package->PackagePath = strdupW( db->path );
         package->BaseURL = strdupW( base_url );
 
         create_temp_property_table( package );
-        msi_clone_properties( package );
+        msi_clone_properties( package->db );
         msi_adjust_privilege_properties( package );
 
         package->ProductCode = msi_dup_property( package->db, szProductCode );
         package->script = msi_alloc_zero( sizeof(MSISCRIPT) );
 
-        set_installed_prop( package );
         set_installer_properties( package );
 
-        sprintfW(uilevel,szpi,gUILevel);
-        msi_set_property(package->db, szLevel, uilevel);
+        package->ui_level = gUILevel;
+        len = sprintfW( uilevel, fmtW, gUILevel & INSTALLUILEVEL_MASK );
+        msi_set_property( package->db, szUILevel, uilevel, len );
 
-        r = msi_load_summary_properties( package );
+        r = msi_load_suminfo_properties( package );
         if (r != ERROR_SUCCESS)
         {
             msiobj_release( &package->hdr );
@@ -1156,48 +1081,16 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
 
         package->log_file = INVALID_HANDLE_VALUE;
     }
-
     return package;
 }
 
-/*
- * copy_package_to_temp   [internal]
- *
- * copy the msi file to a temp file to prevent locking a CD
- * with a multi disc install 
- *
- * FIXME: I think this is wrong, and instead of copying the package,
- *        we should read all the tables to memory, then open the
- *        database to read binary streams on demand.
- */ 
-static UINT copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
-{
-    WCHAR path[MAX_PATH];
-
-    GetTempPathW( MAX_PATH, path );
-    GetTempFileNameW( path, szMsi, 0, filename );
-
-    if( !CopyFileW( szPackage, filename, FALSE ) )
-    {
-        UINT error = GetLastError();
-        if ( error == ERROR_FILE_NOT_FOUND )
-            ERR("can't find %s\n", debugstr_w(szPackage));
-        else
-            ERR("failed to copy package %s to %s (%u)\n", debugstr_w(szPackage), debugstr_w(filename), error);
-        DeleteFileW( filename );
-        return error;
-    }
-
-    return ERROR_SUCCESS;
-}
-
 UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename )
 {
     LPINTERNET_CACHE_ENTRY_INFOW cache_entry;
     DWORD size = 0;
     HRESULT hr;
 
-    /* call will always fail, becase size is 0,
+    /* call will always fail, because size is 0,
      * but will return ERROR_FILE_NOT_FOUND first
      * if the file doesn't exist
      */
@@ -1227,7 +1120,7 @@ UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename )
     return ERROR_SUCCESS;
 }
 
-UINT msi_get_local_package_name( LPWSTR path, LPCWSTR suffix )
+UINT msi_create_empty_local_file( LPWSTR path, LPCWSTR suffix )
 {
     static const WCHAR szInstaller[] = {
         '\\','I','n','s','t','a','l','l','e','r','\\',0};
@@ -1260,70 +1153,18 @@ UINT msi_get_local_package_name( LPWSTR path, LPCWSTR suffix )
     return ERROR_SUCCESS;
 }
 
-static UINT apply_registered_patch( MSIPACKAGE *package, LPCWSTR patch_code )
+static enum platform parse_platform( const WCHAR *str )
 {
-    UINT r;
-    DWORD len;
-    WCHAR patch_file[MAX_PATH];
-    MSIDATABASE *patch_db;
-    MSIPATCHINFO *patch_info;
-    MSISUMMARYINFO *si;
-
-    len = sizeof(patch_file) / sizeof(WCHAR);
-    r = MsiGetPatchInfoExW( patch_code, package->ProductCode, NULL, package->Context,
-                            INSTALLPROPERTY_LOCALPACKAGEW, patch_file, &len );
-    if (r != ERROR_SUCCESS)
-    {
-        ERR("failed to get patch filename %u\n", r);
-        return r;
-    }
-
-    r = MSI_OpenDatabaseW( patch_file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
-    if (r != ERROR_SUCCESS)
-    {
-        ERR("failed to open patch database %s\n", debugstr_w( patch_file ));
-        return r;
-    }
-
-    si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
-    if (!si)
-    {
-        msiobj_release( &patch_db->hdr );
-        return ERROR_FUNCTION_FAILED;
-    }
-
-    r = msi_parse_patch_summary( si, &patch_info );
-    msiobj_release( &si->hdr );
-    if (r != ERROR_SUCCESS)
-    {
-        ERR("failed to parse patch summary %u\n", r);
-        msiobj_release( &patch_db->hdr );
-        return r;
-    }
-
-    patch_info->localfile = strdupW( patch_file );
-    if (!patch_info->localfile)
-    {
-        msiobj_release( &patch_db->hdr );
-        return ERROR_OUTOFMEMORY;
-    }
-
-    r = msi_apply_patch_db( package, patch_db, patch_info );
-    msiobj_release( &patch_db->hdr );
-    if (r != ERROR_SUCCESS)
-    {
-        ERR("failed to apply patch %u\n", r);
-        msi_free( patch_info->patchcode );
-        msi_free( patch_info->transforms );
-        msi_free( patch_info->localfile );
-        msi_free( patch_info );
-    }
-    return r;
+    if (!str[0] || !strcmpW( str, szIntel )) return PLATFORM_INTEL;
+    else if (!strcmpW( str, szIntel64 )) return PLATFORM_INTEL64;
+    else if (!strcmpW( str, szX64 ) || !strcmpW( str, szAMD64 )) return PLATFORM_X64;
+    else if (!strcmpW( str, szARM )) return PLATFORM_ARM;
+    return PLATFORM_UNKNOWN;
 }
 
-static UINT msi_parse_summary( MSISUMMARYINFO *si, MSIPACKAGE *package )
+static UINT parse_suminfo( MSISUMMARYINFO *si, MSIPACKAGE *package )
 {
-    WCHAR *template, *p, *q;
+    WCHAR *template, *p, *q, *platform;
     DWORD i, count;
 
     package->version = msi_suminfo_get_int32( si, PID_PAGECOUNT );
@@ -1343,13 +1184,16 @@ static UINT msi_parse_summary( MSISUMMARYINFO *si, MSIPACKAGE *package )
         return ERROR_PATCH_PACKAGE_INVALID;
     }
     *p = 0;
-    if (!template[0] || !strcmpW( template, szIntel ))
-        package->platform = PLATFORM_INTEL;
-    else if (!strcmpW( template, szIntel64 ))
-        package->platform = PLATFORM_INTEL64;
-    else if (!strcmpW( template, szX64 ) || !strcmpW( template, szAMD64 ))
-        package->platform = PLATFORM_X64;
-    else
+    platform = template;
+    if ((q = strchrW( platform, ',' ))) *q = 0;
+    package->platform = parse_platform( platform );
+    while (package->platform == PLATFORM_UNKNOWN && q)
+    {
+        platform = q + 1;
+        if ((q = strchrW( platform, ',' ))) *q = 0;
+        package->platform = parse_platform( platform );
+    }
+    if (package->platform == PLATFORM_UNKNOWN)
     {
         WARN("unknown platform %s\n", debugstr_w(template));
         msi_free( template );
@@ -1389,10 +1233,14 @@ static UINT msi_parse_summary( MSISUMMARYINFO *si, MSIPACKAGE *package )
 
 static UINT validate_package( MSIPACKAGE *package )
 {
-    BOOL is_wow64;
     UINT i;
 
-    IsWow64Process( GetCurrentProcess(), &is_wow64 );
+    if (package->platform == PLATFORM_INTEL64)
+        return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
+#ifndef __arm__
+    if (package->platform == PLATFORM_ARM)
+        return ERROR_INSTALL_PLATFORM_UNSUPPORTED;
+#endif
     if (package->platform == PLATFORM_X64)
     {
         if (!is_64bit && !is_wow64)
@@ -1422,22 +1270,176 @@ static UINT validate_package( MSIPACKAGE *package )
     return ERROR_INSTALL_LANGUAGE_UNSUPPORTED;
 }
 
+static WCHAR *get_product_code( MSIDATABASE *db )
+{
+    static const WCHAR query[] = {
+        'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
+        'F','R','O','M',' ','`','P','r','o','p','e','r','t','y','`',' ',
+        'W','H','E','R','E',' ','`','P','r','o','p','e','r','t','y','`','=',
+        '\'','P','r','o','d','u','c','t','C','o','d','e','\'',0};
+    MSIQUERY *view;
+    MSIRECORD *rec;
+    WCHAR *ret = NULL;
+
+    if (MSI_DatabaseOpenViewW( db, query, &view ) != ERROR_SUCCESS)
+    {
+        return NULL;
+    }
+    if (MSI_ViewExecute( view, 0 ) != ERROR_SUCCESS)
+    {
+        MSI_ViewClose( view );
+        msiobj_release( &view->hdr );
+        return NULL;
+    }
+    if (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
+    {
+        ret = strdupW( MSI_RecordGetString( rec, 1 ) );
+        msiobj_release( &rec->hdr );
+    }
+    MSI_ViewClose( view );
+    msiobj_release( &view->hdr );
+    return ret;
+}
+
+static UINT get_registered_local_package( const WCHAR *product, const WCHAR *package, WCHAR *localfile )
+{
+    MSIINSTALLCONTEXT context;
+    HKEY product_key, props_key;
+    WCHAR *registered_package = NULL, unsquashed[GUID_SIZE];
+    UINT r;
+
+    r = msi_locate_product( product, &context );
+    if (r != ERROR_SUCCESS)
+        return r;
+
+    r = MSIREG_OpenProductKey( product, NULL, context, &product_key, FALSE );
+    if (r != ERROR_SUCCESS)
+        return r;
+
+    r = MSIREG_OpenInstallProps( product, context, NULL, &props_key, FALSE );
+    if (r != ERROR_SUCCESS)
+    {
+        RegCloseKey( product_key );
+        return r;
+    }
+    r = ERROR_FUNCTION_FAILED;
+    registered_package = msi_reg_get_val_str( product_key, INSTALLPROPERTY_PACKAGECODEW );
+    if (!registered_package)
+        goto done;
+
+    unsquash_guid( registered_package, unsquashed );
+    if (!strcmpiW( package, unsquashed ))
+    {
+        WCHAR *filename = msi_reg_get_val_str( props_key, INSTALLPROPERTY_LOCALPACKAGEW );
+        if (!filename)
+            goto done;
+
+        strcpyW( localfile, filename );
+        msi_free( filename );
+        r = ERROR_SUCCESS;
+    }
+done:
+    msi_free( registered_package );
+    RegCloseKey( props_key );
+    RegCloseKey( product_key );
+    return r;
+}
+
+static WCHAR *get_package_code( MSIDATABASE *db )
+{
+    WCHAR *ret;
+    MSISUMMARYINFO *si;
+    UINT r;
+
+    r = msi_get_suminfo( db->storage, 0, &si );
+    if (r != ERROR_SUCCESS)
+    {
+        r = msi_get_db_suminfo( db, 0, &si );
+        if (r != ERROR_SUCCESS)
+        {
+            WARN("failed to load summary info %u\n", r);
+            return NULL;
+        }
+    }
+    ret = msi_suminfo_dup_string( si, PID_REVNUMBER );
+    msiobj_release( &si->hdr );
+    return ret;
+}
+
+static UINT get_local_package( const WCHAR *filename, WCHAR *localfile )
+{
+    WCHAR *product_code, *package_code;
+    MSIDATABASE *db;
+    UINT r;
+
+    if ((r = MSI_OpenDatabaseW( filename, MSIDBOPEN_READONLY, &db )) != ERROR_SUCCESS)
+    {
+        if (GetFileAttributesW( filename ) == INVALID_FILE_ATTRIBUTES)
+            return ERROR_FILE_NOT_FOUND;
+        return r;
+    }
+    if (!(product_code = get_product_code( db )))
+    {
+        msiobj_release( &db->hdr );
+        return ERROR_INSTALL_PACKAGE_INVALID;
+    }
+    if (!(package_code = get_package_code( db )))
+    {
+        msi_free( product_code );
+        msiobj_release( &db->hdr );
+        return ERROR_INSTALL_PACKAGE_INVALID;
+    }
+    r = get_registered_local_package( product_code, package_code, localfile );
+    msi_free( package_code );
+    msi_free( product_code );
+    msiobj_release( &db->hdr );
+    return r;
+}
+
+UINT msi_set_original_database_property( MSIDATABASE *db, const WCHAR *package )
+{
+    UINT r;
+
+    if (UrlIsW( package, URLIS_URL ))
+        r = msi_set_property( db, szOriginalDatabase, package, -1 );
+    else if (package[0] == '#')
+        r = msi_set_property( db, szOriginalDatabase, db->path, -1 );
+    else
+    {
+        DWORD len;
+        WCHAR *path;
+
+        if (!(len = GetFullPathNameW( package, 0, NULL, NULL ))) return GetLastError();
+        if (!(path = msi_alloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
+        len = GetFullPathNameW( package, len, path, NULL );
+        r = msi_set_property( db, szOriginalDatabase, path, len );
+        msi_free( path );
+    }
+    return r;
+}
+
 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
 {
-    static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0};
     static const WCHAR dotmsi[] = {'.','m','s','i',0};
-    MSIDATABASE *db = NULL;
+    MSIDATABASE *db;
     MSIPACKAGE *package;
     MSIHANDLE handle;
+    MSIRECORD *data_row, *info_row;
     LPWSTR ptr, base_url = NULL;
     UINT r;
-    WCHAR temppath[MAX_PATH], localfile[MAX_PATH], cachefile[MAX_PATH];
+    WCHAR localfile[MAX_PATH], cachefile[MAX_PATH];
     LPCWSTR file = szPackage;
     DWORD index = 0;
     MSISUMMARYINFO *si;
+    BOOL delete_on_close = FALSE;
+    LPWSTR productname;
+    WCHAR *info_template;
 
     TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
 
+    MSI_ProcessMessage(NULL, INSTALLMESSAGE_INITIALIZE, 0);
+
+    localfile[0] = 0;
     if( szPackage[0] == '#' )
     {
         handle = atoiW(&szPackage[1]);
@@ -1461,88 +1463,65 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
         if ( UrlIsW( szPackage, URLIS_URL ) )
         {
             r = msi_download_file( szPackage, cachefile );
-            if ( r != ERROR_SUCCESS )
-                return r;
-
-            r = copy_package_to_temp( cachefile, temppath );
-            if ( r != ERROR_SUCCESS )
+            if (r != ERROR_SUCCESS)
                 return r;
 
-            file = temppath;
+            file = cachefile;
 
             base_url = strdupW( szPackage );
-            if ( !base_url )
+            if (!base_url)
                 return ERROR_OUTOFMEMORY;
 
             ptr = strrchrW( base_url, '/' );
             if (ptr) *(ptr + 1) = '\0';
         }
-        else
+        r = get_local_package( file, localfile );
+        if (r != ERROR_SUCCESS || GetFileAttributesW( localfile ) == INVALID_FILE_ATTRIBUTES)
         {
-            r = copy_package_to_temp( szPackage, temppath );
-            if ( r != ERROR_SUCCESS )
+            r = msi_create_empty_local_file( localfile, dotmsi );
+            if (r != ERROR_SUCCESS)
+            {
+                msi_free ( base_url );
                 return r;
+            }
 
-            file = temppath;
+            if (!CopyFileW( file, localfile, FALSE ))
+            {
+                r = GetLastError();
+                WARN("unable to copy package %s to %s (%u)\n", debugstr_w(file), debugstr_w(localfile), r);
+                DeleteFileW( localfile );
+                msi_free ( base_url );
+                return r;
+            }
+            delete_on_close = TRUE;
         }
-
-        r = msi_get_local_package_name( localfile, dotmsi );
+        TRACE("opening package %s\n", debugstr_w( localfile ));
+        r = MSI_OpenDatabaseW( localfile, MSIDBOPEN_TRANSACT, &db );
         if (r != ERROR_SUCCESS)
-            return r;
-
-        TRACE("Copying to local package %s\n", debugstr_w(localfile));
-
-        if (!CopyFileW( file, localfile, FALSE ))
-        {
-            ERR("Unable to copy package (%s -> %s) (error %u)\n",
-                debugstr_w(file), debugstr_w(localfile), GetLastError());
-            return GetLastError();
-        }
-
-        TRACE("Opening relocated package %s\n", debugstr_w( file ));
-
-        /* transforms that add binary streams require that we open the database
-         * read/write, which is safe because we always create a copy that is thrown
-         * away when we're done.
-         */
-        r = MSI_OpenDatabaseW( file, MSIDBOPEN_TRANSACT, &db );
-        if( r != ERROR_SUCCESS )
         {
-            if (file != szPackage)
-                DeleteFileW( file );
-
-            if (GetFileAttributesW(szPackage) == INVALID_FILE_ATTRIBUTES)
-                return ERROR_FILE_NOT_FOUND;
-
+            msi_free ( base_url );
             return r;
         }
-
-        db->localfile = strdupW( localfile );
     }
-
     package = MSI_CreatePackage( db, base_url );
     msi_free( base_url );
     msiobj_release( &db->hdr );
-    if( !package )
-    {
-        if (file != szPackage)
-            DeleteFileW( file );
-
-        return ERROR_INSTALL_PACKAGE_INVALID;
-    }
+    if (!package) return ERROR_INSTALL_PACKAGE_INVALID;
+    package->localfile = strdupW( localfile );
+    package->delete_on_close = delete_on_close;
 
-    if( file != szPackage )
-        track_tempfile( package, file );
-
-    si = MSI_GetSummaryInformationW( db->storage, 0 );
-    if (!si)
+    r = msi_get_suminfo( db->storage, 0, &si );
+    if (r != ERROR_SUCCESS)
     {
-        WARN("failed to load summary info %u\n", r);
-        msiobj_release( &package->hdr );
-        return ERROR_INSTALL_PACKAGE_INVALID;
+        r = msi_get_db_suminfo( db, 0, &si );
+        if (r != ERROR_SUCCESS)
+        {
+            WARN("failed to load summary info\n");
+            msiobj_release( &package->hdr );
+            return ERROR_INSTALL_PACKAGE_INVALID;
+        }
     }
-
-    r = msi_parse_summary( si, package );
+    r = parse_suminfo( si, package );
     msiobj_release( &si->hdr );
     if (r != ERROR_SUCCESS)
     {
@@ -1550,27 +1529,14 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
         msiobj_release( &package->hdr );
         return r;
     }
-
     r = validate_package( package );
     if (r != ERROR_SUCCESS)
     {
         msiobj_release( &package->hdr );
         return r;
     }
-    msi_set_property( package->db, Database, db->path );
-
-    if( UrlIsW( szPackage, URLIS_URL ) )
-        msi_set_property( package->db, szOriginalDatabase, szPackage );
-    else if( szPackage[0] == '#' )
-        msi_set_property( package->db, szOriginalDatabase, db->path );
-    else
-    {
-        WCHAR fullpath[MAX_PATH];
-
-        GetFullPathNameW( szPackage, MAX_PATH, fullpath, NULL );
-        msi_set_property( package->db, szOriginalDatabase, fullpath );
-    }
-
+    msi_set_property( package->db, szDatabase, db->path, -1 );
+    set_installed_prop( package );
     msi_set_context( package );
 
     while (1)
@@ -1583,27 +1549,60 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
 
         TRACE("found registered patch %s\n", debugstr_w(patch_code));
 
-        r = apply_registered_patch( package, patch_code );
+        r = msi_apply_registered_patch( package, patch_code );
         if (r != ERROR_SUCCESS)
         {
             ERR("registered patch failed to apply %u\n", r);
             msiobj_release( &package->hdr );
             return r;
         }
-
         index++;
     }
+    if (index) msi_adjust_privilege_properties( package );
 
-    if (index)
+    r = msi_set_original_database_property( package->db, szPackage );
+    if (r != ERROR_SUCCESS)
     {
-        msi_clone_properties( package );
-        msi_adjust_privilege_properties( package );
+        msiobj_release( &package->hdr );
+        return r;
     }
-
     if (gszLogFile)
         package->log_file = CreateFileW( gszLogFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
                                          OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
 
+    /* FIXME: when should these messages be sent? */
+    data_row = MSI_CreateRecord(3);
+    if (!data_row)
+       return ERROR_OUTOFMEMORY;
+    MSI_RecordSetStringW(data_row, 0, NULL);
+    MSI_RecordSetInteger(data_row, 1, 0);
+    MSI_RecordSetInteger(data_row, 2, package->num_langids ? package->langids[0] : 0);
+    MSI_RecordSetInteger(data_row, 3, msi_get_string_table_codepage(package->db->strings));
+    MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, data_row);
+
+    info_row = MSI_CreateRecord(0);
+    if (!info_row)
+    {
+       msiobj_release(&data_row->hdr);
+       return ERROR_OUTOFMEMORY;
+    }
+    info_template = msi_get_error_message(package->db, MSIERR_INFO_LOGGINGSTART);
+    MSI_RecordSetStringW(info_row, 0, info_template);
+    msi_free(info_template);
+    MSI_ProcessMessage(package, INSTALLMESSAGE_INFO|MB_ICONHAND, info_row);
+
+    MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, data_row);
+
+    productname = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
+    MSI_RecordSetInteger(data_row, 1, 1);
+    MSI_RecordSetStringW(data_row, 2, productname);
+    MSI_RecordSetStringW(data_row, 3, NULL);
+    MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, data_row);
+
+    msi_free(productname);
+    msiobj_release(&info_row->hdr);
+    msiobj_release(&data_row->hdr);
+
     *pPackage = package;
     return ERROR_SUCCESS;
 }
@@ -1635,6 +1634,8 @@ UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phP
             ret = ERROR_NOT_ENOUGH_MEMORY;
         msiobj_release( &package->hdr );
     }
+    else
+        MSI_ProcessMessage(NULL, INSTALLMESSAGE_TERMINATE, 0);
 
     return ret;
 }
@@ -1701,23 +1702,172 @@ MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
     return handle;
 }
 
-INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
-                               MSIRECORD *record)
+static INT internal_ui_handler(MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record, LPCWSTR message)
+{
+    static const WCHAR szActionData[] = {'A','c','t','i','o','n','D','a','t','a',0};
+    static const WCHAR szActionText[] = {'A','c','t','i','o','n','T','e','x','t',0};
+    static const WCHAR szSetProgress[] = {'S','e','t','P','r','o','g','r','e','s','s',0};
+    static const WCHAR szWindows_Installer[] =
+        {'W','i','n','d','o','w','s',' ','I','n','s','t','a','l','l','e','r',0};
+
+    if (!package || (package->ui_level & INSTALLUILEVEL_MASK) == INSTALLUILEVEL_NONE)
+        return 0;
+
+    /* todo: check if message needs additional styles (topmost/foreground/modality?) */
+
+    switch (eMessageType & 0xff000000)
+    {
+    case INSTALLMESSAGE_FATALEXIT:
+    case INSTALLMESSAGE_ERROR:
+    case INSTALLMESSAGE_OUTOFDISKSPACE:
+        if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
+        if (!(eMessageType & MB_ICONMASK))
+            eMessageType |= MB_ICONEXCLAMATION;
+        return MessageBoxW(gUIhwnd, message, szWindows_Installer, eMessageType & 0x00ffffff);
+    case INSTALLMESSAGE_WARNING:
+        if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
+        if (!(eMessageType & MB_ICONMASK))
+            eMessageType |= MB_ICONASTERISK;
+        return MessageBoxW(gUIhwnd, message, szWindows_Installer, eMessageType & 0x00ffffff);
+    case INSTALLMESSAGE_USER:
+        if (package->ui_level & INSTALLUILEVEL_PROGRESSONLY) return 0;
+        if (!(eMessageType & MB_ICONMASK))
+            eMessageType |= MB_USERICON;
+        return MessageBoxW(gUIhwnd, message, szWindows_Installer, eMessageType & 0x00ffffff);
+    case INSTALLMESSAGE_INFO:
+    case INSTALLMESSAGE_INITIALIZE:
+    case INSTALLMESSAGE_TERMINATE:
+        return 0;
+    case INSTALLMESSAGE_SHOWDIALOG:
+    {
+        LPWSTR dialog = msi_dup_record_field(record, 0);
+        INT rc = ACTION_DialogBox(package, dialog);
+        msi_free(dialog);
+        return rc;
+    }
+    case INSTALLMESSAGE_ACTIONSTART:
+    {
+        LPWSTR deformatted;
+        MSIRECORD *uirow = MSI_CreateRecord(1);
+        if (!uirow) return -1;
+        deformat_string(package, MSI_RecordGetString(record, 2), &deformatted);
+        MSI_RecordSetStringW(uirow, 1, deformatted);
+        msi_event_fire(package, szActionText, uirow);
+
+        msi_free(deformatted);
+        msiobj_release(&uirow->hdr);
+        return 1;
+    }
+    case INSTALLMESSAGE_ACTIONDATA:
+    {
+        MSIRECORD *uirow = MSI_CreateRecord(1);
+        if (!uirow) return -1;
+        MSI_RecordSetStringW(uirow, 1, message);
+        msi_event_fire(package, szActionData, uirow);
+        msiobj_release(&uirow->hdr);
+
+        if (package->action_progress_increment)
+        {
+            uirow = MSI_CreateRecord(2);
+            if (!uirow) return -1;
+            MSI_RecordSetInteger(uirow, 1, 2);
+            MSI_RecordSetInteger(uirow, 2, package->action_progress_increment);
+            msi_event_fire(package, szSetProgress, uirow);
+            msiobj_release(&uirow->hdr);
+        }
+        return 1;
+    }
+    case INSTALLMESSAGE_PROGRESS:
+        msi_event_fire(package, szSetProgress, record);
+        return 1;
+    case INSTALLMESSAGE_COMMONDATA:
+        switch (MSI_RecordGetInteger(record, 1))
+        {
+        case 0:
+        case 1:
+            /* do nothing */
+            return 0;
+        default:
+            /* fall through */
+            ;
+        }
+    default:
+        FIXME("internal UI not implemented for message 0x%08x (UI level = %x)\n", eMessageType, package->ui_level);
+        return 0;
+    }
+}
+
+static const WCHAR szActionNotFound[] = {'D','E','B','U','G',':',' ','E','r','r','o','r',' ','[','1',']',':',' ',' ','A','c','t','i','o','n',' ','n','o','t',' ','f','o','u','n','d',':',' ','[','2',']',0};
+
+static const struct
+{
+    int id;
+    const WCHAR *text;
+}
+internal_errors[] =
+{
+    {2726, szActionNotFound},
+    {0}
+};
+
+static LPCWSTR get_internal_error_message(int error)
+{
+    int i = 0;
+
+    while (internal_errors[i].id != 0)
+    {
+        if (internal_errors[i].id == error)
+            return internal_errors[i].text;
+        i++;
+    }
+
+    FIXME("missing error message %d\n", error);
+    return NULL;
+}
+
+/* Returned string must be freed */
+LPWSTR msi_get_error_message(MSIDATABASE *db, int error)
+{
+    static const WCHAR query[] =
+        {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
+         'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
+         '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
+    MSIRECORD *record;
+    LPWSTR ret = NULL;
+
+    if ((record = MSI_QueryGetRecord(db, query, error)))
+    {
+        ret = msi_dup_record_field(record, 1);
+        msiobj_release(&record->hdr);
+    }
+    else if (error < 2000)
+    {
+        int len = LoadStringW(msi_hInstance, IDS_ERROR_BASE + error, (LPWSTR) &ret, 0);
+        if (len)
+        {
+            ret = msi_alloc((len + 1) * sizeof(WCHAR));
+            LoadStringW(msi_hInstance, IDS_ERROR_BASE + error, ret, len + 1);
+        }
+        else
+            ret = NULL;
+    }
+
+    return ret;
+}
+
+INT MSI_ProcessMessageVerbatim(MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record)
 {
-    static const WCHAR szActionData[] =
-        {'A','c','t','i','o','n','D','a','t','a',0};
-    static const WCHAR szSetProgress[] =
-        {'S','e','t','P','r','o','g','r','e','s','s',0};
-    static const WCHAR szActionText[] =
-        {'A','c','t','i','o','n','T','e','x','t',0};
-    LPWSTR message;
-    DWORD sz, total_size = 0, log_type = 0;
-    INT i, rc = 0;
+    LPWSTR message = {0};
+    DWORD len, log_type = 0;
+    UINT res;
+    INT rc = 0;
     char *msg;
-    int len;
 
     TRACE("%x\n", eMessageType);
+    if (TRACE_ON(msi)) dump_record(record);
 
+    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_FATALEXIT)
+        log_type |= INSTALLLOGMODE_FATALEXIT;
     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
         log_type |= INSTALLLOGMODE_ERROR;
     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
@@ -1726,103 +1876,67 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
         log_type |= INSTALLLOGMODE_USER;
     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
         log_type |= INSTALLLOGMODE_INFO;
+    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_RESOLVESOURCE)
+        log_type |= INSTALLLOGMODE_RESOLVESOURCE;
+    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_OUTOFDISKSPACE)
+        log_type |= INSTALLLOGMODE_OUTOFDISKSPACE;
     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
         log_type |= INSTALLLOGMODE_COMMONDATA;
     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
         log_type |= INSTALLLOGMODE_ACTIONSTART;
     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
         log_type |= INSTALLLOGMODE_ACTIONDATA;
-    /* just a guess */
     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
-        log_type |= 0x800;
-
-    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
-    {
-        static const WCHAR template_s[]=
-            {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ',0};
-        static const WCHAR format[] = 
-            {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
-        WCHAR timet[0x100];
-        LPCWSTR action_text, action;
-        LPWSTR deformatted = NULL;
-
-        GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
-
-        action = MSI_RecordGetString(record, 1);
-        action_text = MSI_RecordGetString(record, 2);
-
-        if (!action || !action_text)
-            return IDOK;
-
-        deformat_string(package, action_text, &deformatted);
-
-        len = strlenW(timet) + strlenW(action) + strlenW(template_s);
-        if (deformatted)
-            len += strlenW(deformatted);
-        message = msi_alloc(len*sizeof(WCHAR));
-        sprintfW(message, template_s, timet, action);
-        if (deformatted)
-            strcatW(message, deformatted);
-        msi_free(deformatted);
-    }
-    else
-    {
-        INT msg_field=1;
-        message = msi_alloc(1*sizeof (WCHAR));
-        message[0]=0;
-        msg_field = MSI_RecordGetFieldCount(record);
-        for (i = 1; i <= msg_field; i++)
-        {
-            LPWSTR tmp;
-            WCHAR number[3];
-            static const WCHAR format[] = { '%','i',':',' ',0};
-            sz = 0;
-            MSI_RecordGetStringW(record,i,NULL,&sz);
-            sz+=4;
-            total_size+=sz*sizeof(WCHAR);
-            tmp = msi_alloc(sz*sizeof(WCHAR));
-            message = msi_realloc(message,total_size*sizeof (WCHAR));
-
-            MSI_RecordGetStringW(record,i,tmp,&sz);
-
-            if (msg_field > 1)
-            {
-                sprintfW(number,format,i);
-                strcatW(message,number);
-            }
-            strcatW(message,tmp);
-            if (msg_field > 1)
-                strcatW(message, szSpace);
-
-            msi_free(tmp);
-        }
+        log_type |= INSTALLLOGMODE_PROGRESS;
+    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INITIALIZE)
+        log_type |= INSTALLLOGMODE_INITIALIZE;
+    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_TERMINATE)
+        log_type |= INSTALLLOGMODE_TERMINATE;
+    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_SHOWDIALOG)
+        log_type |= INSTALLLOGMODE_SHOWDIALOG;
+
+    if (!package || !record)
+        message = NULL;
+    else {
+        res = MSI_FormatRecordW(package, record, message, &len);
+        if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
+            return res;
+        len++;
+        message = msi_alloc(len * sizeof(WCHAR));
+        if (!message) return ERROR_OUTOFMEMORY;
+        MSI_FormatRecordW(package, record, message, &len);
     }
 
-    TRACE("%p %p %p %x %x %s\n", gUIHandlerA, gUIHandlerW, gUIHandlerRecord,
-          gUIFilter, log_type, debugstr_w(message));
-
     /* convert it to ASCII */
     len = WideCharToMultiByte( CP_ACP, 0, message, -1, NULL, 0, NULL, NULL );
     msg = msi_alloc( len );
     WideCharToMultiByte( CP_ACP, 0, message, -1, msg, len, NULL, NULL );
 
-    if (gUIHandlerW && (gUIFilter & log_type))
+    if (gUIHandlerRecord && (gUIFilterRecord & log_type))
     {
-        rc = gUIHandlerW( gUIContext, eMessageType, message );
+        MSIHANDLE rec = alloc_msihandle(&record->hdr);
+        TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, hRecord=%u)\n",
+              gUIHandlerRecord, gUIContextRecord, eMessageType, rec);
+        rc = gUIHandlerRecord( gUIContextRecord, eMessageType, rec );
+        MsiCloseHandle( rec );
     }
-    else if (gUIHandlerA && (gUIFilter & log_type))
+    if (!rc && gUIHandlerW && (gUIFilter & log_type))
     {
-        rc = gUIHandlerA( gUIContext, eMessageType, msg );
+        TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, szMessage=%s)\n",
+              gUIHandlerW, gUIContext, eMessageType, debugstr_w(message));
+        rc = gUIHandlerW( gUIContext, eMessageType, message );
     }
-    else if (gUIHandlerRecord && (gUIFilter & log_type))
+    else if (!rc && gUIHandlerA && (gUIFilter & log_type))
     {
-        MSIHANDLE rec = MsiCreateRecord( 1 );
-        MsiRecordSetStringW( rec, 0, message );
-        rc = gUIHandlerRecord( gUIContext, eMessageType, rec );
-        MsiCloseHandle( rec );
+        TRACE("Calling UI handler %p(pvContext=%p, iMessageType=%08x, szMessage=%s)\n",
+              gUIHandlerA, gUIContext, eMessageType, debugstr_a(msg));
+        rc = gUIHandlerA( gUIContext, eMessageType, msg );
     }
 
-    if (!rc && package->log_file != INVALID_HANDLE_VALUE &&
+    if (!rc)
+        rc = internal_ui_handler(package, eMessageType, record, message);
+
+    if (!rc && package && package->log_file != INVALID_HANDLE_VALUE &&
         (eMessageType & 0xff000000) != INSTALLMESSAGE_PROGRESS)
     {
         DWORD written;
@@ -1832,36 +1946,113 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
     msi_free( msg );
     msi_free( message );
 
+    return rc;
+}
+
+INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record )
+{
     switch (eMessageType & 0xff000000)
     {
-    case INSTALLMESSAGE_ACTIONDATA:
-        /* FIXME: format record here instead of in ui_actiondata to get the
-         * correct action data for external scripts */
-        ControlEvent_FireSubscribedEvent(package, szActionData, record);
+    case INSTALLMESSAGE_FATALEXIT:
+    case INSTALLMESSAGE_ERROR:
+    case INSTALLMESSAGE_WARNING:
+    case INSTALLMESSAGE_USER:
+    case INSTALLMESSAGE_INFO:
+    case INSTALLMESSAGE_OUTOFDISKSPACE:
+        if (MSI_RecordGetInteger(record, 1) != MSI_NULL_INTEGER)
+        {
+            /* error message */
+
+            LPWSTR template;
+            LPWSTR template_rec = NULL, template_prefix = NULL;
+            int error = MSI_RecordGetInteger(record, 1);
+
+            if (MSI_RecordIsNull(record, 0))
+            {
+                if (error >= 32)
+                {
+                    template_rec = msi_get_error_message(package->db, error);
+
+                    if (!template_rec && error >= 2000)
+                    {
+                        /* internal error, not localized */
+                        if ((template_rec = (LPWSTR) get_internal_error_message(error)))
+                        {
+                            MSI_RecordSetStringW(record, 0, template_rec);
+                            MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_INFO, record);
+                        }
+                        template_rec = msi_get_error_message(package->db, MSIERR_INSTALLERROR);
+                        MSI_RecordSetStringW(record, 0, template_rec);
+                        MSI_ProcessMessageVerbatim(package, eMessageType, record);
+                        msi_free(template_rec);
+                        return 0;
+                    }
+                }
+            }
+            else
+                template_rec = msi_dup_record_field(record, 0);
+
+            template_prefix = msi_get_error_message(package->db, eMessageType >> 24);
+            if (!template_prefix) template_prefix = strdupW(szEmpty);
+
+            if (!template_rec)
+            {
+                /* always returns 0 */
+                MSI_RecordSetStringW(record, 0, template_prefix);
+                MSI_ProcessMessageVerbatim(package, eMessageType, record);
+                msi_free(template_prefix);
+                return 0;
+            }
+
+            template = msi_alloc((strlenW(template_rec) + strlenW(template_prefix) + 1) * sizeof(WCHAR));
+            if (!template) return ERROR_OUTOFMEMORY;
+
+            strcpyW(template, template_prefix);
+            strcatW(template, template_rec);
+            MSI_RecordSetStringW(record, 0, template);
+
+            msi_free(template_prefix);
+            msi_free(template_rec);
+            msi_free(template);
+        }
         break;
     case INSTALLMESSAGE_ACTIONSTART:
     {
-        MSIRECORD *uirow;
-        LPWSTR deformated;
-        LPCWSTR action_text = MSI_RecordGetString(record, 2);
+        WCHAR *template = msi_get_error_message(package->db, MSIERR_ACTIONSTART);
+        MSI_RecordSetStringW(record, 0, template);
+        msi_free(template);
 
-        deformat_string(package, action_text, &deformated);
-        uirow = MSI_CreateRecord(1);
-        MSI_RecordSetStringW(uirow, 1, deformated);
-        TRACE("INSTALLMESSAGE_ACTIONSTART: %s\n", debugstr_w(deformated));
-        msi_free(deformated);
-
-        ControlEvent_FireSubscribedEvent(package, szActionText, uirow);
-
-        msiobj_release(&uirow->hdr);
+        msi_free(package->LastAction);
+        msi_free(package->LastActionTemplate);
+        package->LastAction = msi_dup_record_field(record, 1);
+        if (!package->LastAction) package->LastAction = strdupW(szEmpty);
+        package->LastActionTemplate = msi_dup_record_field(record, 3);
         break;
     }
-    case INSTALLMESSAGE_PROGRESS:
-        ControlEvent_FireSubscribedEvent(package, szSetProgress, record);
+    case INSTALLMESSAGE_ACTIONDATA:
+        if (package->LastAction && package->LastActionTemplate)
+        {
+            static const WCHAR template_s[] =
+                {'{','{','%','s',':',' ','}','}','%','s',0};
+            WCHAR *template;
+
+            template = msi_alloc((strlenW(package->LastAction) + strlenW(package->LastActionTemplate) + 7) * sizeof(WCHAR));
+            if (!template) return ERROR_OUTOFMEMORY;
+            sprintfW(template, template_s, package->LastAction, package->LastActionTemplate);
+            MSI_RecordSetStringW(record, 0, template);
+            msi_free(template);
+        }
         break;
+    case INSTALLMESSAGE_COMMONDATA:
+    {
+        WCHAR *template = msi_get_error_message(package->db, MSIERR_COMMONDATA);
+        MSI_RecordSetStringW(record, 0, template);
+        msi_free(template);
+    }
+    break;
     }
 
-    return ERROR_SUCCESS;
+    return MSI_ProcessMessageVerbatim(package, eMessageType, record);
 }
 
 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
@@ -1871,6 +2062,14 @@ INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
     MSIPACKAGE *package = NULL;
     MSIRECORD *record = NULL;
 
+    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INITIALIZE ||
+        (eMessageType & 0xff000000) == INSTALLMESSAGE_TERMINATE)
+        return -1;
+
+    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA &&
+        MsiRecordGetInteger(hRecord, 1) != 2)
+        return -1;
+
     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
     if( !package )
     {
@@ -1953,71 +2152,65 @@ void msi_reset_folders( MSIPACKAGE *package, BOOL source )
     }
 }
 
-UINT msi_set_property( MSIDATABASE *db, LPCWSTR szName, LPCWSTR szValue )
+UINT msi_set_property( MSIDATABASE *db, const WCHAR *name, const WCHAR *value, int len )
 {
-    MSIQUERY *view;
-    MSIRECORD *row = NULL;
-    UINT rc;
-    DWORD sz = 0;
-    WCHAR Query[1024];
-
-    static const WCHAR Insert[] = {
-        'I','N','S','E','R','T',' ','i','n','t','o',' ',
-        '`','_','P','r','o','p','e','r','t','y','`',' ','(',
-        '`','_','P','r','o','p','e','r','t','y','`',',',
-        '`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
-        ,' ','(','?',',','?',')',0};
-    static const WCHAR Update[] = {
-        'U','P','D','A','T','E',' ','`','_','P','r','o','p','e','r','t','y','`',
-        ' ','s','e','t',' ','`','V','a','l','u','e','`',' ','=',' ','?',' ',
-        'w','h','e','r','e',' ','`','_','P','r','o','p','e','r','t','y','`',
-        ' ','=',' ','\'','%','s','\'',0};
-    static const WCHAR Delete[] = {
+    static const WCHAR insert_query[] = {
+        'I','N','S','E','R','T',' ','I','N','T','O',' ',
+        '`','_','P','r','o','p','e','r','t','y','`',' ',
+        '(','`','_','P','r','o','p','e','r','t','y','`',',','`','V','a','l','u','e','`',')',' ',
+        'V','A','L','U','E','S',' ','(','?',',','?',')',0};
+    static const WCHAR update_query[] = {
+        'U','P','D','A','T','E',' ','`','_','P','r','o','p','e','r','t','y','`',' ',
+        'S','E','T',' ','`','V','a','l','u','e','`',' ','=',' ','?',' ','W','H','E','R','E',' ',
+        '`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
+    static const WCHAR delete_query[] = {
         'D','E','L','E','T','E',' ','F','R','O','M',' ',
         '`','_','P','r','o','p','e','r','t','y','`',' ','W','H','E','R','E',' ',
         '`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
+    MSIQUERY *view;
+    MSIRECORD *row = NULL;
+    DWORD sz = 0;
+    WCHAR query[1024];
+    UINT rc;
 
-    TRACE("%p %s %s\n", db, debugstr_w(szName), debugstr_w(szValue));
+    TRACE("%p %s %s %d\n", db, debugstr_w(name), debugstr_wn(value, len), len);
 
-    if (!szName)
+    if (!name)
         return ERROR_INVALID_PARAMETER;
 
     /* this one is weird... */
-    if (!szName[0])
-        return szValue ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
+    if (!name[0])
+        return value ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
+
+    if (value && len < 0) len = strlenW( value );
 
-    rc = msi_get_property(db, szName, 0, &sz);
-    if (!szValue || !*szValue)
+    rc = msi_get_property( db, name, 0, &sz );
+    if (!value || (!*value && !len))
     {
-        sprintfW(Query, Delete, szName);
+        sprintfW( query, delete_query, name );
     }
     else if (rc == ERROR_MORE_DATA || rc == ERROR_SUCCESS)
     {
-        sprintfW(Query, Update, szName);
-
+        sprintfW( query, update_query, name );
         row = MSI_CreateRecord(1);
-        MSI_RecordSetStringW(row, 1, szValue);
+        msi_record_set_string( row, 1, value, len );
     }
     else
     {
-        strcpyW(Query, Insert);
-
+        strcpyW( query, insert_query );
         row = MSI_CreateRecord(2);
-        MSI_RecordSetStringW(row, 1, szName);
-        MSI_RecordSetStringW(row, 2, szValue);
+        msi_record_set_string( row, 1, name, -1 );
+        msi_record_set_string( row, 2, value, len );
     }
 
-    rc = MSI_DatabaseOpenViewW(db, Query, &view);
+    rc = MSI_DatabaseOpenViewW(db, query, &view);
     if (rc == ERROR_SUCCESS)
     {
         rc = MSI_ViewExecute(view, row);
         MSI_ViewClose(view);
         msiobj_release(&view->hdr);
     }
-
-    if (row)
-      msiobj_release(&row->hdr);
-
+    if (row) msiobj_release(&row->hdr);
     return rc;
 }
 
@@ -2064,8 +2257,8 @@ UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue
         return ERROR_SUCCESS;
     }
 
-    ret = msi_set_property( package->db, szName, szValue );
-    if (ret == ERROR_SUCCESS && !strcmpW( szName, cszSourceDir ))
+    ret = msi_set_property( package->db, szName, szValue, -1 );
+    if (ret == ERROR_SUCCESS && !strcmpW( szName, szSourceDir ))
         msi_reset_folders( package, TRUE );
 
     msiobj_release( &package->hdr );
@@ -2074,19 +2267,53 @@ UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue
 
 static MSIRECORD *msi_get_property_row( MSIDATABASE *db, LPCWSTR name )
 {
-    MSIQUERY *view;
+    static const WCHAR query[]= {
+        'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
+        'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`',' ',
+        'W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`','=','?',0};
     MSIRECORD *rec, *row = NULL;
+    MSIQUERY *view;
     UINT r;
 
-    static const WCHAR query[]= {
-        'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
-        'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
-        ' ','W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
-        '=','?',0};
+    static const WCHAR szDate[] = {'D','a','t','e',0};
+    static const WCHAR szTime[] = {'T','i','m','e',0};
+    WCHAR *buffer;
+    int length;
 
     if (!name || !*name)
         return NULL;
 
+    if (!strcmpW(name, szDate))
+    {
+        length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, NULL, 0);
+        if (!length)
+            return NULL;
+        buffer = msi_alloc(length * sizeof(WCHAR));
+        GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, buffer, length);
+
+        row = MSI_CreateRecord(1);
+        if (!row)
+            return NULL;
+        MSI_RecordSetStringW(row, 1, buffer);
+        msi_free(buffer);
+        return row;
+    }
+    else if (!strcmpW(name, szTime))
+    {
+        length = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER, NULL, NULL, NULL, 0);
+        if (!length)
+            return NULL;
+        buffer = msi_alloc(length * sizeof(WCHAR));
+        GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER, NULL, NULL, buffer, length);
+
+        row = MSI_CreateRecord(1);
+        if (!row)
+            return NULL;
+        MSI_RecordSetStringW(row, 1, buffer);
+        msi_free(buffer);
+        return row;
+    }
+
     rec = MSI_CreateRecord(1);
     if (!rec)
         return NULL;
@@ -2101,7 +2328,6 @@ static MSIRECORD *msi_get_property_row( MSIDATABASE *db, LPCWSTR name )
         MSI_ViewClose(view);
         msiobj_release(&view->hdr);
     }
-
     msiobj_release(&rec->hdr);
     return row;
 }
@@ -2113,6 +2339,8 @@ UINT msi_get_property( MSIDATABASE *db, LPCWSTR szName,
     MSIRECORD *row;
     UINT rc = ERROR_FUNCTION_FAILED;
 
+    TRACE("%p %s %p %p\n", db, debugstr_w(szName), szValueBuf, pchValueBuf);
+
     row = msi_get_property_row( db, szName );
 
     if (*pchValueBuf > 0)
@@ -2125,7 +2353,7 @@ UINT msi_get_property( MSIDATABASE *db, LPCWSTR szName,
     }
 
     if (rc == ERROR_SUCCESS)
-        TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
+        TRACE("returning %s for property %s\n", debugstr_wn(szValueBuf, *pchValueBuf),
             debugstr_w(szName));
     else if (rc == ERROR_MORE_DATA)
         TRACE("need %d sized buffer for %s\n", *pchValueBuf,
@@ -2176,6 +2404,7 @@ static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
     MSIRECORD *row = NULL;
     UINT r = ERROR_FUNCTION_FAILED;
     LPCWSTR val = NULL;
+    DWORD len = 0;
 
     TRACE("%u %s %p %p\n", handle, debugstr_w(name),
           szValueBuf->str.w, pchValueBuf );
@@ -2190,7 +2419,6 @@ static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
         IWineMsiRemotePackage *remote_package;
         LPWSTR value = NULL;
         BSTR bname;
-        DWORD len;
 
         remote_package = (IWineMsiRemotePackage *)msi_get_remote( handle );
         if (!remote_package)
@@ -2203,7 +2431,6 @@ static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
             return ERROR_OUTOFMEMORY;
         }
 
-        len = 0;
         hr = IWineMsiRemotePackage_GetProperty( remote_package, bname, NULL, &len );
         if (FAILED(hr))
             goto done;
@@ -2216,11 +2443,11 @@ static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
             goto done;
         }
 
-        hr = IWineMsiRemotePackage_GetProperty( remote_package, bname, (BSTR *)value, &len );
+        hr = IWineMsiRemotePackage_GetProperty( remote_package, bname, value, &len );
         if (FAILED(hr))
             goto done;
 
-        r = msi_strcpy_to_awstring( value, szValueBuf, pchValueBuf );
+        r = msi_strcpy_to_awstring( value, len, szValueBuf, pchValueBuf );
 
         /* Bug required by Adobe installers */
         if (!szValueBuf->unicode && !szValueBuf->str.a)
@@ -2244,12 +2471,12 @@ done:
 
     row = msi_get_property_row( package->db, name );
     if (row)
-        val = MSI_RecordGetString( row, 1 );
+        val = msi_record_get_string( row, 1, (int *)&len );
 
     if (!val)
         val = szEmpty;
 
-    r = msi_strcpy_to_awstring( val, szValueBuf, pchValueBuf );
+    r = msi_strcpy_to_awstring( val, len, szValueBuf, pchValueBuf );
 
     if (row)
         msiobj_release( &row->hdr );
@@ -2305,7 +2532,7 @@ static HRESULT WINAPI mrp_QueryInterface( IWineMsiRemotePackage *iface,
     if( IsEqualCLSID( riid, &IID_IUnknown ) ||
         IsEqualCLSID( riid, &IID_IWineMsiRemotePackage ) )
     {
-        IUnknown_AddRef( iface );
+        IWineMsiRemotePackage_AddRef( iface );
         *ppobj = iface;
         return S_OK;
     }
@@ -2368,15 +2595,11 @@ static HRESULT WINAPI mrp_GetActiveDatabase( IWineMsiRemotePackage *iface, MSIHA
     return S_OK;
 }
 
-static HRESULT WINAPI mrp_GetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR *value, DWORD *size )
+static HRESULT WINAPI mrp_GetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR value, DWORD *size )
 {
     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
-    UINT r;
-
-    r = MsiGetPropertyW(This->package, (LPWSTR)property, (LPWSTR)value, size);
-    if (r != ERROR_SUCCESS)
-        return HRESULT_FROM_WIN32(r);
-
+    UINT r = MsiGetPropertyW(This->package, property, value, size);
+    if (r != ERROR_SUCCESS) return HRESULT_FROM_WIN32(r);
     return S_OK;
 }
 
@@ -2408,10 +2631,10 @@ static HRESULT WINAPI mrp_Sequence( IWineMsiRemotePackage *iface, BSTR table, in
     return HRESULT_FROM_WIN32(r);
 }
 
-static HRESULT WINAPI mrp_GetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR *value, DWORD *size )
+static HRESULT WINAPI mrp_GetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR value, DWORD *size )
 {
     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
-    UINT r = MsiGetTargetPathW(This->package, (LPWSTR)folder, (LPWSTR)value, size);
+    UINT r = MsiGetTargetPathW(This->package, folder, value, size);
     return HRESULT_FROM_WIN32(r);
 }
 
@@ -2422,10 +2645,10 @@ static HRESULT WINAPI mrp_SetTargetPath( IWineMsiRemotePackage *iface, BSTR fold
     return HRESULT_FROM_WIN32(r);
 }
 
-static HRESULT WINAPI mrp_GetSourcePath( IWineMsiRemotePackage *iface, BSTR folder, BSTR *value, DWORD *size )
+static HRESULT WINAPI mrp_GetSourcePath( IWineMsiRemotePackage *iface, BSTR folder, BSTR value, DWORD *size )
 {
     msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
-    UINT r = MsiGetSourcePathW(This->package, (LPWSTR)folder, (LPWSTR)value, size);
+    UINT r = MsiGetSourcePathW(This->package, folder, value, size);
     return HRESULT_FROM_WIN32(r);
 }
 
@@ -2519,6 +2742,15 @@ static HRESULT WINAPI mrp_GetFeatureCost( IWineMsiRemotePackage *iface, BSTR fea
     return HRESULT_FROM_WIN32(r);
 }
 
+static HRESULT WINAPI mrp_EnumComponentCosts( IWineMsiRemotePackage *iface, BSTR component,
+                                              DWORD index, INSTALLSTATE state, BSTR drive,
+                                              DWORD *buflen, INT *cost, INT *temp )
+{
+    msi_remote_package_impl* This = impl_from_IWineMsiRemotePackage( iface );
+    UINT r = MsiEnumComponentCostsW(This->package, component, index, state, drive, buflen, cost, temp);
+    return HRESULT_FROM_WIN32(r);
+}
+
 static const IWineMsiRemotePackageVtbl msi_remote_package_vtbl =
 {
     mrp_QueryInterface,
@@ -2545,6 +2777,7 @@ static const IWineMsiRemotePackageVtbl msi_remote_package_vtbl =
     mrp_FormatRecord,
     mrp_EvaluateCondition,
     mrp_GetFeatureCost,
+    mrp_EnumComponentCosts
 };
 
 HRESULT create_msi_remote_package( IUnknown *pOuter, LPVOID *ppObj )
@@ -2559,7 +2792,7 @@ HRESULT create_msi_remote_package( IUnknown *pOuter, LPVOID *ppObj )
     This->package = 0;
     This->refs = 1;
 
-    *ppObj = This;
+    *ppObj = &This->IWineMsiRemotePackage_iface;
 
     return S_OK;
 }