I have a ClickOnce application, and I need the ability to pass URL parameters to it. For example, a user could click a URL of the form "http://foo.bar/MyApp.application?flavor=grape", and this will launch my application, passing the "?flavor=grape" query to it.
Unfortunately, it looks like this only works in IE out of the box. On Firefox and Chrome, the user must install add-ons in order to get ClickOnce deployment to work. My users work in a restrictive corporate environment, and are not allowed to install any add-ons, or anything else for that matter (ClickOnce does work for them, though). So, what do I do ?
One hack I could think of is registering my application as a file handler for some sufficiently unique file extension, such as ".bugmaster" . Then -- or so my theory went -- I could have my webserver generate a file named "flavor_grape.bugmaster"; the user will click a URL pointing to that file, then choose "Run" instead of "Save", and this will launch my application, who will then parse the filename for URL parameters. Unfortunately, this approach doesn't work either. It works perfectly fine when the "flavor_grape.bugmaster" file is opened from the local filesystem, but, for some reason, this does not work when the user attempts to open the file from a browser.
Does anyone have any other ideas ?
The accepted answer probably worked in the past, but using that undocumented /dest
parameter now just fails with: Unable to modify 'grape_setup.exe'. The file may be read-only or locked.
Fortunately, /dest
wasn't necessary when I tried it in VS 2017, and now in VS 2019, so the option can be simply ignored.
Make a copy of the executable because the next command alters the file:
COPY setup.exe grape_setup.exe
Replace the URL like so:
grape_setup.exe -url="http://foo.bar/MyApp.application?flavor=grape#"
This alters grape_setup.exe
so that subsequent runs launch the ClickOnce application as if it were opened from the specified URL.
But wait, what's that #
on the end?
For some reason I still haven't figured out, using -url
gives me an executable that has an extra /MyApp.application
on the end of the URL. The #
is there to separate out this string so it doesn't get treated as part of the last URL param's value. Using #
puts it in the fragment identifier but alternatives are using &junk=
or &_=
or just &
.
Using -url
modifies the executable and any Authenticode signatures are removed.
Unfortunately, it removes it in a way that breaks signtool.exe
when trying to resign:
SignTool Error: SignedCode::Sign returned error: 0x800700C1
%1 is not a valid Win32 application.
This blog post as well as a tool called delcert
sheds light on why this is happening.
Here's the output of delcert
:
ImageRemoveCertificate failed with error 0x00000057
This happens when there's a listing in IMAGE_DIRECTORY_SECURITY
in the PE's header, but the actual Authenticode signature has been stripped.
Let's fix that ...
Setting both fields to zero ...
Succeeded.
This suggests -url
removes the signature in a non-clean manner, and delcert
can fix this for us.
Given of this problem, there appears to be three options for getting a signed executable with embedded URL parameters:
-url
to set the URL. Finally use signtool.exe
to sign.-url
to set the URL. Follow up with delcert
to clean the broken signature. Finally use signtool.exe
to sign.delcert
to remove the signature. Use -url
to set the URL, and finally sign with signtool.exe
.The three methods all probably create the same executable. The first requires a change to .csproj
. The second and third depend on a third-party software delcert
.
Here's an actual example:
Make a copy of the executable as grape_setup.exe
. (Described in first example)
Remove the Authenticode signature:
delcert.exe grape_setup.exe
Replace the URL to set our parameters. (Described in first example)
Resign the newly created executable:
signtool.exe sign /sha1 XYZ /t "http://..." grape_setup.exe
The value of /sha1
is <ManifestCertificateThumbprint>
in the project .csproj
file.
The value of /t
is <ManifestTimestampUrl>
but /t
can be omitted if timestamping is not required.
I found another way of getting an unsigned setup.exe
which alleviates me having to remove the signature with software like delcert
.
By adding this to my .csproj
file, the build process leaves an unsigned copy under bin\Release\app.publish\
as unsigned_setup.exe
.
<Target Name="UnsignedBootstrapper" AfterTargets="_DeploymentGenerateBootstrapper" BeforeTargets="_DeploymentSignClickOnceDeployment">
<Copy SourceFiles="$(PublishDir)\setup.exe" DestinationFiles="$(PublishDir)\unsigned_setup.exe" />
</Target>
The _DeploymentGenerateBootstrapper
target generates the bootstrapper and _DeploymentSignClickOnceDeployment
signs it. The above target runs between the two to make a copy of the executable.
This worked in VS 2019 but target names could differ in other versions. I came across them by looking at the build output after setting verbosity to "Diagnostic" under Options
> Project and Solutions
> Build and Run
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With