Browse Source

Added new [Setup] section directive: SignToolRetryCount, which defaults to 2. Specifies the number of times the Setup Compiler should automatically retry digital signing on any errors.

Martijn Laan 11 năm trước cách đây
mục cha
commit
da1e38035c
5 tập tin đã thay đổi với 82 bổ sung37 xóa
  1. 1 0
      Components/ScintStylerInnoSetup.pas
  2. 1 0
      Projects/CompMsgs.pas
  3. 63 36
      Projects/Compile.pas
  4. 15 0
      ishelp/isetup.xml
  5. 2 1
      whatsnew.htm

+ 1 - 0
Components/ScintStylerInnoSetup.pas

@@ -194,6 +194,7 @@ type
     ssSignedUninstaller,
     ssSignedUninstallerDir,
     ssSignTool,
+    ssSignToolRetryCount,
     ssSlicesPerDisk,
     ssSolidCompression,
     ssSourceDir,

+ 1 - 0
Projects/CompMsgs.pas

@@ -131,6 +131,7 @@ const
   SCompilerStatusWarning = 'Warning: ';
   SCompilerStatusSigningSetup = '   Signing Setup program executable';
   SCompilerStatusSigning = '   Running Sign Tool command: %s';
+  SCompilerStatusWillRetrySigning = '   Sign Tool command failed (%s). Will retry (%d tries left).';
 
   SCompilerSuccessfulMessage2 = 'The setup images were successfully created ' +
     'in the output directory:' + SNewLine +

+ 63 - 36
Projects/Compile.pas

@@ -153,6 +153,7 @@ type
     ssSignedUninstaller,
     ssSignedUninstallerDir,
     ssSignTool,
+    ssSignToolRetryCount,
     ssSlicesPerDisk,
     ssSolidCompression,
     ssSourceDir,
@@ -341,6 +342,7 @@ type
     {$IFDEF UNICODE} PreLangDataList, {$ENDIF} LangDataList: TList;
     SignToolList: TList;
     SignTool, SignToolParams: String;
+    SignToolRetryCount: Integer;
 
     OutputDir, OutputBaseFilename, OutputManifestFile, SignedUninstallerDir,
       ExeFilename: String;
@@ -490,7 +492,7 @@ type
     procedure ReadTextFile(const Filename: String; const LangIndex: Integer; var Text: AnsiString);
     procedure SeparateDirective(const Line: PChar; var Key, Value: String);
     procedure ShiftDebugEntryIndexes(AKind: TDebugEntryKind);
-    procedure Sign(const ACommand, AParams, AExeFilename: String);
+    procedure Sign(const ACommand, AParams, AExeFilename: String; const RetryCount: Integer);
     procedure WriteDebugEntry(Kind: TDebugEntryKind; Index: Integer);
     procedure WriteCompiledCodeText(const CompiledCodeText: Ansistring);
     procedure WriteCompiledCodeDebugInfo(const CompiledCodeDebugInfo: AnsiString);
@@ -4039,6 +4041,12 @@ begin
         if FindSignToolIndexByName(SignTool) = -1 then
           Invalid;
       end;
+    ssSignToolRetryCount: begin
+        I := StrToIntDef(Value, -1);
+        if I < 0 then
+          Invalid;
+        SignToolRetryCount := I;
+      end;
     ssSlicesPerDisk: begin
         I := StrToIntDef(Value, -1);
         if (I < 1) or (I > 26) then
@@ -7309,7 +7317,7 @@ begin
   SignToolList.Add(SignTool);
 end;
 
-procedure TSetupCompiler.Sign(const ACommand, AParams, AExeFilename: String);
+procedure TSetupCompiler.Sign(const ACommand, AParams, AExeFilename: String; const RetryCount: Integer);
 
   function FmtCommand(S: PChar; const AParams, AExeFileName: String): String;
   var
@@ -7350,45 +7358,63 @@ procedure TSetupCompiler.Sign(const ACommand, AParams, AExeFilename: String);
       end;
     end;
   end;
+  
+  procedure DoSign(const AFormattedCommand: String);
+  var
+    StartupInfo: TStartupInfo;
+    ProcessInfo: TProcessInformation;
+    LastError, ExitCode: DWORD;
+  begin
+    AddStatus(Format(SCompilerStatusSigning, [AFormattedCommand]));
+
+    FillChar(StartupInfo, SizeOf(StartupInfo), 0);
+    StartupInfo.cb := SizeOf(StartupInfo);
+    StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
+    StartupInfo.wShowWindow := SW_SHOW;
+    
+    if not CreateProcess(nil, PChar(AFormattedCommand), nil, nil, False,
+       CREATE_DEFAULT_ERROR_MODE, nil, PChar(CompilerDir), StartupInfo, ProcessInfo) then begin
+      LastError := GetLastError;
+      AbortCompileFmt(SCompilerSignToolCreateProcessFailed, [LastError,
+        Win32ErrorString(LastError)]);
+    end;
+    CloseHandle(ProcessInfo.hThread);
+    try
+      while True do begin
+        case WaitForSingleObject(ProcessInfo.hProcess, 50) of
+          WAIT_OBJECT_0: Break;
+          WAIT_TIMEOUT: CallIdleProc;
+        else
+          AbortCompile('Sign: WaitForSingleObject failed');
+        end;
+      end;
+      if not GetExitCodeProcess(ProcessInfo.hProcess, ExitCode) then
+        AbortCompile('Sign: GetExitCodeProcess failed');
+      if ExitCode <> 0 then
+        AbortCompileFmt(SCompilerSignToolNonZeroExitCode, [ExitCode]);
+    finally
+      CloseHandle(ProcessInfo.hProcess);
+    end;
+  end;
 
 var
   Params, Command: String;
-  StartupInfo: TStartupInfo;
-  ProcessInfo: TProcessInformation;
-  LastError, ExitCode: DWORD;
+  I: Integer;
 begin
   Params := FmtCommand(PChar(AParams), '', AExeFileName);
   Command := FmtCommand(PChar(ACommand), Params, AExeFileName);
-
-  AddStatus(Format(SCompilerStatusSigning, [Command]));
-
-  FillChar(StartupInfo, SizeOf(StartupInfo), 0);
-  StartupInfo.cb := SizeOf(StartupInfo);
-  StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
-  StartupInfo.wShowWindow := SW_SHOW;
-
-  if not CreateProcess(nil, PChar(Command), nil, nil, False,
-     CREATE_DEFAULT_ERROR_MODE, nil, PChar(CompilerDir), StartupInfo, ProcessInfo) then begin
-    LastError := GetLastError;
-    AbortCompileFmt(SCompilerSignToolCreateProcessFailed, [LastError,
-      Win32ErrorString(LastError)]);
-  end;
-  CloseHandle(ProcessInfo.hThread);
-  try
-    while True do begin
-      case WaitForSingleObject(ProcessInfo.hProcess, 50) of
-        WAIT_OBJECT_0: Break;
-        WAIT_TIMEOUT: CallIdleProc;
-      else
-        AbortCompile('Sign: WaitForSingleObject failed');
-      end;
+  
+  for I := 0 to RetryCount do begin
+    try
+      DoSign(Command);
+      Break;
+    except on E: Exception do
+      if I < RetryCount then begin
+        AddStatus(Format(SCompilerStatusWillRetrySigning, [E.Message, RetryCount-I]));
+        Sleep(500); //wait a little bit before retrying
+      end else
+        raise;
     end;
-    if not GetExitCodeProcess(ProcessInfo.hProcess, ExitCode) then
-      AbortCompile('Sign: GetExitCodeProcess failed');
-    if ExitCode <> 0 then
-      AbortCompileFmt(SCompilerSignToolNonZeroExitCode, [ExitCode]);
-  finally
-    CloseHandle(ProcessInfo.hProcess);
   end;
 end;
 
@@ -7997,7 +8023,7 @@ var
       end;
 
       try
-        Sign(TSignTool(SignToolList[SignToolIndex]).Command, SignToolParams, Filename);
+        Sign(TSignTool(SignToolList[SignToolIndex]).Command, SignToolParams, Filename, SignToolRetryCount);
         if not InternalSignSetupE32(Filename, UnsignedFile, UnsignedFileSize,
            SCompilerSignedFileContentsMismatch) then
           AbortCompile(SCompilerSignToolSucceededButNoSignature);
@@ -8260,6 +8286,7 @@ begin
     WizardSmallImageFile := 'compiler:WIZMODERNSMALLIMAGE.BMP';
     DefaultDialogFontName := 'Tahoma';
     SignTool := '';
+    SignToolRetryCount := 2;
     SetupHeader.CloseApplicationsFilter := '*.exe,*.dll,*.chm';
 
     { Read [Setup] section }
@@ -8814,7 +8841,7 @@ begin
         SignToolIndex := FindSignToolIndexByName(SignTool);
         if SignToolIndex <> -1 then begin
           AddStatus(SCompilerStatusSigningSetup);
-          Sign(TSignTool(SignToolList[SignToolIndex]).Command, SignToolParams, ExeFilename);
+          Sign(TSignTool(SignToolList[SignToolIndex]).Command, SignToolParams, ExeFilename, SignToolRetryCount);
         end;
       except
         EmptyOutputDir(False);

+ 15 - 0
ishelp/isetup.xml

@@ -910,6 +910,7 @@ DefaultGroupName=My Program
 <li><link topic="setup_signeduninstaller">SignedUninstaller</link></li>
 <li><link topic="setup_signeduninstallerdir">SignedUninstallerDir</link></li>
 <li><link topic="setup_signtool">SignTool</link></li>
+<li><link topic="setup_signtoolretrycount">SignToolRetryCount</link></li>
 <li><link topic="setup_slicesperdisk">SlicesPerDisk</link></li>
 <li><link topic="setup_solidcompression">SolidCompression</link></li>
 <li><link topic="setup_sourcedir">SourceDir</link></li>
@@ -4881,6 +4882,20 @@ SignTool=byparam format c:
 </example>
 <p>Details on obtaining signing certificates and using code-signing tools are beyond the scope of this documentation.</p>
 <p><i>Note:</i> If you use a Sign Tool and your Setup contains a large amount of data, it is recommended that you enable <link topic="setup_diskspanning">Disk spanning</link> with <link topic="setup_diskslicesize">DiskSliceSize</link> set to <tt>max</tt>. If you don't do this, the user might experience a long delay after starting Setup caused by Windows verifying the digital signature against all your data. There should be no security reduction from using disk spanning in practice: all files extracted from the unsigned .bin files undergo SHA-1 verification (provided <tt>dontverifychecksum</tt> isn't used). The SHA-1 hashes for this (along with all other metadata) are kept inside Setup's EXE, which is protected by the digital signature.</p>
+<p><b>See also:</b><br/>
+<link topic="setup_signtoolretrycount">SignToolRetryCount</link></p>
+</body>
+</setuptopic>
+
+<setuptopic directive="SignToolRetryCount">
+<keyword value="signature" />
+<keyword value="digital signature" />
+<keyword value="code signing" />
+<setupdefault><tt>2</tt></setupdefault>
+<body>
+<p>Specifies the number of times the Setup Compiler should automatically retry digital signing on any errors.</p>
+<p><b>See also:</b><br/>
+<link topic="setup_signtool">SignTool</link></p>
 </body>
 </setuptopic>
 

+ 2 - 1
whatsnew.htm

@@ -28,6 +28,7 @@ For conditions of distribution and use, see <a href="http://www.jrsoftware.org/f
 
 <p><a name="5.5.6"></a><span class="ver">5.5.6-dev </span><span class="date">(?)</span></p>
 <ul>
+<li>Added new [Setup] section directive: <tt>SignToolRetryCount</tt>, which defaults to <tt>2</tt>. Specifies the number of times the Setup Compiler should automatically retry digital signing on any errors.</li>
 <li><i>Fix:</i> Console-mode compiler (ISCC) change: Renamed /DO and /EO command line parameters to /O- and /O+ to avoid possible conflicts with /D.</li>
 <li>Various documentation improvements. Contributed by <a href="https://github.com/jogo-" target="_blank">jogo-</a> via <a href="https://github.com/jrsoftware" target="_blank">GitHub</a>.</li>
 <li>Minor tweaks.</li>
@@ -79,7 +80,7 @@ For conditions of distribution and use, see <a href="http://www.jrsoftware.org/f
 <p><a name="5.5.3"></a><span class="ver">5.5.3 </span><span class="date">(2013-01-30)</span></p>
 <ul>
 <li>Windows 8 change: [Icons] section flag <tt>excludefromshowinnewinstall</tt> now additionally prevents the new shortcut from being automatically pinned the Start screen.</li>
-<li>Added new command line parameters supported by Setup: /HELP and /?. Cause Setup to display the list of accepted command line parameters in a message box, exiting with exit code 0 afterwards. Ignored if the <tt>UseSetupLdr</tt> [Setup] section directive was set to <tt>no</tt>.</li>
+<li>Added new command line parameters supported by Setup: /HELP and /?. Causes Setup to display the list of accepted command line parameters in a message box, exiting with exit code 0 afterwards. Ignored if the <tt>UseSetupLdr</tt> [Setup] section directive was set to <tt>no</tt>.</li>
 <li>Added new command line parameter supported by Inno Setup's own installer: /PORTABLE=1. Causes Inno Setup's own installer to not create an uninstaller nor an entry in the <i>Add/Remove Programs</i> Control Panel applet. Also supported by QuickStart Pack's installer.</li>
 <li>Added workaround for bug in 64-bit Windows which in some cases would cause Windows to display an error message when a user tries to change the icon of an installed shortcut.</li>
 <li>Updated the compiler and document icons, created by Motaz Alnuweiri.</li>