Sfoglia il codice sorgente

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 anni fa
parent
commit
da1e38035c
5 ha cambiato i file con 82 aggiunte e 37 eliminazioni
  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>