瀏覽代碼

Use lazy evaluation for events from attributes. Is more consistent with existing events.

Martijn Laan 6 年之前
父節點
當前提交
09fc3e6912
共有 6 個文件被更改,包括 28 次插入29 次删除
  1. 3 3
      ISHelp/isx.xml
  2. 1 1
      Projects/Install.pas
  3. 2 2
      Projects/Main.pas
  4. 14 15
      Projects/ScriptRunner.pas
  5. 2 2
      Projects/Uninstall.pas
  6. 6 6
      Projects/Wizard.pas

+ 3 - 3
ISHelp/isx.xml

@@ -314,10 +314,10 @@ end;
 
 <ul>
 <li>The implementations will be called in order of their definition except that any main implementation (=the implementation without an event attribute) will be called last.</li>
-<li>Event attributes may only be used for event functions which are a procedure or are a function which return a Boolean. In the latter case:</li>
+<li>Event attributes may only be used for event functions which are a procedure or are a function which return a Boolean. In the latter case lazy evaluation is performed:</li>
 <ul>
-<li><tt>InitializeSetup</tt>, <tt>BackButtonClick</tt>, <tt>NextButtonClick</tt>, <tt>InitializeUninstall</tt>: All implementations must return True for the event function to be treated as returning True and an implementation returning False does not stop the calls to the other implementations. In other words: the results are 'and'-ed without lazy evaluation.</li>
-<li><tt>CheckPassword</tt>, <tt>CheckSerial</tt>, <tt>ShouldSkipPage</tt>, <tt>NeedRestart</tt>: One implementation must return True for the event function to be treated as returning True and an implementation returning True does not stop the calls to the other implementations. In other words: the results are 'or'-ed without lazy evaluation.</li>
+<li><tt>InitializeSetup</tt>, <tt>BackButtonClick</tt>, <tt>NextButtonClick</tt>, <tt>InitializeUninstall</tt>: All implementations must return True for the event function to be treated as returning True and an implementation returning False stops the calls to the other implementations.</li>
+<li><tt>CheckPassword</tt>, <tt>CheckSerial</tt>, <tt>ShouldSkipPage</tt>, <tt>NeedRestart</tt>: All implementation must return False for the event function to be treated as returning False and an implementation returning True stop the calls to the other implementations.</li>
 </ul>
 <li>Event attributes may only be used on procedures or functions which do not already have the name of an event function.</li>
 <li>If the event function uses <tt>var</tt> parameters then the value will be passed on from implementation to implementation.</li>

+ 1 - 1
Projects/Install.pas

@@ -2920,7 +2920,7 @@ var
     if (CodeRunner <> nil) and CodeRunner.FunctionExists('NeedRestart', True) then begin
       if not NeedsRestart then begin
         try
-          if CodeRunner.RunBooleanFunctions('NeedRestart', [''], False, False, False) then begin
+          if CodeRunner.RunBooleanFunctions('NeedRestart', [''], bcTrue, False, False) then begin
             NeedsRestart := True;
             Log('Will restart because NeedRestart returned True.');
           end;

+ 2 - 2
Projects/Main.pas

@@ -2706,7 +2706,7 @@ var
       if shPassword in SetupHeader.Options then
         PasswordOk := TestPassword(S);
       if not PasswordOk and (CodeRunner <> nil) then
-        PasswordOk := CodeRunner.RunBooleanFunctions('CheckPassword', [S], False, False, PasswordOk);
+        PasswordOk := CodeRunner.RunBooleanFunctions('CheckPassword', [S], bcTrue, False, PasswordOk);
 
       if PasswordOk then begin
         Result := False;
@@ -3313,7 +3313,7 @@ begin
       raise;
     end;
     try
-      Res := CodeRunner.RunBooleanFunctions('InitializeSetup', [''], True, False, True);
+      Res := CodeRunner.RunBooleanFunctions('InitializeSetup', [''], bcFalse, False, True);
     except
       Log('InitializeSetup raised an exception (fatal).');
       raise;

+ 14 - 15
Projects/ScriptRunner.pas

@@ -24,6 +24,8 @@ type
   TScriptRunnerOnDebugIntermediate = function(const Position: LongInt; var ContinueStepOver: Boolean): Boolean;
   TScriptRunnerOnException = procedure(const Exception: AnsiString; const Position: LongInt);
 
+  TBreakCondition = (bcNone, bcTrue, bcFalse);
+
   TScriptRunner = class
     private
       FNamingAttribute: String;
@@ -37,7 +39,7 @@ type
       FOnException: TScriptRunnerOnException;
       function GetProcNos(const Name: AnsiString; const CheckNamingAttribute: Boolean; const ProcNos: TPSList): Integer;
       procedure InternalRunProcedure(const Name: AnsiString; const Parameters: array of Const; const CheckNamingAttribute, MustExist: Boolean);
-      function InternalRunBooleanFunction(const Name: AnsiString; const Parameters: array of Const; const CheckNamingAttribute, CheckNamingAttributeAndResults, MustExist, Default: Boolean): Boolean;
+      function InternalRunBooleanFunction(const Name: AnsiString; const Parameters: array of Const; const CheckNamingAttribute: Boolean; const BreakCondition: TBreakCondition; const MustExist, Default: Boolean): Boolean;
       procedure Log(const S: String);
       procedure LogFmt(const S: String; const Args: array of const);
       procedure RaisePSExecException;
@@ -52,7 +54,7 @@ type
       procedure RunProcedure(const Name: AnsiString; const Parameters: array of Const; const MustExist: Boolean);
       procedure RunProcedures(const Name: AnsiString; const Parameters: array of Const; const MustExist: Boolean);
       function RunBooleanFunction(const Name: AnsiString; const Parameters: array of Const; const MustExist, Default: Boolean): Boolean;
-      function RunBooleanFunctions(const Name: AnsiString; const Parameters: array of Const; const AndResults, MustExist, Default: Boolean): Boolean;
+      function RunBooleanFunctions(const Name: AnsiString; const Parameters: array of Const; const BreakCondition: TBreakCondition; const MustExist, Default: Boolean): Boolean;
       function RunIntegerFunction(const Name: AnsiString; const Parameters: array of Const; const MustExist: Boolean; const Default: Integer): Integer;
       function RunStringFunction(const Name: AnsiString; const Parameters: array of Const; const MustExist: Boolean; const Default: String): String;
       function EvaluateUsedVariable(const Param1, Param2, Param3: LongInt; const Param4: AnsiString): String;
@@ -455,17 +457,17 @@ begin
   InternalRunProcedure(Name, Parameters, True, MustExist);
 end;
 
-function TScriptRunner.InternalRunBooleanFunction(const Name: AnsiString; const Parameters: array of Const; const CheckNamingAttribute, CheckNamingAttributeAndResults, MustExist, Default: Boolean): Boolean;
+function TScriptRunner.InternalRunBooleanFunction(const Name: AnsiString; const Parameters: array of Const; const CheckNamingAttribute: Boolean; const BreakCondition: TBreakCondition; const MustExist, Default: Boolean): Boolean;
 var
   ProcNos, Params: TPSList;
   Res: PPSVariant;
-  ProcResult: Boolean;
   I: Integer;
 begin
   ProcNos := TPSList.Create;
   try
     if GetProcNos(Name, CheckNamingAttribute, ProcNos) <> 0 then begin
-      Result := True; { Silence compiler }
+      if (BreakCondition = bcNone) and (ProcNos.Count > 1) then
+        InternalError('InternalRunBooleanFunction: invalid BreakCondition');
       for I := 0 to ProcNos.Count-1 do begin
         Params := TPSList.Create();
         try
@@ -475,13 +477,10 @@ begin
           WriteBackParameters(Parameters, Params);
 
           RaisePSExecException;
-          ProcResult := PPSVariantU8(Res).Data = 1;
-          if I = 0 then
-            Result := ProcResult
-          else if CheckNamingAttributeAndResults then
-            Result := Result and ProcResult { Don't break on Result = False: need to call all procs always. }
-          else
-            Result := Result or ProcResult { Don't break on Result = True: need to call all procs always. }
+          Result := PPSVariantU8(Res).Data = 1;
+          if (Result and (BreakCondition = bcTrue)) or
+             (not Result and (BreakCondition = bcFalse)) then
+            Exit;
         finally
           FreePSVariantList(Params);
         end;
@@ -498,12 +497,12 @@ end;
 
 function TScriptRunner.RunBooleanFunction(const Name: AnsiString; const Parameters: array of Const; const MustExist, Default: Boolean): Boolean;
 begin
-  Result := InternalRunBooleanFunction(Name, Parameters, False, False, MustExist, Default);
+  Result := InternalRunBooleanFunction(Name, Parameters, False, bcNone, MustExist, Default);
 end;
 
-function TScriptRunner.RunBooleanFunctions(const Name: AnsiString; const Parameters: array of Const; const AndResults, MustExist, Default: Boolean): Boolean;
+function TScriptRunner.RunBooleanFunctions(const Name: AnsiString; const Parameters: array of Const; const BreakCondition: TBreakCondition; const MustExist, Default: Boolean): Boolean;
 begin
-  Result := InternalRunBooleanFunction(Name, Parameters, True, AndResults, MustExist, Default);
+  Result := InternalRunBooleanFunction(Name, Parameters, True, BreakCondition, MustExist, Default);
 end;
 
 function TScriptRunner.RunIntegerFunction(const Name: AnsiString; const Parameters: array of Const; const MustExist: Boolean; const Default: Integer): Integer;

+ 2 - 2
Projects/Uninstall.pas

@@ -603,7 +603,7 @@ begin
       try
         if CodeRunner <> nil then begin
           try
-            Res := CodeRunner.RunBooleanFunctions('InitializeUninstall', [''], True, False, True);
+            Res := CodeRunner.RunBooleanFunctions('InitializeUninstall', [''], bcFalse, False, True);
           except
             Log('InitializeUninstall raised an exception (fatal).');
             raise;
@@ -657,7 +657,7 @@ begin
         if (CodeRunner <> nil) and CodeRunner.FunctionExists('UninstallNeedRestart', True) then begin
           if not UninstallNeedsRestart then begin
             try
-              if CodeRunner.RunBooleanFunctions('UninstallNeedRestart', [''], False, False, False) then begin
+              if CodeRunner.RunBooleanFunctions('UninstallNeedRestart', [''], bcTrue, False, False) then begin
                 UninstallNeedsRestart := True;
                 Log('Will restart because UninstallNeedRestart returned True.');
               end;

+ 6 - 6
Projects/Wizard.pas

@@ -250,7 +250,7 @@ implementation
 
 uses
   ShellApi, ShlObj, Types, Msgs, Main, PathFunc, CmnFunc, CmnFunc2,
-  MD5, InstFunc, SelFolderForm, Extract, Logging, RestartManager;
+  MD5, InstFunc, SelFolderForm, Extract, Logging, RestartManager, ScriptRunner;
 
 {$R *.DFM}
 
@@ -431,7 +431,7 @@ begin
     WizardUserInfoName := UserInfoNameEdit.Text;
     WizardUserInfoOrg := UserInfoOrgEdit.Text;
     WizardUserInfoSerial := UserInfoSerialEdit.Text;
-    Result := CodeRunner.RunBooleanFunctions('CheckSerial', [UserInfoSerialEdit.Text], False, True, False)
+    Result := CodeRunner.RunBooleanFunctions('CheckSerial', [UserInfoSerialEdit.Text], bcTrue, True, False)
   end else
     Result := True;
 end;
@@ -2042,7 +2042,7 @@ begin
     if not Result then begin
       try
         if CodeRunner <> nil then
-          Result := CodeRunner.RunBooleanFunctions('ShouldSkipPage', [PageID], False, False, Result);
+          Result := CodeRunner.RunBooleanFunctions('ShouldSkipPage', [PageID], bcTrue, False, Result);
       except
         Application.HandleException(Self);
       end;
@@ -2063,7 +2063,7 @@ procedure TWizardForm.NextButtonClick(Sender: TObject);
     if shPassword in SetupHeader.Options then
       Result := TestPassword(S);
     if not Result and (CodeRunner <> nil) then
-      Result := CodeRunner.RunBooleanFunctions('CheckPassword', [S], False, False, Result);
+      Result := CodeRunner.RunBooleanFunctions('CheckPassword', [S], bcTrue, False, Result);
 
     if Result then begin
       NeedPassword := False;
@@ -2228,7 +2228,7 @@ begin
     Exit;
 
   if CodeRunner <> nil then
-    if CodeRunner.RunBooleanFunctions('NextButtonClick', [CurPageID], True, False, True) = False then
+    if CodeRunner.RunBooleanFunctions( 'NextButtonClick', [CurPageID], bcFalse, False, True) = False then
       Exit;
 
   { Go to the next page, or close wizard if it was on the last page }
@@ -2328,7 +2328,7 @@ begin
     Exit;
 
   if CodeRunner <> nil then
-    if CodeRunner.RunBooleanFunctions('BackButtonClick', [CurPageID], True, False, True) = False then
+    if CodeRunner.RunBooleanFunctions('BackButtonClick', [CurPageID], bcFalse, False, True) = False then
       Exit;
 
   PrevPageID := GetPreviousPageID;