msi: register unique actions

Aric Stewart aric at codeweavers.com
Thu Jun 30 07:42:28 CDT 2005


Keep track of what sequence we are in and register unique actions. This 
allows us to make sure actions and custom actions flagged to run only 
once, actually run only once.
Also clean up some of the numeric constants in custom.c using the 
defined values from msidefs.h
-------------- next part --------------
? dlls/msi/msi.spec.def
Index: dlls/msi/action.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.c,v
retrieving revision 1.166
diff -u -r1.166 action.c
--- dlls/msi/action.c	28 Jun 2005 19:14:30 -0000	1.166
+++ dlls/msi/action.c	30 Jun 2005 12:40:15 -0000
@@ -447,6 +447,8 @@
     package->script = HeapAlloc(GetProcessHeap(),0,sizeof(MSISCRIPT));
     memset(package->script,0,sizeof(MSISCRIPT));
 
+    package->script->InWhatSequence = SEQUENCE_INSTALL;
+
     package->msiFilePath= strdupW(msiFilePath);
 
     if (szPackagePath)   
@@ -540,10 +542,14 @@
     {
         if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED)
         {
+            package->script->InWhatSequence |= SEQUENCE_UI;
             rc = ACTION_ProcessUISequence(package);
             ui = TRUE;
             if (rc == ERROR_SUCCESS)
+            {
+                package->script->InWhatSequence |= SEQUENCE_EXEC;
                 rc = ACTION_ProcessExecSequence(package,TRUE);
+            }
         }
         else
             rc = ACTION_ProcessExecSequence(package,FALSE);
@@ -3847,6 +3853,7 @@
     level = load_dynamic_property(package,szUILevel,NULL);
 
     MSI_SetPropertyW(package,szUILevel,szTwo);
+    package->script->InWhatSequence |= SEQUENCE_EXEC;
     rc = ACTION_ProcessExecSequence(package,FALSE);
     MSI_SetPropertyW(package,szUILevel,level);
     HeapFree(GetProcessHeap(),0,level);
Index: dlls/msi/action.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.h,v
retrieving revision 1.21
diff -u -r1.21 action.h
--- dlls/msi/action.h	29 Jun 2005 19:19:09 -0000	1.21
+++ dlls/msi/action.h	30 Jun 2005 12:40:15 -0000
@@ -187,13 +187,21 @@
         TOTAL_SCRIPTS = 3
 };
 
+enum SequenceValues {
+    SEQUENCE_UI = 0x1,
+    SEQUENCE_EXEC = 0x2,
+    SEQUENCE_INSTALL = 0x10
+};
+
 typedef struct tagMSISCRIPT
 {
     LPWSTR  *Actions[TOTAL_SCRIPTS];
     UINT    ActionCount[TOTAL_SCRIPTS];
     BOOL    ExecuteSequenceRun;
-    BOOL    FindRelatedProductsRun;
     BOOL    CurrentlyScripting;
+    UINT    InWhatSequence;
+    LPWSTR  *UniqueActions;
+    UINT    UniqueActionsCount;
 }MSISCRIPT;
 
 
@@ -234,6 +242,8 @@
 void reduce_to_shortfilename(WCHAR*);
 LPWSTR create_component_advertise_string(MSIPACKAGE*, MSICOMPONENT*, LPCWSTR);
 void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature);
+UINT register_unique_action(MSIPACKAGE *, LPCWSTR);
+BOOL check_unique_action(MSIPACKAGE *, LPCWSTR);
 WCHAR* generate_error_string(MSIPACKAGE *, UINT, DWORD, ... );
 
 
Index: dlls/msi/custom.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/custom.c,v
retrieving revision 1.16
diff -u -r1.16 custom.c
--- dlls/msi/custom.c	16 Jun 2005 20:33:58 -0000	1.16
+++ dlls/msi/custom.c	30 Jun 2005 12:40:15 -0000
@@ -36,6 +36,7 @@
 #include "wine/debug.h"
 #include "fdi.h"
 #include "msi.h"
+#include "msidefs.h"
 #include "msiquery.h"
 #include "msvcrt/fcntl.h"
 #include "objbase.h"
@@ -74,6 +75,45 @@
 static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source,
                                 LPCWSTR target, const INT type, LPCWSTR action);
 
+
+static BOOL check_execution_scheduling_options(MSIPACKAGE *package, LPCWSTR action, UINT options)
+{
+    if (!package->script)
+        return TRUE;
+
+    if ((options & msidbCustomActionTypeClientRepeat) == 
+            msidbCustomActionTypeClientRepeat)
+    {
+        if (!(package->script->InWhatSequence & SEQUENCE_UI &&
+            package->script->InWhatSequence & SEQUENCE_EXEC))
+        {
+            TRACE("Skipping action due to dbCustomActionTypeClientRepeat option.\n");
+            return FALSE;
+        }
+    }
+    else if (options & msidbCustomActionTypeFirstSequence)
+    {
+        if (package->script->InWhatSequence & SEQUENCE_UI &&
+            package->script->InWhatSequence & SEQUENCE_EXEC )
+        {
+            TRACE("Skipping action due to msidbCustomActionTypeFirstSequence option.\n");
+            return FALSE;
+        }
+    }
+    else if (options & msidbCustomActionTypeOncePerProcess)
+    {
+        if (check_unique_action(package,action))
+        {
+            TRACE("Skipping action due to msidbCustomActionTypeOncePerProcess option.\n");
+            return FALSE;
+        }
+        else
+            register_unique_action(package,action);
+    }
+
+    return TRUE;
+}
+
 UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
 {
     UINT rc = ERROR_SUCCESS;
@@ -101,9 +141,15 @@
           debugstr_w(source), debugstr_w(target));
 
     /* handle some of the deferred actions */
-    if (type & 0x400)
+    if (type & msidbCustomActionTypeTSAware)
+        FIXME("msidbCustomActionTypeTSAware not handled\n");
+
+    if (type & msidbCustomActionTypeInScript)
     {
-        if (type & 0x100)
+        if (type & msidbCustomActionTypeNoImpersonate)
+            FIXME("msidbCustomActionTypeNoImpersonate not handled\n");
+
+        if (type & msidbCustomActionTypeRollback)
         {
             FIXME("Rollback only action... rollbacks not supported yet\n");
             schedule_action(package, ROLLBACK_SCRIPT, action);
@@ -114,7 +160,7 @@
         }
         if (!execute)
         {
-            if (type & 0x200)
+            if (type & msidbCustomActionTypeCommit)
             {
                 TRACE("Deferring Commit Action!\n");
                 schedule_action(package, COMMIT_SCRIPT, action);
@@ -136,11 +182,16 @@
 
             static const WCHAR szActionData[] = {
             'C','u','s','t','o','m','A','c','t','i','o','n','D','a','t','a',0};
+            static const WCHAR szBlank[] = {' ',0};
             LPWSTR actiondata = load_dynamic_property(package,action,NULL);
             if (actiondata)
                 MSI_SetPropertyW(package,szActionData,actiondata);
+            else
+                MSI_SetPropertyW(package,szActionData,szBlank);
         }
     }
+    else if (!check_execution_scheduling_options(package,action,type))
+        return ERROR_SUCCESS;
 
     switch (type & CUSTOM_ACTION_TYPE_MASK)
     {
@@ -304,7 +355,7 @@
 {
     UINT rc = ERROR_SUCCESS;
 
-    if (!(type & 0x80))
+    if (!(type & msidbCustomActionTypeAsync))
     {
         /* synchronous */
         TRACE("Synchronous Execution of action %s\n",debugstr_w(Name));
@@ -313,7 +364,7 @@
         else
             msi_dialog_check_messages(ThreadHandle);
 
-        if (!(type & 0x40))
+        if (!(type & msidbCustomActionTypeContinue))
         {
             if (ProcessHandle)
                 rc = process_action_return_value(2,ProcessHandle);
@@ -331,7 +382,7 @@
     {
         TRACE("Asynchronous Execution of action %s\n",debugstr_w(Name));
         /* asynchronous */
-        if (type & 0x40)
+        if (type & msidbCustomActionTypeContinue)
         {
             if (ProcessHandle)
             {
Index: dlls/msi/helpers.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/helpers.c,v
retrieving revision 1.4
diff -u -r1.4 helpers.c
--- dlls/msi/helpers.c	29 Jun 2005 19:19:09 -0000	1.4
+++ dlls/msi/helpers.c	30 Jun 2005 12:40:16 -0000
@@ -576,6 +576,11 @@
         
             HeapFree(GetProcessHeap(),0,package->script->Actions[i]);
         }
+
+        for (i = 0; i < package->script->UniqueActionsCount; i++)
+            HeapFree(GetProcessHeap(),0,package->script->UniqueActions[i]);
+
+        HeapFree(GetProcessHeap(),0,package->script->UniqueActions);
         HeapFree(GetProcessHeap(),0,package->script);
     }
 
@@ -911,6 +916,45 @@
             newstate, debugstr_w(component->Component), component->Installed, 
             component->Action, component->ActionRequest);
     } 
+}
+
+UINT register_unique_action(MSIPACKAGE *package, LPCWSTR action)
+{
+    UINT count;
+    LPWSTR *newbuf = NULL;
+
+    if (!package || !package->script)
+        return FALSE;
+
+    TRACE("Registering Action %s as having fun\n",debugstr_w(action));
+    
+    count = package->script->UniqueActionsCount;
+    package->script->UniqueActionsCount++;
+    if (count != 0)
+        newbuf = HeapReAlloc(GetProcessHeap(),0,
+                        package->script->UniqueActions,
+                        package->script->UniqueActionsCount* sizeof(LPWSTR));
+    else
+        newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
+
+    newbuf[count] = strdupW(action);
+    package->script->UniqueActions = newbuf;
+
+   return ERROR_SUCCESS;
+}
+
+BOOL check_unique_action(MSIPACKAGE *package, LPCWSTR action)
+{
+    INT i;
+
+    if (!package || !package->script)
+        return FALSE;
+
+    for (i = 0; i < package->script->UniqueActionsCount; i++)
+        if (!strcmpW(package->script->UniqueActions[i],action))
+            return TRUE;
+
+    return FALSE;
 }
 
 WCHAR* generate_error_string(MSIPACKAGE *package, UINT error, DWORD count, ... )
Index: dlls/msi/upgrade.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/upgrade.c,v
retrieving revision 1.2
diff -u -r1.2 upgrade.c
--- dlls/msi/upgrade.c	16 Jun 2005 16:08:58 -0000	1.2
+++ dlls/msi/upgrade.c	30 Jun 2005 12:40:16 -0000
@@ -211,12 +211,14 @@
     UINT rc = ERROR_SUCCESS;
     MSIQUERY *view;
 
-    if (package->script && package->script->FindRelatedProductsRun)
+    if (check_unique_action(package,szFindRelatedProducts))
+    {
+        TRACE("Skipping FindRelatedProducts action: already done on client side\n");
         return ERROR_SUCCESS;
+    }
+    else
+        register_unique_action(package,szFindRelatedProducts);
 
-    if (package->script)
-        package->script->FindRelatedProductsRun = TRUE;
-    
     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
     if (rc != ERROR_SUCCESS)
         return ERROR_SUCCESS;


More information about the wine-patches mailing list