[MSI] Apply Wine commit fdac39f by Hans Leidekker: Pass correct length to GetDateForm...
[reactos.git] / dll / win32 / msi / package.c
index 5034359..3e0ae71 100644 (file)
 
 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 );
-
-        list_remove( &temp->entry );
-        TRACE("deleting temp file %s\n", debugstr_w( temp->Path ));
-        DeleteFileW( temp->Path );
-        msi_free( temp->Path );
-        msi_free( temp );
-    }
-}
-
 static void free_feature( MSIFEATURE *feature )
 {
     struct list *item, *cursor;
@@ -145,6 +129,22 @@ static void free_package_structures( MSIPACKAGE *package )
         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 )
     {
         MSICOMPONENT *comp = LIST_ENTRY( item, MSICOMPONENT, entry );
@@ -160,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 */
@@ -311,10 +305,9 @@ static void free_package_structures( MSIPACKAGE *package )
     msi_free( package->ProductCode );
     msi_free( package->ActionFormat );
     msi_free( package->LastAction );
+    msi_free( package->LastActionTemplate );
     msi_free( package->langids );
 
-    remove_tracked_tempfiles(package);
-
     /* cleanup control event subscriptions */
     msi_event_cleanup_all_subscriptions( package );
 }
@@ -334,6 +327,7 @@ static void MSI_FreePackage( MSIOBJECTHDR *arg)
 
     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)
@@ -361,7 +355,7 @@ static UINT create_temp_property_table(MSIPACKAGE *package)
     return rc;
 }
 
-UINT msi_clone_properties(MSIPACKAGE *package)
+UINT msi_clone_properties( MSIDATABASE *db )
 {
     static const WCHAR query_select[] = {
         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
@@ -378,7 +372,7 @@ UINT msi_clone_properties(MSIPACKAGE *package)
     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;
 
@@ -399,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 );
@@ -415,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);
@@ -654,7 +648,6 @@ static VOID set_installer_properties(MSIPACKAGE *package)
     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};
@@ -716,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};
@@ -726,8 +717,6 @@ static VOID set_installer_properties(MSIPACKAGE *package)
     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};
-    static const WCHAR szBrowseProperty[] = {'_','B','r','o','w','s','e','P','r','o','p','e','r','t','y',0};
-    static const WCHAR szInstallDir[] = {'I','N','S','T','A','L','L','D','I','R',0};
 
     /*
      * Other things that probably should be set:
@@ -948,22 +937,6 @@ 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, -1 );
-    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, -1 );
-    else
-        ERR("Couldn't set Time property: GetTimeFormat failed with error %d\n", GetLastError());
-
     set_msi_assembly_prop( package );
 
     langid = GetUserDefaultLangID();
@@ -999,74 +972,6 @@ static VOID set_installer_properties(MSIPACKAGE *package)
             msi_free( computername );
         }
     }
-    msi_set_property( package->db, szBrowseProperty, szInstallDir, -1 );
-}
-
-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)
-    {
-        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;
-    }
-
-    msi_set_property( package->db, szPackageCode, package_code, len );
-    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 )
@@ -1144,25 +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 );
 
         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 );
@@ -1246,7 +1153,7 @@ UINT msi_create_empty_local_file( LPWSTR path, LPCWSTR suffix )
     return ERROR_SUCCESS;
 }
 
-static enum platform parse_platform( WCHAR *str )
+static enum platform parse_platform( const WCHAR *str )
 {
     if (!str[0] || !strcmpW( str, szIntel )) return PLATFORM_INTEL;
     else if (!strcmpW( str, szIntel64 )) return PLATFORM_INTEL64;
@@ -1255,7 +1162,7 @@ static enum platform parse_platform( WCHAR *str )
     return PLATFORM_UNKNOWN;
 }
 
-static UINT msi_parse_summary( MSISUMMARYINFO *si, MSIPACKAGE *package )
+static UINT parse_suminfo( MSISUMMARYINFO *si, MSIPACKAGE *package )
 {
     WCHAR *template, *p, *q, *platform;
     DWORD i, count;
@@ -1363,22 +1270,6 @@ static UINT validate_package( MSIPACKAGE *package )
     return ERROR_INSTALL_LANGUAGE_UNSUPPORTED;
 }
 
-int msi_track_tempfile( MSIPACKAGE *package, const WCHAR *path )
-{
-    MSITEMPFILE *temp;
-
-    TRACE("%s\n", debugstr_w(path));
-
-    LIST_FOR_EACH_ENTRY( temp, &package->tempfiles, MSITEMPFILE, entry )
-    {
-        if (!strcmpW( path, temp->Path )) return 0;
-    }
-    if (!(temp = msi_alloc_zero( sizeof (MSITEMPFILE) ))) return -1;
-    list_add_head( &package->tempfiles, &temp->entry );
-    temp->Path = strdupW( path );
-    return 0;
-}
-
 static WCHAR *get_product_code( MSIDATABASE *db )
 {
     static const WCHAR query[] = {
@@ -1458,11 +1349,17 @@ static WCHAR *get_package_code( MSIDATABASE *db )
 {
     WCHAR *ret;
     MSISUMMARYINFO *si;
+    UINT r;
 
-    if (!(si = MSI_GetSummaryInformationW( db->storage, 0 )))
+    r = msi_get_suminfo( db->storage, 0, &si );
+    if (r != ERROR_SUCCESS)
     {
-        WARN("failed to load summary info\n");
-        return NULL;
+        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 );
@@ -1527,6 +1424,7 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
     MSIDATABASE *db;
     MSIPACKAGE *package;
     MSIHANDLE handle;
+    MSIRECORD *data_row, *info_row;
     LPWSTR ptr, base_url = NULL;
     UINT r;
     WCHAR localfile[MAX_PATH], cachefile[MAX_PATH];
@@ -1534,9 +1432,13 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
     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] == '#' )
     {
@@ -1608,14 +1510,18 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
     package->localfile = strdupW( localfile );
     package->delete_on_close = delete_on_close;
 
-    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\n");
-        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)
     {
@@ -1630,6 +1536,7 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
         return r;
     }
     msi_set_property( package->db, szDatabase, db->path, -1 );
+    set_installed_prop( package );
     msi_set_context( package );
 
     while (1)
@@ -1651,11 +1558,8 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
         }
         index++;
     }
-    if (index)
-    {
-        msi_clone_properties( package );
-        msi_adjust_privilege_properties( package );
-    }
+    if (index) msi_adjust_privilege_properties( package );
+
     r = msi_set_original_database_property( package->db, szPackage );
     if (r != ERROR_SUCCESS)
     {
@@ -1665,6 +1569,40 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
     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;
 }
@@ -1696,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;
 }
@@ -1762,18 +1702,169 @@ 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 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};
-    MSIRECORD *uirow;
-    LPWSTR deformated, message;
-    DWORD i, len, total_len, log_type = 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)
+{
+    LPWSTR message = {0};
+    DWORD len, log_type = 0;
+    UINT res;
     INT rc = 0;
     char *msg;
 
     TRACE("%x\n", eMessageType);
+    if (TRACE_ON(msi)) dump_record(record);
 
     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_FATALEXIT)
         log_type |= INSTALLLOGMODE_FATALEXIT;
@@ -1804,97 +1895,48 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIREC
     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_SHOWDIALOG)
         log_type |= INSTALLLOGMODE_SHOWDIALOG;
 
-    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
-    {
-        static const WCHAR format[] = {'%','u',':',' ',0};
-        UINT count = MSI_RecordGetFieldCount( record );
-        WCHAR *p;
-
-        total_len = 1;
-        for (i = 1; i <= count; i++)
-        {
-            len = 0;
-            MSI_RecordGetStringW( record, i, NULL, &len );
-            total_len += len + 13;
-        }
-        p = message = msi_alloc( total_len * sizeof(WCHAR) );
-        if (!p) return ERROR_OUTOFMEMORY;
-
-        for (i = 1; i <= count; i++)
-        {
-            if (count > 1)
-            {
-                len = sprintfW( p, format, i );
-                total_len -= len;
-                p += len;
-            }
-            len = total_len;
-            MSI_RecordGetStringW( record, i, p, &len );
-            total_len -= len;
-            p += len;
-            if (count > 1 && total_len)
-            {
-                *p++ = ' ';
-                total_len--;
-            }
-        }
-        p[0] = 0;
+    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;
@@ -1904,44 +1946,113 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIREC
     msi_free( msg );
     msi_free( message );
 
+    return rc;
+}
+
+INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record )
+{
     switch (eMessageType & 0xff000000)
     {
-    case INSTALLMESSAGE_ACTIONDATA:
-        deformat_string(package, MSI_RecordGetString(record, 2), &deformated);
-        uirow = MSI_CreateRecord(1);
-        MSI_RecordSetStringW(uirow, 1, deformated);
-        msi_free(deformated);
+    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 */
 
-        msi_event_fire( package, szActionData, uirow );
-        msiobj_release(&uirow->hdr);
+            LPWSTR template;
+            LPWSTR template_rec = NULL, template_prefix = NULL;
+            int error = MSI_RecordGetInteger(record, 1);
 
-        if (package->action_progress_increment)
-        {
-            uirow = MSI_CreateRecord(2);
-            MSI_RecordSetInteger(uirow, 1, 2);
-            MSI_RecordSetInteger(uirow, 2, package->action_progress_increment);
-            msi_event_fire( package, szSetProgress, uirow );
-            msiobj_release(&uirow->hdr);
-        }
-        break;
+            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);
 
-    case INSTALLMESSAGE_ACTIONSTART:
-        deformat_string(package, MSI_RecordGetString(record, 2), &deformated);
-        uirow = MSI_CreateRecord(1);
-        MSI_RecordSetStringW(uirow, 1, deformated);
-        msi_free(deformated);
+            template_prefix = msi_get_error_message(package->db, eMessageType >> 24);
+            if (!template_prefix) template_prefix = strdupW(szEmpty);
 
-        msi_event_fire( package, szActionText, uirow );
+            if (!template_rec)
+            {
+                /* always returns 0 */
+                MSI_RecordSetStringW(record, 0, template_prefix);
+                MSI_ProcessMessageVerbatim(package, eMessageType, record);
+                msi_free(template_prefix);
+                return 0;
+            }
 
-        msiobj_release(&uirow->hdr);
+            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:
+    {
+        WCHAR *template = msi_get_error_message(package->db, MSIERR_ACTIONSTART);
+        MSI_RecordSetStringW(record, 0, template);
+        msi_free(template);
 
-    case INSTALLMESSAGE_PROGRESS:
-        msi_event_fire( package, szSetProgress, record );
+        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_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,
@@ -1951,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 )
     {
@@ -2156,9 +2275,45 @@ static MSIRECORD *msi_get_property_row( MSIDATABASE *db, LPCWSTR name )
     MSIQUERY *view;
     UINT r;
 
+    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;
@@ -2184,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)
@@ -2635,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;
 }