Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

desktop: Add a windows .msi installer #17335

Merged
merged 5 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/release_nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,14 @@ jobs:
target: i686-pc-windows-msvc
RUSTFLAGS: -Ctarget-feature=+crt-static
DESKTOP_FEATURES: jpegxr
MSI_ARCH: x86

- build_name: windows-x86_64
os: windows-latest
target: x86_64-pc-windows-msvc
RUSTFLAGS: -Ctarget-feature=+crt-static
DESKTOP_FEATURES: jpegxr
MSI_ARCH: x64

env:
PACKAGE_FILE: ${{ needs.create-nightly-release.outputs.package_prefix }}-${{ matrix.build_name }}.${{ startsWith(matrix.build_name, 'win') && 'zip' || 'tar.gz' }}
Expand All @@ -117,6 +119,13 @@ jobs:
sudo apt-get update
sudo apt install -y libasound2-dev libxcb-shape0-dev libxcb-xfixes0-dev libgtk-3-dev libudev-dev

- name: Install WiX
run: |
dotnet tool install --global wix
wix extension add -g WixToolset.UI.wixext
wix extension add -g WixToolset.Util.wixext
if: runner.os == 'Windows'

- name: Cargo build
run: cargo build --locked --package ruffle_desktop --release ${{matrix.DESKTOP_FEATURES && '--features' }} ${{matrix.DESKTOP_FEATURES}} ${{ matrix.target && '--target' }} ${{ matrix.target }}
env:
Expand All @@ -129,6 +138,15 @@ jobs:
cp README.md package/README.md
cp LICENSE.md package/LICENSE.md

- name: Package MSI
run: |
cd desktop/packages/windows/wix
wix build ruffle.wxs -ext WixToolset.UI.wixext -ext WixToolset.Util.wixext -arch ${{ matrix.MSI_ARCH }} -o ../../../../package/setup.msi -pdbtype none
env:
RUFFLE_VERSION: "0.1.0"
kjarosh marked this conversation as resolved.
Show resolved Hide resolved
CARGO_BUILD_DIR: target/${{ matrix.target }}/release
if: runner.os == 'Windows'

- name: Package Windows
if: runner.os == 'Windows'
run: |
Expand Down
Binary file modified desktop/assets/favicon.ico
Binary file not shown.
1 change: 1 addition & 0 deletions desktop/assets/ruffle_desktop.rc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// winres.h cannot be included, so define manually
#define VS_VERSION_INFO 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering about these version-related strings in this file (VER_FILEVERSION, VER_PRODUCTVERSION). Are they important? If they are, we should probably set them dynamically based on the version from cargo somehow?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we should! They're not critical by any means, but it's good practice to set them. It's the windows equivalent of tools giving --version as a standard CLI argument.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we could set them dynamically in build.rs then. It seems that we can use the macros parameter for that, however I'm unsure how that works and I wasn't able to find any examples. We should also consider parameterizing VER_DEBUG and possibly the year.

#define VS_FF_DEBUG 0x1L
#define VS_FFI_FILEFLAGSMASK 0x17L
#define VOS__WINDOWS32 0x4L
Expand Down
25 changes: 25 additions & 0 deletions desktop/packages/windows/wix/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Ruffle installer (.msi)
## Prerequisites
To build the msi, you need to set up your environment first:
- [Install `wix`](https://wixtoolset.org/docs/intro/#nettool) (`dotnet tool install --global wix`)
- `wix extension add -g WixToolset.UI.wixext` to add the UI extension
- `wix extension add -g WixToolset.Util.wixext` to add the util extension
- [Build Ruffle desktop](../../../../README.md) for releases (`cargo build --release`)
- or at least have a prebuilt `exe` ready to go at `target/release/ruffle_desktop.exe` (inside repository root)

## Environment variables
### `RUFFLE_VERSION` (required)
This should be set to the version of Ruffle that this MSI contains.
The format should either be `1.2.3` or `1.2.3.4` - however the fourth value is IGNORED by Windows for "is it the same version or newer" checks.

### `CARGO_BUILD_DIR` (optional)
This should be set to the folder that contains `ruffle_desktop`. The default value is `../../../../target/release`.

# Build
In this directory, run: `wix build ruffle.wxs -ext WixToolset.UI.wixext -ext WixToolset.Util.wixext -arch x64`

You can change `-arch` to `x86` to mark the msi as x86 (and install to, for example, `Program Files (x86)`)

Add `-pdbtype none` to disable generation of the `.wixpdb` if you wish.

Add `-o foo.msi` to control where the MSI is placed.
Binary file added desktop/packages/windows/wix/banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added desktop/packages/windows/wix/dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
128 changes: 128 additions & 0 deletions desktop/packages/windows/wix/dialog.wxi
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<!-- Modified version of WixUI_InstallDir, originally licensed MS-RL. -->

<!--
First-time install dialog sequence:
- WixUI_WelcomeDlg
- WixUI_InstallDirDlg
- WixUI_VerifyReadyDlg
- WixUI_DiskCostDlg

Maintenance dialog sequence:
- WixUI_MaintenanceWelcomeDlg
- WixUI_MaintenanceTypeDlg
- WixUI_InstallDirDlg
- WixUI_VerifyReadyDlg

Patch dialog sequence:
- WixUI_WelcomeDlg
- WixUI_VerifyReadyDlg

-->

<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
<?foreach WIXUIARCH in X86;X64;A64 ?>
<Fragment>
<UI Id="WixUI_InstallDir_NoLicense_$(WIXUIARCH)">
<Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath_$(WIXUIARCH)" Order="3"
Condition="NOT WIXUI_DONTVALIDATEPATH"/>
<Publish Dialog="RuffleInstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath_$(WIXUIARCH)"
Order="2" Condition="NOT WIXUI_DONTVALIDATEPATH"/>
</UI>

<UIRef Id="WixUI_InstallDir_NoLicense"/>
</Fragment>
<?endforeach?>

<Fragment>
<UI Id="file WixUI_InstallDir_NoLicense">
<TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8"/>
<TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12"/>
<TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes"/>

<Property Id="DefaultUIFont" Value="WixUI_Font_Normal"/>

<DialogRef Id="BrowseDlg"/>
<DialogRef Id="DiskCostDlg"/>
<DialogRef Id="ErrorDlg"/>
<DialogRef Id="FatalError"/>
<DialogRef Id="FilesInUse"/>
<DialogRef Id="MsiRMFilesInUse"/>
<DialogRef Id="PrepareDlg"/>
<DialogRef Id="ProgressDlg"/>
<DialogRef Id="ResumeDlg"/>
<DialogRef Id="UserExit"/>
<Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="4"
Condition="NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID&lt;&gt;&quot;1&quot;"/>

<Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999"/>

<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="RuffleInstallDirDlg"
Condition="NOT Installed"/>
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg"
Condition="Installed AND PATCH"/>

<Publish Dialog="RuffleInstallDirDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg"/>
<Publish Dialog="RuffleInstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]"
Order="1"/>
<Publish Dialog="RuffleInstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3"
Condition="NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID&lt;&gt;&quot;1&quot;"/>
<Publish Dialog="RuffleInstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="4"
Condition="WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID=&quot;1&quot;"/>
<Publish Dialog="RuffleInstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty"
Value="[WIXUI_INSTALLDIR]"
Order="1"/>
<Publish Dialog="RuffleInstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg"
Order="2"/>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="RuffleInstallDirDlg" Order="1"
Condition="NOT Installed"/>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2"
Condition="Installed AND NOT PATCH"/>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2"
Condition="Installed AND PATCH"/>

<Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg"/>

<Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg"/>
<Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg"/>
<Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg"/>

<Property Id="ARPNOMODIFY" Value="1"/>
</UI>

<UIRef Id="WixUI_Common"/>
</Fragment>

<Fragment>
<UI>
<Dialog Id="RuffleInstallDirDlg" Width="370" Height="270" Title="!(loc.InstallDirDlg_Title)">
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes"
Text="!(loc.WixUINext)"/>
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="!(loc.WixUIBack)"/>
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes"
Text="!(loc.WixUICancel)">
<Publish Event="SpawnDialog" Value="CancelDlg"/>
</Control>

<Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes"
NoPrefix="yes" Text="!(loc.InstallDirDlgDescription)"/>
<Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"
Text="!(loc.InstallDirDlgTitle)"/>
<Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no"
Text="!(loc.InstallDirDlgBannerBitmap)"/>
<Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0"/>
<Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0"/>

<Control Id="FolderLabel" Type="Text" X="20" Y="60" Width="290" Height="30" NoPrefix="yes"
Text="!(loc.InstallDirDlgFolderLabel)"/>
<Control Id="Folder" Type="PathEdit" X="20" Y="100" Width="320" Height="18" Property="WIXUI_INSTALLDIR"
Indirect="yes"/>
<Control Id="ChangeFolder" Type="PushButton" X="20" Y="120" Width="56" Height="17"
Text="!(loc.InstallDirDlgChange)"/>

<Control Id="DesktopShortcutCheckBox" Type="CheckBox" X="20" Y="160" Width="290" Height="17"
Property="INSTALLDESKTOPSHORTCUT" CheckBoxValue="1"
Text="Create a shortcut for this program on the desktop."/>
</Dialog>
</UI>
</Fragment>
</Include>
191 changes: 191 additions & 0 deletions desktop/packages/windows/wix/ruffle.wxs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
<?xml version='1.0' encoding='utf-8'?>

<!--
wix extension add -g WixToolset.UI.wixext
wix extension add -g WixToolset.Util.wixext
RUFFLE_VERSION="xxxxxx" wix build ruffle.wxs -ext WixToolset.UI.wixext -ext WixToolset.Util.wixext -arch x64
-->

<Wix xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui"
xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"
xmlns="http://wixtoolset.org/schemas/v4/wxs"
xsi:schemaLocation="http://wixtoolset.org/schemas/v4/wxs https://raw.githubusercontent.com/wixtoolset/web/master/src/xsd4/wix.xsd
http://wixtoolset.org/schemas/v4/wxs/ui https://raw.githubusercontent.com/wixtoolset/web/master/src/xsd4/ui.xsd
http://wixtoolset.org/schemas/v4/wxs/util https://raw.githubusercontent.com/wixtoolset/web/master/src/xsd4/util.xsd">
<?include dialog.wxi?>

<!-- Set this to something else to be able to install the msi as a *different* package (e.g. for local testing) -->
<?define UpgradeCode = "C6A4BA50-FA08-4B87-9B55-D81A1C730D25"?>

<?ifdef env.CARGO_BUILD_DIR?>
<?define CargoBuildDir = "$(env.CARGO_BUILD_DIR)"?>
<?else?>
<?define CargoBuildDir = "../../../../target/release"?>
<?endif?>

<Package
Name='Ruffle'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a nitpick: there are mixed apostrophes (' vs "), we should probably use " everywhere.

UpgradeCode='$(var.UpgradeCode)'
Manufacturer='Ruffle LLC'
Language='1033'
Codepage='65001'
Version='$(env.RUFFLE_VERSION)'
InstallerVersion='500'
Compressed='yes'>

<MajorUpgrade
Schedule='afterInstallInitialize'
DowngradeErrorMessage='A newer version of Ruffle is already installed. Setup will now exit.'
AllowSameVersionUpgrades="yes"/>

<Media Id='1' Cabinet='media1.cab' EmbedCab='yes' DiskPrompt='CD-ROM #1'/>
<Property Id='DiskPrompt' Value='Ruffle Installation'/>

<Property Id="INSTALLDESKTOPSHORTCUT" Secure="yes" Value="1"/>

<StandardDirectory Id="ProgramFiles6432Folder">
<Directory Id='INSTALLFOLDER' Name='ruffle'>
<Component Id='EnsureDirectoryWritable' Guid='372b3408-c431-4f8b-99a4-f5518cb87f9e'>
<CreateFolder>
<util:PermissionEx User="Users" GenericAll="yes"/>
</CreateFolder>
</Component>

<Component Id='License' Guid='*'>
<File Id='LicenseFile'
DiskId='1'
Source='../../../../LICENSE.md'
KeyPath='yes'/>
</Component>

<Directory Id='Bin' Name='bin'>
<Component Id='Path' Guid='ABEDD436-5D52-4C25-9FD1-D810A2B66AC1' KeyPath='yes'>
<Environment
Id='PATH'
Name='PATH'
Value='[Bin]'
Permanent='no'
Part='last'
Action='set'
System='yes'/>
</Component>
<Component Id='binary0' Guid='*'>
<File
Id='DesktopEXE'
Name='ruffle.exe'
DiskId='1'
Source='$(CargoBuildDir)/ruffle_desktop.exe'
KeyPath='yes'>
<Shortcut Name="Ruffle" Directory="ProgramMenuFolder" Advertise="yes"
WorkingDirectory="INSTALLFOLDER" Icon="Icon.ico"/>
</File>
</Component>
<Component Id='DesktopShortcut' Guid='*' Condition="INSTALLDESKTOPSHORTCUT">
<!-- A useless registry key is needed to work as a keypath -->
<CreateFolder/>
<RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]"
Value="1" Type="integer" KeyPath="yes"/>
<Shortcut Name="Ruffle" Directory="DesktopFolder" Target="[#DesktopEXE]"
WorkingDirectory="INSTALLFOLDER" Icon="Icon.ico"/>
</Component>
</Directory>
</Directory>
</StandardDirectory>

<Component Id='Associations' Guid='2216512a-9c76-412f-ba36-08e703a56f25'>
<!--
This creates the Ruffle progids and *hints* that Ruffle can be associated with them.
This may or may not cause Windows to make the association, but more likely makes it ask the user
what they want the next time they open a swf.
-->

<ProgId Id='Ruffle.swf' Description='Flash Movie' Icon="DesktopEXE" IconIndex="1">
<Extension Id='swf' ContentType='application/x-shockwave-flash'>
<Verb Id='open' Command='Open' TargetFile='DesktopEXE' Argument='"%1"'/>
</Extension>
</ProgId>
<ProgId Id='Ruffle.spl' Description='Flash Movie' Icon="DesktopEXE" IconIndex="1">
<Extension Id='spl' ContentType='application/x-shockwave-flash'>
<Verb Id='open' Command='Open' TargetFile='DesktopEXE' Argument='"%1"'/>
</Extension>
</ProgId>
<ProgId Id='Ruffle.ruf' Description='Ruffle Bundle' Icon="DesktopEXE" IconIndex="1">
<Extension Id='ruf' ContentType='application/x.ruffle-bundle+zip'>
<Verb Id='open' Command='Open' TargetFile='DesktopEXE' Argument='"%1"'/>
</Extension>
</ProgId>

<!-- This tells Windows to include Ruffle in the "Open With" dialog -->
<RegistryValue Root="HKCR" Key=".swf\OpenWithProgids" Name="Ruffle.swf" Value="" Type="string"/>
<RegistryValue Root="HKCR" Key=".spl\OpenWithProgids" Name="Ruffle.spl" Value="" Type="string"/>
<RegistryValue Root="HKCR" Key=".ruf\OpenWithProgids" Name="Ruffle.ruf" Value="" Type="string"/>
</Component>

<Component Id='ApplicationInfo' Guid='f7e7c5bb-729c-427e-b913-fd0d2e11a143'>
<!--
Tell windows a few properties about our application, so that it can handle it slightly better in "Open With"

(wondering how Windows matches these to the ruffle.exe that we install at some arbitrary path the user picks?)
(well that's the fun part... it doesn't! Windows SOLELY goes by the filename. Isn't that convenient?!)
(rename an executable and suddenly windows can't associate these things with it anymore whoops)
-->

<RegistryKey Root="HKCR" Key="Applications\ruffle.exe">
<!-- Give Ruffle a better name in the "Open With" dialog, than just "ruffle.exe" -->
<RegistryValue Name="FriendlyAppName" Value="Ruffle" Type="string"/>

<!-- Hint that we can open certain files -->
<RegistryValue Key="SupportedTypes" Name=".swf" Value="" Type="string"/>
<RegistryValue Key="SupportedTypes" Name=".spl" Value="" Type="string"/>
<RegistryValue Key="SupportedTypes" Name=".ruf" Value="" Type="string"/>
</RegistryKey>
</Component>

<Feature
Id='Binaries'
Title='Application'
Description='Installs the Ruffle desktop application'
Level='1'
ConfigurableDirectory='INSTALLFOLDER'
AllowAdvertise='no'
Display='expand'>
<ComponentRef Id='EnsureDirectoryWritable'/>
<ComponentRef Id='License'/>
<ComponentRef Id='binary0'/>
<ComponentRef Id='Associations'/>
<ComponentRef Id='ApplicationInfo'/>
<ComponentRef Id="DesktopShortcut"/>

<Feature
Id='Environment'
Title='PATH Environment Variable'
Description='Add the install location of the Ruffle executable to the PATH system environment variable. This allows Ruffle to be called from any location.'
Level='1'>
<ComponentRef Id='Path'/>
</Feature>
</Feature>

<SetProperty Id='ARPINSTALLLOCATION' Value='[APPLICATIONFOLDER]' After='CostFinalize'/>


<Icon Id='Icon.ico' SourceFile='../../../assets/favicon.ico'/>
<Property Id='ARPPRODUCTICON' Value='Icon.ico'/>

<Property Id='ARPHELPLINK' Value='https://ruffle.rs'/>

<ui:WixUI
Id="WixUI_InstallDir_NoLicense"
InstallDirectory="INSTALLFOLDER"
>

</ui:WixUI>
<WixVariable
Id="WixUIBannerBmp"
Value="banner.png"
/>
<WixVariable
Id="WixUIDialogBmp"
Value="dialog.png"
/>
</Package>
</Wix>
Loading