问题
My ClickOnce installation fails with an error:
File, WindowsFormsProject.exe, has a different computed hash than specified in manifest.
I use MSBuild to generate ClickOnce deployment package. The relevant line from the build script:
<MSBuild Targets="Publish"
Projects="WindowsFormsProject.csproj"
ContinueOnError="false" />
The WindowsFormsProject.csproj has a Post-Build step that signs the executable, as follows:
signtool sign /a $(ProjectDir)\obj\$(PlatformName)\$(ConfigurationName)\$(TargetFileName)
The trouble is, when I look at the build log I see that the manifest is generated BEFORE the Post-Build event executes. So it's not surprising that hash codes don't match. The relevant lines from the build log:
_CopyManifestFiles:
WindowsFormsProject -> ...\WindowsFormsProject.application
...
PostBuildEvent:
Successfully signed: ...\WindowsFormsProject.exe
So, the questions are:
- Is there a way to sign the assembly BEFORE the manifest is generated during the <MSBuild> task?
- Is there a way to re-generate the manifest (and manifest only) after the build is complete so that hash codes match again?
Or, if you can think of a different solution to the problem, I'd appreciate your ideas.
回答1:
If you are using MSBuild 4, you can use AfterTargets property to sign assembly just after it was created and before any further steps will be taken. Remove your post-build step and add this block to your project instead:
<Target Name="SignOutput" AfterTargets ="CoreCompile">
<PropertyGroup>
<TimestampServerUrl>http://timestamp.verisign.com/scripts/timstamp.dll</TimestampServerUrl>
<ApplicationDescription>Foo bar</ApplicationDescription>
<SigningCertificateCriteria>/sha1 578a9486f10ed1118f2b5f428afb842e3f374793</SigningCertificateCriteria>
</PropertyGroup>
<ItemGroup>
<SignableFiles Include="$(ProjectDir)obj\$(PlatformName)\$(ConfigurationName)\$(TargetName)$(TargetExt)" />
</ItemGroup>
<GetFrameworkSdkPath>
<Output
TaskParameter="Path"
PropertyName="SdkPath" />
</GetFrameworkSdkPath>
<Exec Command=""$(SdkPath)bin\signtool" sign $(SigningCertificateCriteria) /d "$(ApplicationDescription)" /t "$(TimestampServerUrl)" "%(SignableFiles.Identity)"" />
</Target>
回答2:
The credit goes to Dmitriy for his answer. However I had to make slight changes to Dmitry's answer to make it work for me. Specifically:
- I added an ending tag for "Target"
- I am using Windows 8.1, and had to change the signtool.exe path
- I am using a PFX file and had to specify the password
- I didn't need to add all of the info he provided
Please modify the values for "my_signing_file.pfx", "mypassword", "myexe.exe" and to make this work for you:
<Target Name="SignOutput" AfterTargets="CoreCompile">
<Exec Command=""C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool.exe" sign /f "$(ProjectDir)my_signing_file.pfx" /p mypassword "$(ProjectDir)obj\$(ConfigurationName)\myexe.exe"" />
</Target>
回答3:
You can configure the signing process of the assembly and the ClickOnce manifest from VisualStudio:
- Right click your project > properties > Signing.
- Check "Sign the ClickOnce Manifest" and select the certificate you want to use.
- Check "Sign the assembly" and select the certificate you want to use.
- Save all the changes and publish again.
All these settings will be valid when you build using MsBuild.
Note: You can generate your self-signed certificate from that screen if required.
Note 2: Remember that you have TWO manifests "Application Manifest" and "Deployment Manifest" both must be signed with the same certificate.
If you need to re-sign your manifests at any time after the build you can use Mage.exe.
来源:https://stackoverflow.com/questions/12521642/file-has-a-different-computed-hash-than-specified-in-manifest-error-when-signi