msi [2/3]: Run SetProperty events before all other events no matter what the order is

James Hawkins truiken at gmail.com
Mon Oct 16 17:44:52 CDT 2006


Hi,

This patch is the correct solution to fix the America's Army installer.

Changelog:
* Run SetProperty events before all other events no matter what the order is.

 dlls/msi/dialog.c  |   84 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 dlls/msi/msipriv.h |    1 +
 dlls/msi/record.c  |   23 ++++++++++++++
 3 files changed, 107 insertions(+), 1 deletions(-)

-- 
James Hawkins
-------------- next part --------------
diff --git a/dlls/msi/dialog.c b/dlls/msi/dialog.c
index f40ed76..03ba6f2 100644
--- a/dlls/msi/dialog.c
+++ b/dlls/msi/dialog.c
@@ -2886,6 +2886,62 @@ static UINT msi_dialog_control_event( MS
     return ERROR_SUCCESS;
 }
 
+struct rec_list
+{
+    struct list entry;
+    MSIRECORD *rec;
+};
+
+static UINT add_recs_to_list( MSIRECORD *rec, LPVOID param )
+{
+    struct rec_list *add_rec;
+    struct list *records = (struct list *)param;
+    MSIRECORD *copy;
+
+    copy = MSI_CopyRecord( rec );
+    if (!copy)
+        return ERROR_OUTOFMEMORY;
+
+    add_rec = msi_alloc( sizeof( *add_rec ) );
+    if (!add_rec)
+    {
+        msiobj_release( &copy->hdr );
+        return ERROR_OUTOFMEMORY;
+    }
+
+    add_rec->rec = copy;
+    list_add_tail( records, &add_rec->entry );
+    return ERROR_SUCCESS;
+}
+
+static void reprioritize_set_prop_events( struct list *events)
+{
+    struct rec_list *rec_entry, *next;
+    struct list set_props;
+    LPCWSTR event;
+    DWORD len;
+
+    list_init( &set_props );
+
+    LIST_FOR_EACH_ENTRY_SAFE( rec_entry, next, events, struct rec_list, entry )
+    {
+        event = MSI_RecordGetString( rec_entry->rec, 3 );
+        len = lstrlenW(event);
+
+        if ( event[0] == '[' && event[len - 1] == ']' )
+        {
+            list_remove( &rec_entry->entry );
+            list_add_head( &set_props, &rec_entry->entry );
+        }
+    }
+
+    LIST_FOR_EACH_ENTRY_SAFE( rec_entry, next, &set_props, struct rec_list, entry )
+    {
+        list_remove( &rec_entry->entry );
+        list_add_head( events, &rec_entry->entry );
+    }
+}
+
 static UINT msi_dialog_button_handler( msi_dialog *dialog,
                                        msi_control *control, WPARAM param )
 {
@@ -2899,11 +2955,15 @@ static UINT msi_dialog_button_handler( m
       'O','R','D','E','R',' ','B','Y',' ','`','O','r','d','e','r','i','n','g','`',0
     };
     MSIQUERY *view = NULL;
+    struct rec_list *rec_entry, *next;
+    struct list events;
     UINT r;
 
     if( HIWORD(param) != BN_CLICKED )
         return ERROR_SUCCESS;
 
+    list_init( &events );
+
     r = MSI_OpenQuery( dialog->package->db, &view, query,
                        dialog->name, control->name );
     if( r != ERROR_SUCCESS )
@@ -2912,8 +2972,30 @@ static UINT msi_dialog_button_handler( m
         return 0;
     }
 
-    r = MSI_IterateRecords( view, 0, msi_dialog_control_event, dialog );
+    r = MSI_IterateRecords( view, 0, add_recs_to_list, &events );
     msiobj_release( &view->hdr );
+    if (r != ERROR_SUCCESS)
+        goto done;
+
+    /* move SetProperty events to the front of the list */
+    reprioritize_set_prop_events( &events );
+
+    LIST_FOR_EACH_ENTRY_SAFE( rec_entry, next, &events, struct rec_list, entry )
+    {
+        r = msi_dialog_control_event( rec_entry->rec, dialog );
+        list_remove( &rec_entry->entry );
+        msiobj_release( &rec_entry->rec->hdr );
+
+        if ( r != ERROR_SUCCESS )
+            goto done;
+    }
+
+done:
+    LIST_FOR_EACH_ENTRY_SAFE( rec_entry, next, &events, struct rec_list, entry )
+    {
+        list_remove( &rec_entry->entry );
+        msi_free( rec_entry );
+    }
 
     return r;
 }
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 94edb23..137f2d9 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -590,6 +590,7 @@ extern UINT MSI_RecordSetStreamA( MSIREC
 extern UINT MSI_RecordDataSize( MSIRECORD *, unsigned int );
 extern UINT MSI_RecordStreamToFile( MSIRECORD *, unsigned int, LPCWSTR );
 extern UINT MSI_RecordCopyField( MSIRECORD *, unsigned int, MSIRECORD *, unsigned int );
+extern MSIRECORD *MSI_CopyRecord( MSIRECORD * );
 
 /* stream internals */
 extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm );
diff --git a/dlls/msi/record.c b/dlls/msi/record.c
index 6705a03..9ec9bd3 100644
--- a/dlls/msi/record.c
+++ b/dlls/msi/record.c
@@ -200,6 +200,29 @@ UINT MSI_RecordCopyField( MSIRECORD *in_
     return r;
 }
 
+MSIRECORD *MSI_CopyRecord( MSIRECORD *in )
+{
+    DWORD num_fields = MSI_RecordGetFieldCount( in );
+    MSIRECORD *out =  MSI_CreateRecord( num_fields );
+    DWORD i;
+    UINT r;
+
+    if ( !out )
+        return NULL;
+
+    for ( i = 0; i < num_fields; i++)
+    {
+        r = MSI_RecordCopyField( in, i, out, i );
+        if ( r != ERROR_SUCCESS )
+        {
+            msiobj_release( &out->hdr );
+            return NULL;
+        }
+    }
+
+    return out;
+}
+
 int MSI_RecordGetInteger( MSIRECORD *rec, unsigned int iField)
 {
     int ret = 0;
-- 
1.4.2.1


More information about the wine-patches mailing list