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