ClickOnce for Rust Apps
ClickOnce is a cool decentralized way of distributing applications on Windows. I’ll demonstrate distributing a Rust language application using ClickOnce. The game uses Rust/WinRT to build a UI on top of the Windows Runtime. ClickOnce shipped with .NET Framework 2.0 in January of 2006. Almost 15 years later, .NET 5.0 was announced with improved ClickOnce support. A simple .NET 5.0 app is used to launch the bundled game.
Published to GitHub Pages
I published the app to GitHub Pages in an orphaned gh-pages branch. A concern of this approach may be bloat for the GitHub repository. One way to keep the repository smaller is to not keep history in that branch by force pushing to it. I published the Minesweeper.application
file and the entire Application Files/Minesweeper_0_1_0_0
folder.
The Application Files
folder contains all the files with a .deploy
extension. To avoid some checksum validation problems due to different line endings, I added a .gitattributes
file.
The published files were copies from the ClickOnce the app.publish folder. The ClickOnce can be tested locally by double clicking on the Minesweeper.application. The .NET launcher can be tested without ClickOnce by just clicking on the Minesweeper.exe. The Rust app can be tested without the .NET launcher by clicking on the minesweeper-rs.exe.
ClickOnce Publishing
I put all the files needed to publish via ClickOnce in a folder named ClickOnce
. After building the Rust app with cargo build --release
, I just call .\ClickOnce\build.ps1
. It launches msbuild
to build the .NET launcher, create the ClickOnce Application Manifest, create the ClickOnce Deployment Manifest, and sign both of them, creating the app.publish
folder above. The targets come with any version of Visual Studio, include Visual Studio Build Tools. The targets to sign the manifests do not work with dotnet msbuild
yet, so stick to msbuild
. In PowerShell, I can add add it to the PATH
environment variable with $env:PATH
FYI, Visual Studio Build Tools are available using winget. Run winget install Microsoft.VisualStudio.BuildTools
. There are a few ways to install winget, but I usually just download and launch the latest .appxbundle from the most recent release on the releases page. Running the Visual Studio Installer app will help you update if you wish to.
You could build the ClickOnce manifests by hand, but it is much easier to let the MSBuild targets do it for you using a publish profile. A publish profile is itself an MSBuild file containing a bunch of properties and items.
The ClickOnce\Properties\PublishProfiles\ClickOnceProfile.pubxml
was generated from a Build > Publish wizard in Visual Studio. I’m not sure what the minimal set of properties are.
I moved a couple of the properties into a ClickOnceProfile.pubxml.user
file that are specific to a particular user and shouldn’t be committed. The InstallUrl
is the base URL for the deployments. The ManifestCertificateThumbprint
is the certificate of my locally installed code signing certificate.
.NET Launcher
The .NET app that starts the Rust app is a very basic Windows Form application.
The project file is also straight forward, but take the time to read how .NET 5.0 has changed things, especially TargetFramework
:
Windows desktop APIs (including Windows Forms, WPF, and WinRT) will only be available when targeting net5.0-windows. You can specify an operating system version, like
net5.0-windows7
ornet5.0-windows10.0.17763.0
( for Windows October 2018 Update). You need to target a Windows 10 version if you want to use WinRT APIs.
I added the Configuration
and PublishProfile
properties to that project file, but you leave them out and pass them in or override them by passing them as parameters to msbuild
on the command line, such as /p:Configuration=Release
and /p:PublishProfile=ClickOnceProfile
.
Wrapping it Up
I enjoy seeing Rust being used more for desktop application development. Projects like Rust/WinRT and gtk-rs are making desktop application development more accessible from Rust. I’m looking forward to even better support for WinUI 3 and GTK 4.0. Even though ClickOnce is a .NET component, it can be used to distribute desktop apps built in Rust as well.