Skip to content

Commit

Permalink
Create msi installer
Browse files Browse the repository at this point in the history
  • Loading branch information
WilliamVenner committed Feb 25, 2021
1 parent f61e56f commit 54e679c
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 111 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ keywords = ["blackhole", "black hole", "forget", "ramdisk", "organization", "org
description = "Semi-temporary directory for not-so-organized organized people"

[package.metadata.bundle]
name = "Blackhole"
identifier = "com.venner.blackhole"
icon = ["src/assets/blackhole.ico"]

Expand All @@ -31,7 +32,6 @@ objc = { version = "0.2.7", features = ["exception"] }
powershell_script = "0.1"
winapi = { version = "0.3", features = ["winuser"] }
rust-ini = "0.16"
winreg = "0.8"

[target.'cfg(target_os="windows")'.build-dependencies]
winres = "0.1"
2 changes: 2 additions & 0 deletions build.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cargo build --release --features gui
cargo wix --no-build --nocapture
16 changes: 1 addition & 15 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,7 @@ use std::io;

fn main() -> io::Result<()> {
#[cfg(windows)] {
WindowsResource::new()
.set_manifest(r#"
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
"#)

.set_icon("src/assets/blackhole.ico")
.compile()?;
WindowsResource::new().set_icon("src/assets/blackhole.ico").compile()?;
}
Ok(())
}
Binary file added src/assets/msi-banner.bmp
Binary file not shown.
Binary file added src/assets/msi.bmp
Binary file not shown.
96 changes: 1 addition & 95 deletions src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::Show;

use std::{ffi::{CString, OsString}, fs, iter, os::windows::ffi::OsStrExt, os::windows::process::CommandExt, path::Path, process::Command};
use ini::{Ini, EscapePolicy};
use winreg::{enums::*, RegKey};
use winapi::{
self,
um::winbase::CREATE_NO_WINDOW,
Expand Down Expand Up @@ -32,8 +31,6 @@ pub trait Windows {
fn set_file_attributes(path: &std::path::PathBuf, attr: winapi::shared::minwindef::DWORD) -> *const u16;
fn quick_access(path: &std::path::PathBuf);
fn set_blackhole_attributes(path: &std::path::PathBuf);
fn edit_context_menu_registry();
fn edit_startup_registry();
fn move_items(&self, from: &Path, to: &Path) -> Result<(), String>;
fn chores(&self);
}
Expand Down Expand Up @@ -139,91 +136,6 @@ impl Windows for Blackhole {
Blackhole::change_notify(path_utf16_ptr as *const _);
}

fn edit_context_menu_registry() {
// Add blackhole.exe --send to the File Explorer context menu

let exe_path = match std::env::current_exe() {
Ok(exe_path) => exe_path,
Err(error) => {
Show::error(&format!("Error getting executable path: {}", error));
return;
}
};

let hkcr = RegKey::predef(HKEY_CLASSES_ROOT);

for path in ["*\\shell\\Blackhole", "Folder\\shell\\blackhole"].iter() {
match hkcr.create_subkey_with_flags(*path, KEY_WRITE) {
Ok(blackhole_shell) => {
match blackhole_shell.0.set_value("", &"Blackhole") {
Ok(_) => (),
Err(error) => {
Show::error(&format!("Error setting registry key: {}", error));
return;
}
}

match blackhole_shell.0.set_value("Icon", &format!("\"{}\"", exe_path.display())) {
Ok(_) => (),
Err(error) => {
Show::error(&format!("Error setting registry key: {}", error));
return;
}
}

match blackhole_shell.0.create_subkey_with_flags("command", KEY_WRITE) {
Ok(command) => {
match command.0.set_value("", &format!("{} --send \"%1\"", exe_path.display())) {
Ok(_) => (),
Err(error) => {
Show::error(&format!("Error setting registry key: {}", error));
return;
}
}
},
Err(error) => {
Show::error(&format!("Error opening registry subkey: {}", error));
return;
}
};
},
Err(error) => {
Show::error(&format!("Error opening registry subkey: {}", error));
return;
}
};
}
}

fn edit_startup_registry() {
// Add blackhole.exe --purge to the startup registry

let exe_path = match std::env::current_exe() {
Ok(exe_path) => exe_path,
Err(error) => {
Show::error(&format!("Error getting executable path: {}", error));
return;
}
};

let hkcu = RegKey::predef(HKEY_CURRENT_USER);
let startup = match hkcu.open_subkey_with_flags("Software\\Microsoft\\Windows\\CurrentVersion\\Run", KEY_WRITE) {
Ok(startup) => startup,
Err(error) => {
Show::error(&format!("Error opening registry subkey: {}", error));
return;
}
};

match startup.set_value("Blackhole", &format!("{} --purge", exe_path.display())) {
Ok(_) => return,
Err(error) => {
Show::error(&format!("Error setting registry key: {}", error));
return;
}
};
}

fn move_items(&self, from: &Path, to: &Path) -> Result<(), String> {
let mut from_null_terminated = OsString::from(from);
from_null_terminated.push("\0\0");
Expand Down Expand Up @@ -251,13 +163,7 @@ impl Windows for Blackhole {
}
}

fn chores(&self) {
// If we're running Windows, add blackhole.exe --purge to the startup registry
Blackhole::edit_startup_registry();

// Add blackhole.exe --send to the context menu registry
Blackhole::edit_context_menu_registry();

fn chores(&self) {
// Set file/folder attributes
Blackhole::set_blackhole_attributes(&self.path);

Expand Down
Binary file added wix/License.rtf
Binary file not shown.
163 changes: 163 additions & 0 deletions wix/main.wxs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
<?xml version='1.0' encoding='windows-1252'?>
<!--
Copyright (C) 2017 Christopher R. Field.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<!--
Please do not remove these pre-processor If-Else blocks. These are used with
the `cargo wix` subcommand to automatically determine the installation
destination for 32-bit versus 64-bit installers. Removal of these lines will
cause installation errors.
-->
<?if $(var.Platform) = x64 ?>
<?define Win64 = "yes" ?>
<?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
<?else ?>
<?define Win64 = "no" ?>
<?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
<?endif ?>

<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>

<Product Id='*' Name='Blackhole' UpgradeCode='E04A54F8-7D00-44C8-973A-8258F273A41E' Manufacturer='William Venner' Language='1033' Codepage='1252' Version='$(var.Version)'>

<Package Id='*' Keywords='Installer' Description='Semi-temporary directory for not-so-organized organized people' Manufacturer='William Venner' InstallerVersion='450' Languages='1033' Compressed='yes' InstallScope='perMachine' SummaryCodepage='1252' Platform='$(var.Platform)'/>

<MajorUpgrade Schedule='afterInstallInitialize' DowngradeErrorMessage='A newer version of [ProductName] is already installed. Setup will now exit.'/>

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

<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='$(var.PlatformProgramFilesFolder)' Name='PFiles'>
<Directory Id='APPLICATIONFOLDER' Name='Blackhole'>
<!--
Disabling the license sidecar file in the installer is a two step process:
1. Comment out or remove the `Component` tag along with its contents.
2. Comment out or remove the `ComponentRef` tag with the "License" Id
attribute value further down in this file.
-->
<Component Id='License' Guid='*' Win64='$(var.Win64)'>
<File Id='LicenseFile' Name='License.rtf' DiskId='1' Source='wix\License.rtf' KeyPath='yes'/>
</Component>

<Component Id='binary0' Guid='*' Win64='$(var.Win64)'>
<File Id='exe0' Name='blackhole.exe' DiskId='1' Source='target\$(var.Profile)\blackhole.exe' KeyPath='yes'/>
</Component>

<Component Id='startup' Guid='*' Win64='$(var.Win64)'>
<RegistryValue Root="HKCU" Key="Software\Microsoft\Windows\CurrentVersion\Run" Name="Blackhole" Value='"[APPLICATIONFOLDER]blackhole.exe" --purge' Type="string" KeyPath="yes" Action="write"/>
</Component>

<Component Id='contextmenu' Guid='*' Win64='$(var.Win64)'>
<RegistryValue Root="HKCR" Key="*\shell\Blackhole" Value='Blackhole' Type="string" KeyPath="yes" Action="write"/>
<RegistryValue Root="HKCR" Key="*\shell\Blackhole" Name="Icon" Value='"[APPLICATIONFOLDER]blackhole.exe"' Type="string" KeyPath="no" Action="write"/>
<RegistryValue Root="HKCR" Key="*\shell\Blackhole" Name="command" Value='"[APPLICATIONFOLDER]blackhole.exe" --send "%1"' Type="string" KeyPath="no" Action="write"/>

<RegistryValue Root="HKCR" Key="Folder\shell\Blackhole" Value='Blackhole' Type="string" KeyPath="no" Action="write"/>
<RegistryValue Root="HKCR" Key="Folder\shell\Blackhole" Name="Icon" Value='"[APPLICATIONFOLDER]blackhole.exe"' Type="string" KeyPath="no" Action="write"/>
<RegistryValue Root="HKCR" Key="Folder\shell\Blackhole" Name="command" Value='"[APPLICATIONFOLDER]blackhole.exe" --send "%1"' Type="string" KeyPath="no" Action="write"/>
</Component>
</Directory>
</Directory>
</Directory>

<Feature Id='Binaries' Title='Application' Description='Installs all binaries and the license.' Level='1' ConfigurableDirectory='APPLICATIONFOLDER' AllowAdvertise='no' Display='expand' Absent='disallow'>
<!--
Comment out or remove the following `ComponentRef` tag to remove
the license sidecar file from the installer.
-->
<ComponentRef Id='License'/>

<ComponentRef Id='binary0'/>

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

<Feature Id='StartupReg' Title='Purge on Startup' Description='Purges the $BLACKHOLE directory when the computer starts up.' Level='1' AllowAdvertise='no' Display='expand' Absent='disallow'>
<ComponentRef Id='startup'/>
</Feature>

<Feature Id='ContextMenuReg' Title='Add Blackhole to context menu' Description='Adds "Blackhole" option to the right click menu on files and folders, which moves them to the $BLACKHOLE.' Level='1' AllowAdvertise='no' Display='expand' Absent='allow'>
<ComponentRef Id='contextmenu'/>
</Feature>

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


<!--
Uncomment the following `Icon` and `Property` tags to change the product icon.
The product icon is the graphic that appears in the Add/Remove
Programs control panel for the application.
-->
<Icon Id='ProductICO' SourceFile='src\assets\blackhole.ico'/>
<Property Id='ARPPRODUCTICON' Value='ProductICO' />

<Property Id='ARPHELPLINK' Value='https://github.com/WilliamVenner/blackhole'/>

<UI>
<UIRef Id='WixUI_FeatureTree'/>
<!--
Disabling the EULA dialog in the installer is a two step process:
1. Uncomment the following two `Publish` tags
2. Comment out or remove the `<WiXVariable Id='WixUILicenseRtf'...` tag further down
-->
<!--<Publish Dialog='WelcomeDlg' Control='Next' Event='NewDialog' Value='CustomizeDlg' Order='99'>1</Publish>-->
<!--<Publish Dialog='CustomizeDlg' Control='Back' Event='NewDialog' Value='WelcomeDlg' Order='99'>1</Publish>-->
</UI>

<!--
Disabling the EULA dialog in the installer requires commenting out
or removing the following `WixVariable` tag
-->
<WixVariable Id='WixUILicenseRtf' Value='wix\License.rtf'/>


<!--
Uncomment the next `WixVaraible` tag to customize the installer's
Graphical User Interface (GUI) and add a custom banner image across
the top of each screen. See the WiX Toolset documentation for details
about customization.
The banner BMP dimensions are 493 x 58 pixels.
-->
<WixVariable Id='WixUIBannerBmp' Value='src\assets\msi-banner.bmp'/>


<!--
Uncomment the next `WixVariable` tag to customize the installer's
Graphical User Interface (GUI) and add a custom image to the first
dialog, or screen. See the WiX Toolset documentation for details about
customization.
The dialog BMP dimensions are 493 x 312 pixels.
-->
<WixVariable Id='WixUIDialogBmp' Value='src\assets\msi.bmp'/>

<CustomAction Id="EXECUTE_AFTER_FINALIZE" Execute="immediate" Impersonate="yes" Return="asyncNoWait" FileKey="exe0" ExeCommand="" />

<InstallExecuteSequence>
<Custom Action="EXECUTE_AFTER_FINALIZE" After="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>

</Product>

</Wix>

0 comments on commit 54e679c

Please sign in to comment.