[PATCH 1/5] msi: Use MsiProcessMessage() to send error messages.

Zebediah Figura z.figura12 at gmail.com
Sun Jul 23 15:50:53 CDT 2017


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/msi/action.c        |  51 +++------------------
 dlls/msi/dialog.c        | 112 -----------------------------------------------
 dlls/msi/media.c         |  41 +++++------------
 dlls/msi/msi.rc          |  12 +++--
 dlls/msi/msipriv.h       |   2 -
 dlls/msi/package.c       | 112 +++++++++++++++++++++++++++++++++++++++--------
 dlls/msi/resource.h      |  23 +++++++---
 dlls/msi/tests/package.c |  41 +++++++++++++++++
 8 files changed, 173 insertions(+), 221 deletions(-)

diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index 2d05ba1..55a16d9 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -5448,43 +5448,6 @@ UINT ACTION_ForceReboot(MSIPACKAGE *package)
     return ERROR_INSTALL_SUSPEND;
 }
 
-WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
-{
-    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 *rec, *row;
-    DWORD i, size = 0;
-    va_list va;
-    const WCHAR *str;
-    WCHAR *data;
-
-    if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
-
-    rec = MSI_CreateRecord( count + 2 );
-    str = MSI_RecordGetString( row, 1 );
-    MSI_RecordSetStringW( rec, 0, str );
-    msiobj_release( &row->hdr );
-    MSI_RecordSetInteger( rec, 1, error );
-
-    va_start( va, count );
-    for (i = 0; i < count; i++)
-    {
-        str = va_arg( va, const WCHAR *);
-        MSI_RecordSetStringW( rec, i + 2, str );
-    }
-    va_end( va );
-
-    MSI_FormatRecordW( package, rec, NULL, &size );
-    size++;
-    data = msi_alloc( size * sizeof(WCHAR) );
-    if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
-    else data[0] = 0;
-    msiobj_release( &rec->hdr );
-    return data;
-}
-
 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
 {
     DWORD attrib;
@@ -5502,7 +5465,8 @@ static UINT ACTION_ResolveSource(MSIPACKAGE* package)
     attrib = GetFileAttributesW(package->db->path);
     if (attrib == INVALID_FILE_ATTRIBUTES)
     {
-        LPWSTR prompt, msg;
+        MSIRECORD *record;
+        LPWSTR prompt;
         DWORD size = 0;
 
         rc = MsiSourceListGetInfoW(package->ProductCode, NULL, 
@@ -5518,19 +5482,18 @@ static UINT ACTION_ResolveSource(MSIPACKAGE* package)
         else
             prompt = strdupW(package->db->path);
 
-        msg = msi_build_error_string(package, 1302, 1, prompt);
+        record = MSI_CreateRecord(2);
+        MSI_RecordSetInteger(record, 1, MSIERR_INSERTDISK);
+        MSI_RecordSetStringW(record, 2, prompt);
         msi_free(prompt);
         while(attrib == INVALID_FILE_ATTRIBUTES)
         {
-            rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL);
+            MSI_RecordSetStringW(record, 0, NULL);
+            rc = MSI_ProcessMessage(package, INSTALLMESSAGE_ERROR, record);
             if (rc == IDCANCEL)
-            {
-                msi_free(msg);
                 return ERROR_INSTALL_USEREXIT;
-            }
             attrib = GetFileAttributesW(package->db->path);
         }
-        msi_free(msg);
         rc = ERROR_SUCCESS;
     }
     else
diff --git a/dlls/msi/dialog.c b/dlls/msi/dialog.c
index c4a94f1..0c46efd 100644
--- a/dlls/msi/dialog.c
+++ b/dlls/msi/dialog.c
@@ -4101,109 +4101,6 @@ void msi_event_cleanup_all_subscriptions( MSIPACKAGE *package )
     }
 }
 
-static UINT error_dialog_handler( msi_dialog *dialog, const WCHAR *event, const WCHAR *argument )
-{
-    static const WCHAR end_dialog[] = {'E','n','d','D','i','a','l','o','g',0};
-    static const WCHAR error_abort[] = {'E','r','r','o','r','A','b','o','r','t',0};
-    static const WCHAR error_cancel[] = {'E','r','r','o','r','C','a','n','c','e','l',0};
-    static const WCHAR error_no[] = {'E','r','r','o','r','N','o',0};
-    static const WCHAR result_prop[] = {
-        'M','S','I','E','r','r','o','r','D','i','a','l','o','g','R','e','s','u','l','t',0
-    };
-
-    if ( strcmpW( event, end_dialog ) )
-        return ERROR_SUCCESS;
-
-    if ( !strcmpW( argument, error_abort ) || !strcmpW( argument, error_cancel ) ||
-         !strcmpW( argument, error_no ) )
-    {
-         msi_set_property( dialog->package->db, result_prop, error_abort, -1 );
-    }
-
-    msi_event_cleanup_all_subscriptions( dialog->package );
-    msi_dialog_end_dialog( dialog );
-
-    return ERROR_SUCCESS;
-}
-
-static UINT msi_error_dialog_set_error( MSIPACKAGE *package, LPWSTR error_dialog, LPWSTR error )
-{
-    MSIRECORD * row;
-
-    static const WCHAR update[] = 
-        {'U','P','D','A','T','E',' ','`','C','o','n','t','r','o','l','`',' ',
-         'S','E','T',' ','`','T','e','x','t','`',' ','=',' ','\'','%','s','\'',' ',
-         'W','H','E','R','E', ' ','`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',' ',
-         'A','N','D',' ','`','C','o','n','t','r','o','l','`',' ','=',' ',
-         '\'','E','r','r','o','r','T','e','x','t','\'',0};
-
-    row = MSI_QueryGetRecord( package->db, update, error, error_dialog );
-    if (!row)
-        return ERROR_FUNCTION_FAILED;
-
-    msiobj_release(&row->hdr);
-    return ERROR_SUCCESS;
-}
-
-UINT msi_spawn_error_dialog( MSIPACKAGE *package, LPWSTR error_dialog, LPWSTR error )
-{
-    msi_dialog *dialog;
-    WCHAR result[MAX_PATH];
-    UINT r = ERROR_SUCCESS;
-    DWORD size = MAX_PATH;
-    int res;
-
-    static const WCHAR pn_prop[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
-    static const WCHAR title_fmt[] = {'%','s',' ','W','a','r','n','i','n','g',0};
-    static const WCHAR error_abort[] = {'E','r','r','o','r','A','b','o','r','t',0};
-    static const WCHAR result_prop[] = {
-        'M','S','I','E','r','r','o','r','D','i','a','l','o','g','R','e','s','u','l','t',0
-    };
-
-    if ((package->ui_level & INSTALLUILEVEL_MASK) == INSTALLUILEVEL_NONE) return ERROR_SUCCESS;
-
-    if ( !error_dialog )
-    {
-        LPWSTR product_name = msi_dup_property( package->db, pn_prop );
-        WCHAR title[MAX_PATH];
-
-        sprintfW( title, title_fmt, product_name );
-        res = MessageBoxW( NULL, error, title, MB_OKCANCEL | MB_ICONWARNING );
-
-        msi_free( product_name );
-
-        if ( res == IDOK )
-            return ERROR_SUCCESS;
-        else
-            return ERROR_FUNCTION_FAILED;
-    }
-
-    r = msi_error_dialog_set_error( package, error_dialog, error );
-    if ( r != ERROR_SUCCESS )
-        return r;
-
-    dialog = dialog_create( package, error_dialog, package->dialog, error_dialog_handler );
-    if ( !dialog )
-        return ERROR_FUNCTION_FAILED;
-
-    dialog->finished = FALSE;
-    r = dialog_run_message_loop( dialog );
-    if ( r != ERROR_SUCCESS )
-        goto done;
-
-    r = msi_get_property( package->db, result_prop, result, &size );
-    if ( r != ERROR_SUCCESS)
-        r = ERROR_SUCCESS;
-
-    if ( !strcmpW( result, error_abort ) )
-        r = ERROR_FUNCTION_FAILED;
-
-done:
-    msi_dialog_destroy( dialog );
-
-    return r;
-}
-
 static void MSI_ClosePreview( MSIOBJECTHDR *arg )
 {
     MSIPREVIEW *preview = (MSIPREVIEW *)arg;
@@ -4564,19 +4461,10 @@ INT ACTION_ShowDialog( MSIPACKAGE *package, const WCHAR *dialog )
 
     if (!rc)
     {
-        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};
-        WCHAR template[1024];
         MSIRECORD *row = MSI_CreateRecord(2);
         if (!row) return -1;
-        MSI_RecordSetStringW(row, 0, szActionNotFound);
         MSI_RecordSetInteger(row, 1, 2726);
         MSI_RecordSetStringW(row, 2, dialog);
-        MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_INFO, row);
-
-        LoadStringW(msi_hInstance, IDS_INSTALLERROR, template, 1024);
-        MSI_RecordSetStringW(row, 0, template);
         MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
 
         msiobj_release(&row->hdr);
diff --git a/dlls/msi/media.c b/dlls/msi/media.c
index bbfdd6f..0bb883b 100644
--- a/dlls/msi/media.c
+++ b/dlls/msi/media.c
@@ -32,6 +32,7 @@
 #include "shlwapi.h"
 #include "objidl.h"
 #include "wine/unicode.h"
+#include "resource.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
@@ -78,44 +79,22 @@ static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPCWSTR source_root)
 
 static UINT msi_change_media(MSIPACKAGE *package, MSIMEDIAINFO *mi)
 {
-    LPWSTR error, error_dialog;
+    MSIRECORD *record;
     LPWSTR source_dir;
-    UINT r = ERROR_SUCCESS;
+    UINT r = IDRETRY;
 
-    static const WCHAR error_prop[] = {'E','r','r','o','r','D','i','a','l','o','g',0};
-
-    if ((package->ui_level & INSTALLUILEVEL_MASK) == INSTALLUILEVEL_NONE &&
-        !gUIHandlerA && !gUIHandlerW && !gUIHandlerRecord) return ERROR_SUCCESS;
-
-    error = msi_build_error_string(package, 1302, 1, mi->disk_prompt);
-    error_dialog = msi_dup_property(package->db, error_prop);
     source_dir = msi_dup_property(package->db, szSourceDir);
+    record = MSI_CreateRecord(2);
 
-    while (r == ERROR_SUCCESS && !source_matches_volume(mi, source_dir))
+    while (r == IDRETRY && !source_matches_volume(mi, source_dir))
     {
-        r = msi_spawn_error_dialog(package, error_dialog, error);
-
-        if (gUIHandlerW)
-        {
-            gUIHandlerW(gUIContext, MB_RETRYCANCEL | INSTALLMESSAGE_ERROR, error);
-        }
-        else if (gUIHandlerA)
-        {
-            char *msg = strdupWtoA(error);
-            gUIHandlerA(gUIContext, MB_RETRYCANCEL | INSTALLMESSAGE_ERROR, msg);
-            msi_free(msg);
-        }
-        else if (gUIHandlerRecord)
-        {
-            MSIHANDLE rec = MsiCreateRecord(1);
-            MsiRecordSetStringW(rec, 0, error);
-            gUIHandlerRecord(gUIContextRecord, MB_RETRYCANCEL | INSTALLMESSAGE_ERROR, rec);
-            MsiCloseHandle(rec);
-        }
+        MSI_RecordSetStringW(record, 0, NULL);
+        MSI_RecordSetInteger(record, 1, MSIERR_CABNOTFOUND);
+        MSI_RecordSetStringW(record, 2, mi->disk_prompt);
+        r = MSI_ProcessMessage(package, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, record);
     }
 
-    msi_free(error);
-    msi_free(error_dialog);
+    msiobj_release(&record->hdr);
     msi_free(source_dir);
 
     return r;
diff --git a/dlls/msi/msi.rc b/dlls/msi/msi.rc
index 73a600a..357bc5a 100644
--- a/dlls/msi/msi.rc
+++ b/dlls/msi/msi.rc
@@ -64,25 +64,23 @@ STRINGTABLE
 	15 "choose which folder contains %s"
 }
 
-/* Install message format strings */
+/* Error messages */
 STRINGTABLE
 {
     IDS_FATALEXIT "{{Fatal error: }}"
     IDS_ERROR "{{Error [1]. }}"
     IDS_WARNING "Warning [1]."
     IDS_INFO "Info [1]."
+    IDS_INSTALLERROR "The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is [1]. {{The arguments are: [2], [3], [4]}}"
     IDS_OUTOFDISKSPACE "{{Disk full: }}"
     IDS_ACTIONSTART "Action %s: [1]. [2]"
     IDS_COMMONDATA "Message type: [1], Argument: [2]{, [3]}"
-}
-
-/* Install message template strings */
-STRINGTABLE
-{
     IDS_INFO_ACTIONSTART "Action start %s: [1]."
     IDS_INFO_ACTIONENDED "Action ended %s: [1]. Return value [2]."
     IDS_INFO_LOGGINGSTART "=== Logging started: %s  %s ==="
-    IDS_INSTALLERROR "The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is [1]. {{The arguments are: [2], [3], [4]}}"
+
+    IDS_ERR_INSERTDISK "Please insert the disk: [2]"
+    IDS_ERR_CABNOTFOUND "Source file not found{{(cabinet)}}: [2]. Verify that the file exists and that you can access it."
 }
 
 /* Standard action description strings */
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 84e53ff..91c614e 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -952,7 +952,6 @@ extern LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWS
 extern void msi_dialog_check_messages( HANDLE ) DECLSPEC_HIDDEN;
 extern void msi_dialog_destroy( msi_dialog* ) DECLSPEC_HIDDEN;
 extern void msi_dialog_unregister_class( void ) DECLSPEC_HIDDEN;
-extern UINT msi_spawn_error_dialog( MSIPACKAGE*, LPWSTR, LPWSTR ) DECLSPEC_HIDDEN;
 
 /* summary information */
 extern UINT msi_get_suminfo( IStorage *stg, UINT uiUpdateCount, MSISUMMARYINFO **si ) DECLSPEC_HIDDEN;
@@ -1039,7 +1038,6 @@ extern WCHAR *msi_create_component_advertise_string(MSIPACKAGE *, MSICOMPONENT *
 extern void ACTION_UpdateComponentStates(MSIPACKAGE *package, MSIFEATURE *feature) DECLSPEC_HIDDEN;
 extern UINT msi_register_unique_action(MSIPACKAGE *, const WCHAR *) DECLSPEC_HIDDEN;
 extern BOOL msi_action_is_unique(const MSIPACKAGE *, const WCHAR *) DECLSPEC_HIDDEN;
-extern WCHAR *msi_build_error_string(MSIPACKAGE *, UINT, DWORD, ...) DECLSPEC_HIDDEN;
 extern UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
                         MSIINSTALLCONTEXT context, DWORD options, LPCWSTR value) DECLSPEC_HIDDEN;
 extern UINT msi_create_empty_local_file(LPWSTR path, LPCWSTR suffix) DECLSPEC_HIDDEN;
diff --git a/dlls/msi/package.c b/dlls/msi/package.c
index 4c44a84..c3b4f5f 100644
--- a/dlls/msi/package.c
+++ b/dlls/msi/package.c
@@ -1848,6 +1848,64 @@ static INT internal_ui_handler(MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
     }
 }
 
+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 */
+static 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};
@@ -1954,34 +2012,49 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIREC
     case INSTALLMESSAGE_OUTOFDISKSPACE:
         if (MSI_RecordGetInteger(record, 1) != MSI_NULL_INTEGER)
         {
-            WCHAR template_prefix[1024];
-            WCHAR *template_rec, *template;
-            UINT prefix_id = 0;
+            /* error message */
+
+            LPWSTR template;
+            LPWSTR template_rec = NULL, template_prefix = NULL;
+            int error = MSI_RecordGetInteger(record, 1);
 
             if (MSI_RecordIsNull(record, 0))
             {
-                LoadStringW(msi_hInstance, IDS_INSTALLERROR, template_prefix, 1024);
-                MSI_RecordSetStringW(record, 0, template_prefix);
-                break;
+                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);
 
-            if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
-                break;
+            template_prefix = msi_get_error_message(package->db, eMessageType >> 24);
+            if (!template_prefix) template_prefix = strdupW(szEmpty);
 
-            switch(eMessageType & 0xff000000)
+            if (!template_rec)
             {
-            case INSTALLMESSAGE_FATALEXIT: prefix_id = IDS_FATALEXIT; break;
-            case INSTALLMESSAGE_ERROR: prefix_id = IDS_ERROR; break;
-            case INSTALLMESSAGE_WARNING: prefix_id = IDS_WARNING; break;
-            case INSTALLMESSAGE_INFO: prefix_id = IDS_INFO; break;
-            case INSTALLMESSAGE_OUTOFDISKSPACE: prefix_id = IDS_OUTOFDISKSPACE; break;
+                /* always returns 0 */
+                MSI_RecordSetStringW(record, 0, template_prefix);
+                MSI_ProcessMessageVerbatim(package, eMessageType, record);
+                msi_free(template_prefix);
+                return 0;
             }
 
-            LoadStringW(msi_hInstance, prefix_id, template_prefix, 1024);
-
-            template_rec = msi_dup_record_field(record, 0);
-            if (!template_rec) return ERROR_OUTOFMEMORY;
-
             template = msi_alloc((strlenW(template_rec) + strlenW(template_prefix) + 1) * sizeof(WCHAR));
             if (!template) return ERROR_OUTOFMEMORY;
 
@@ -1989,6 +2062,7 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIREC
             strcatW(template, template_rec);
             MSI_RecordSetStringW(record, 0, template);
 
+            msi_free(template_prefix);
             msi_free(template_rec);
             msi_free(template);
         }
diff --git a/dlls/msi/resource.h b/dlls/msi/resource.h
index 77c0aa1..88d4e3e 100644
--- a/dlls/msi/resource.h
+++ b/dlls/msi/resource.h
@@ -16,18 +16,29 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#define IDS_FATALEXIT 1000
-#define IDS_ERROR 1001
-#define IDS_WARNING 1002
-#define IDS_INFO 1004
-#define IDS_OUTOFDISKSPACE 1007
+#define MSIERR_INSTALLERROR         5
+
+#define MSIERR_INSERTDISK           1302
+#define MSIERR_CABNOTFOUND          1311
+
+#define IDS_ERROR_BASE          10000
+
+#define IDS_FATALEXIT           (IDS_ERROR_BASE)
+#define IDS_ERROR               (IDS_ERROR_BASE + 1)
+#define IDS_WARNING             (IDS_ERROR_BASE + 2)
+#define IDS_INFO                (IDS_ERROR_BASE + 4)
+#define IDS_INSTALLERROR        (IDS_ERROR_BASE + MSIERR_INSTALLERROR)
+#define IDS_OUTOFDISKSPACE      (IDS_ERROR_BASE + 7)
+
+#define IDS_ERR_INSERTDISK      (IDS_ERROR_BASE + MSIERR_INSERTDISK)
+#define IDS_ERR_CABNOTFOUND     (IDS_ERROR_BASE + MSIERR_CABNOTFOUND)
+
 #define IDS_ACTIONSTART 1008
 #define IDS_COMMONDATA 1011
 
 #define IDS_INFO_ACTIONSTART 1050
 #define IDS_INFO_ACTIONENDED 1051
 #define IDS_INFO_LOGGINGSTART 1052
-#define IDS_INSTALLERROR 1053
 
 #define IDS_DESC_ALLOCATEREGISTRYSPACE 1100
 #define IDS_DESC_APPSEARCH 1101
diff --git a/dlls/msi/tests/package.c b/dlls/msi/tests/package.c
index d978286..4e2d63c 100644
--- a/dlls/msi/tests/package.c
+++ b/dlls/msi/tests/package.c
@@ -9377,6 +9377,22 @@ static const struct externalui_message processmessage_actiondata_sequence[] = {
     {0}
 };
 
+static const struct externalui_message processmessage_error_sequence[] = {
+    {INSTALLMESSAGE_USER, 3, {"", "1311", "banana", "guava"}, {0, 1, 1, 1}},
+    {0}
+};
+
+static const struct externalui_message processmessage_internal_error_sequence[] = {
+    {INSTALLMESSAGE_INFO, 3, {"DEBUG: Error [1]:  Action not found: [2]", "2726", "banana", "guava"}, {1, 1, 1, 1}},
+    {INSTALLMESSAGE_USER, 3, {"internal error", "2726", "banana", "guava"}, {1, 1, 1, 1}},
+    {0}
+};
+
+static const struct externalui_message processmessage_error_format_sequence[] = {
+    {INSTALLMESSAGE_USER, 3, {"", "2726", "banana", "guava"}, {0, 1, 1, 1}},
+    {0}
+};
+
 static const struct externalui_message doaction_costinitialize_sequence[] = {
     {INSTALLMESSAGE_ACTIONSTART, 3, {"", "CostInitialize", "", ""}, {0, 1, 0, 1}},
     {INSTALLMESSAGE_INFO, 2, {"", "CostInitialize", ""}, {0, 1, 1}},
@@ -9519,6 +9535,11 @@ static void test_externalui_message(void)
     r = MsiDatabaseImportA(hdb, CURR_DIR, "forcecodepage.idt");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
 
+    r = run_query(hdb, "CREATE TABLE `Error` (`Error` SHORT NOT NULL, `Message` CHAR(0) PRIMARY KEY `Error`)");
+    ok(r == ERROR_SUCCESS, "Failed to create Error table: %u\n", r);
+    r = run_query(hdb, "INSERT INTO `Error` (`Error`, `Message`) VALUES (5, 'internal error')");
+    ok(r == ERROR_SUCCESS, "Failed to insert into Error table: %u\n", r);
+
     r = MsiOpenPackageA(NULL, &hpkg);
     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
     ok_sequence(empty_sequence, "MsiOpenPackage with NULL db", FALSE);
@@ -9564,6 +9585,26 @@ static void test_externalui_message(void)
     ok(r == 1, "Expected 1, got %d\n", r);
     ok_sequence(processmessage_actiondata_sequence, "MsiProcessMessage(INSTALLMESSAGE_ACTIONDATA)", FALSE);
 
+    /* non-internal error */
+    MsiRecordSetStringA(hrecord, 0, NULL);
+    MsiRecordSetInteger(hrecord, 1, 1311);
+    r = MsiProcessMessage(hpkg, INSTALLMESSAGE_USER, hrecord);
+    ok(r == 1, "Expected 1, got %d\n", r);
+    ok_sequence(processmessage_error_sequence, "MsiProcessMessage non-internal error", FALSE);
+
+    /* internal error */
+    MsiRecordSetStringA(hrecord, 0, NULL);
+    MsiRecordSetInteger(hrecord, 1, 2726);
+    r = MsiProcessMessage(hpkg, INSTALLMESSAGE_USER, hrecord);
+    ok(r == 0, "Expected 0, got %d\n", r);
+    ok_sequence(processmessage_internal_error_sequence, "MsiProcessMessage internal error", FALSE);
+
+    /* with format field */
+    MsiRecordSetStringA(hrecord, 0, "starfruit");
+    r = MsiProcessMessage(hpkg, INSTALLMESSAGE_USER, hrecord);
+    ok(r == 1, "Expected 1, got %d\n", r);
+    ok_sequence(processmessage_error_format_sequence, "MsiProcessMessage error", FALSE);
+
     /* Test a standard action */
     r = MsiDoActionA(hpkg, "CostInitialize");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
-- 
2.7.4




More information about the wine-patches mailing list