17

Visual Studio 2010 には、ビルド後のイベントでバッチ ファイルを実行するプロジェクトがあります。このバッチは、Microsoft SDK から signtool.exe を呼び出して、バイナリに署名し、タイムスタンプを付けます。

ただし、タイムスタンプ サーバー ( http://timestamp.verisign.com/scripts/timstamp.dllを使用) は、何らかの理由で信頼性が低く、失敗することがあります。これにより、ビルドが失敗しました。

その後、(このコードに基づいて) より高度なバッチ スクリプトを実装し、署名とタイムスタンプを分割し、失敗した場合はタイムスタンプ操作を再試行できるようにしました。

バッチ スクリプト (signfile.bat) の簡易バージョンを次に示します。

@echo off

REM sign the file...
signtool.exe /f Authenticode.pfx /p PASS %1

if %errorlevel% neq 0 exit /b %errorlevel%

set timestamp_server=http://timestamp.verisign.com/scripts/timstamp.dll

for /L %%a in (1,1,10) do (

    REM try to timestamp the file...
    signtool.exe timestamp /t %timestamp_server% %1

    if errorlevel 0 if not errorlevel 1 GOTO succeeded

    REM wait 2 seconds...
    ping -n 2 127.0.0.1 > nul
)

REM return an error code...
echo signfile.bat exit code is 1.
exit /b 1

:succeeded
REM return a successful code...
echo signfile.bat exit code is 0.
exit /b 0

ビルド後のイベント コードは次のようになります。

signfile.bat "$(OutDir)$(TargetName)$(TargetExt)"

そのため、タイムスタンプが失敗した場合、2 秒間隔で 10 回再試行します。

しかし、私たちが観察したことは、タイムスタンプが最初の試みからうまくいった場合、すべてが問題ないということでした. ただし、最初の試行が失敗した場合、次の試行でタイムスタンプが成功したとしても、ビルド後のイベント全体がコード -1 で失敗しました。

1>------ Build started: Project: myproject, Configuration: NonOptimized x64 ------
1>  Done Adding Additional Store
1>  Successfully signed: E:\tfs\MySolution\bin\x64\NonOptimized\myproject.dll
1>  
1>EXEC : SignTool error : The specified timestamp server either could not be reached
1>  or returned an invalid response.
1>    This may happen if you specify an RFC 3161 timestamp URL but used
1>    the /t option or you specified a legacy Authenticode timestamp URL
1>    but used the /tr option.
1>EXEC : SignTool error : An error occurred while attempting to timestamp: E:\tfs\MySolution\bin\x64\NonOptimized\myproject.dll
1>  
1>  
1>  Number of errors: 1
1>  
1>  Successfully timestamped: E:\tfs\MySolution\bin\x64\NonOptimized\myproject.dll
1>  
1>  signfile.bat exit code is 0.
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(113,5): error MSB3073: The command "signfile.bat "E:\tfs\MySolution\bin\x64\NonOptimized\myproject.dll"
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(113,5): error MSB3073: :VCEnd" exited with code -1.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

したがって、ご覧のとおり、signfile.bat から返されたエラー コードが 0 であっても、Visual Studio はそれを -1 と見なし、イベントを失敗させます。

ver>nulあちこちに追加する、または最後に追加する (確かに signfile.bat の前に「call」を追加する) など、エラー フラグをクリアしようとするすべての試みは、exit 0Visual Studio が errorlevel だけでなく何かもチェックしたように見えたため、役に立ちませんでしたそうしないと。実際、バッチと signfile.bat は、エラーの場合に 0 または 1 のみを返しますが、-1 は返しません。また、signtool.exe が 1 回エラーを返した場合、ビルド後のイベントが失敗しないように Visual Studio を説得する方法はないようです。

4

2 に答える 2

27

実験と検索に多くの時間を費やした後、コメントでここに言及されている記事を見つけました。Visual Studio が出力をスキャンして、特別なキーワードを検索しているようです。Signtool.exe は他の .xml と一緒に出力します。これは、エラーが発生したことを Visual Studio に警告するのに十分なようです。EXEC : SignTool error : An error occurred

したがって、提案された解決策は、出力とエラー ストリームを nul as にリダイレクトすることでした2>nul 1>nul。エラーレベルは引き続き設定されるため、エラーが発生したかどうかを判断できます。ただし、ステータスを確認するには、いくつかの追加メッセージを出力する必要がある場合があります。

REM try to timestamp the file...
signtool.exe timestamp /t %timestamp_server% %1 2>nul 1>nul

if errorlevel 0 if not errorlevel 1 (
    echo Successfully timestamped: %1
    GOTO succeeded
)
echo Timestamping failed for %1

これで Visual Studio は満足です:

1>------ Build started: Project: myproject, Configuration: NonOptimized x64 ------
1>  Done Adding Additional Store
1>  Successfully signed: E:\tfs\MySolution\bin\x64\NonOptimized\myproject.dll
1>  
1>  Timestamping failed for "E:\tfs\MySolution\bin\x64\NonOptimized\myproject.dll"
1>  Successfully timestamped: "E:\tfs\MySolution\bin\x64\NonOptimized\myproject.dll"
1>  signfile.bat exit code is 0.
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

実際、追加2>nulするだけで修正できます。エラー ストリームは引き続き出力されます:Number of errors: 1が、問題は発生しません。

于 2013-10-01T18:53:48.300 に答える