Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing URL parameters to a ClickOnce application in any browser

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 ?

like image 889
Bugmaster Avatar asked Jun 12 '12 23:06

Bugmaster


1 Answers

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.

Steps for setting URL:

  1. Make a copy of the executable because the next command alters the file:

     COPY setup.exe grape_setup.exe
    
  2. 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 &.

Resigning the executable

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:

  • Uncheck "Sign the ClickOnce manifests" before publishing, publish, then use -url to set the URL. Finally use signtool.exe to sign.
  • Publish as usual, use -url to set the URL. Follow up with delcert to clean the broken signature. Finally use signtool.exe to sign.
  • Publish as usual. Then use 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:

  1. Make a copy of the executable as grape_setup.exe. (Described in first example)

  2. Remove the Authenticode signature:

    delcert.exe grape_setup.exe
    
  3. Replace the URL to set our parameters. (Described in first example)

  4. 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.

Having the build process leave an unsigned bootstrapper

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.

like image 161
antak Avatar answered Sep 24 '22 15:09

antak