diff --git a/.changes/drop-nsis-applicationid.md b/.changes/drop-nsis-applicationid.md new file mode 100644 index 000000000..9f1eaa08d --- /dev/null +++ b/.changes/drop-nsis-applicationid.md @@ -0,0 +1,5 @@ +--- +'tauri-bundler': 'patch:enhance' +--- + +Use nsis's built-in com plugin instead of ApplicationID plugin, this reduces the installer size by 150-200 KB, and also fixes pinned shortcut not getting cleaned up on uninstall diff --git a/tooling/bundler/src/bundle/windows/nsis.rs b/tooling/bundler/src/bundle/windows/nsis.rs index e1aedb0cf..a550106f8 100644 --- a/tooling/bundler/src/bundle/windows/nsis.rs +++ b/tooling/bundler/src/bundle/windows/nsis.rs @@ -8,9 +8,8 @@ use crate::{ bundle::{ common::CommandExt, windows::util::{ - download, download_and_verify, download_webview2_bootstrapper, - download_webview2_offline_installer, extract_zip, verify_file_hash, HashAlgorithm, - NSIS_OUTPUT_FOLDER_NAME, NSIS_UPDATER_OUTPUT_FOLDER_NAME, + download_and_verify, download_webview2_bootstrapper, download_webview2_offline_installer, + verify_file_hash, HashAlgorithm, NSIS_OUTPUT_FOLDER_NAME, NSIS_UPDATER_OUTPUT_FOLDER_NAME, }, }, Settings, @@ -23,7 +22,7 @@ use tauri_utils::config::{NSISInstallerMode, NsisCompression, WebviewInstallMode use std::{ collections::{BTreeMap, HashMap}, - fs::{copy, create_dir_all, remove_dir_all, rename, write}, + fs::{create_dir_all, remove_dir_all, rename, write}, path::{Path, PathBuf}, process::Command, }; @@ -34,7 +33,6 @@ const NSIS_URL: &str = "https://github.com/tauri-apps/binary-releases/releases/download/nsis-3/nsis-3.zip"; #[cfg(target_os = "windows")] const NSIS_SHA1: &str = "057e83c7d82462ec394af76c87d06733605543d4"; -const NSIS_APPLICATIONID_URL: &str = "https://github.com/tauri-apps/binary-releases/releases/download/nsis-plugins-v0/NSIS-ApplicationID.zip"; const NSIS_TAURI_UTILS_URL: &str = "https://github.com/tauri-apps/nsis-tauri-utils/releases/download/nsis_tauri_utils-v0.2.2/nsis_tauri_utils.dll"; const NSIS_TAURI_UTILS_SHA1: &str = "16DF1D1A5B4D5DF3859447279C55BE36D4109DFB"; @@ -45,7 +43,6 @@ const NSIS_REQUIRED_FILES: &[&str] = &[ "Bin/makensis.exe", "Stubs/lzma-x86-unicode", "Stubs/lzma_solid-x86-unicode", - "Plugins/x86-unicode/ApplicationID.dll", "Plugins/x86-unicode/nsis_tauri_utils.dll", "Include/MUI2.nsh", "Include/FileFunc.nsh", @@ -54,10 +51,7 @@ const NSIS_REQUIRED_FILES: &[&str] = &[ "Include/WinMessages.nsh", ]; #[cfg(not(target_os = "windows"))] -const NSIS_REQUIRED_FILES: &[&str] = &[ - "Plugins/x86-unicode/ApplicationID.dll", - "Plugins/x86-unicode/nsis_tauri_utils.dll", -]; +const NSIS_REQUIRED_FILES: &[&str] = &["Plugins/x86-unicode/nsis_tauri_utils.dll"]; const NSIS_REQUIRED_FILES_HASH: &[(&str, &str, &str, HashAlgorithm)] = &[( "Plugins/x86-unicode/nsis_tauri_utils.dll", @@ -109,25 +103,12 @@ fn get_and_extract_nsis(nsis_toolset_path: &Path, _tauri_tools_path: &Path) -> c { let data = download_and_verify(NSIS_URL, NSIS_SHA1, HashAlgorithm::Sha1)?; log::info!("extracting NSIS"); - extract_zip(&data, _tauri_tools_path)?; + crate::bundle::windows::util::extract_zip(&data, _tauri_tools_path)?; rename(_tauri_tools_path.join("nsis-3.08"), nsis_toolset_path)?; } let nsis_plugins = nsis_toolset_path.join("Plugins"); - let data = download(NSIS_APPLICATIONID_URL)?; - log::info!("extracting NSIS ApplicationID plugin"); - extract_zip(&data, &nsis_plugins)?; - - create_dir_all(nsis_plugins.join("x86-unicode"))?; - - copy( - nsis_plugins - .join("ReleaseUnicode") - .join("ApplicationID.dll"), - nsis_plugins.join("x86-unicode").join("ApplicationID.dll"), - )?; - let data = download_and_verify( NSIS_TAURI_UTILS_URL, NSIS_TAURI_UTILS_SHA1, diff --git a/tooling/bundler/src/bundle/windows/templates/installer.nsi b/tooling/bundler/src/bundle/windows/templates/installer.nsi index de6357f34..49f9cd93e 100644 --- a/tooling/bundler/src/bundle/windows/templates/installer.nsi +++ b/tooling/bundler/src/bundle/windows/templates/installer.nsi @@ -13,6 +13,8 @@ ManifestDPIAware true !include WordFunc.nsh !include "FileAssociation.nsh" !include "StrFunc.nsh" +!include "Win\COM.nsh" +!include "Win\Propkey.nsh" ${StrCase} ${StrLoc} @@ -644,6 +646,35 @@ Function un.onInit !insertmacro MUI_UNGETLANGUAGE FunctionEnd +!macro DeleteAppUserModelId + !insertmacro ComHlpr_CreateInProcInstance ${CLSID_DestinationList} ${IID_ICustomDestinationList} r1 "" + ${If} $1 P<> 0 + ${ICustomDestinationList::DeleteList} $1 '("${BUNDLEID}")' + ${IUnknown::Release} $1 "" + ${EndIf} + !insertmacro ComHlpr_CreateInProcInstance ${CLSID_ApplicationDestinations} ${IID_IApplicationDestinations} r1 "" + ${If} $1 P<> 0 + ${IApplicationDestinations::SetAppID} $1 '("${BUNDLEID}")i.r0' + ${If} $0 >= 0 + ${IApplicationDestinations::RemoveAllDestinations} $1 '' + ${EndIf} + ${IUnknown::Release} $1 "" + ${EndIf} +!macroend + +; From https://stackoverflow.com/a/42816728/16993372 +!macro UnpinShortcut shortcut + !insertmacro ComHlpr_CreateInProcInstance ${CLSID_StartMenuPin} ${IID_IStartMenuPinnedList} r0 "" + ${If} $0 P<> 0 + System::Call 'SHELL32::SHCreateItemFromParsingName(ws, p0, g "${IID_IShellItem}", *p0r1)' "${shortcut}" + ${If} $1 P<> 0 + ${IStartMenuPinnedList::RemoveFromList} $0 '(r1)' + ${IUnknown::Release} $1 "" + ${EndIf} + ${IUnknown::Release} $0 "" + ${EndIf} +!macroend + Section Uninstall !insertmacro CheckIfAppIsRunning @@ -685,6 +716,10 @@ Section Uninstall {{/each}} RMDir "$INSTDIR" + !insertmacro DeleteAppUserModelId + !insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk" + !insertmacro UnpinShortcut "$DESKTOP\${MAINBINARYNAME}.lnk" + ; Remove start menu shortcut !insertmacro MUI_STARTMENU_GETFOLDER Application $AppStartMenuFolder Delete "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk" @@ -726,13 +761,39 @@ Function SkipIfPassive ${IfThen} $PassiveMode == 1 ${|} Abort ${|} FunctionEnd +!macro SetLnkAppUserModelId shortcut + !insertmacro ComHlpr_CreateInProcInstance ${CLSID_ShellLink} ${IID_IShellLink} r0 "" + ${If} $0 P<> 0 + ${IUnknown::QueryInterface} $0 '("${IID_IPersistFile}",.r1)' + ${If} $1 P<> 0 + ${IPersistFile::Load} $1 '("${shortcut}", ${STGM_READWRITE})' + ${IUnknown::QueryInterface} $0 '("${IID_IPropertyStore}",.r2)' + ${If} $2 P<> 0 + System::Call 'Oleaut32::SysAllocString(w "${BUNDLEID}") i.r3' + System::Call '*${SYSSTRUCT_PROPERTYKEY}(${PKEY_AppUserModel_ID})p.r4' + System::Call '*${SYSSTRUCT_PROPVARIANT}(${VT_BSTR},,&i4 $3)p.r5' + ${IPropertyStore::SetValue} $2 '($4,$5)' + + System::Call 'Oleaut32::SysFreeString($3)' + System::Free $4 + System::Free $5 + ${IPropertyStore::Commit} $2 "" + ${IUnknown::Release} $2 "" + ${IPersistFile::Save} $1 '("${shortcut}",1)' + ${EndIf} + ${IUnknown::Release} $1 "" + ${EndIf} + ${IUnknown::Release} $0 "" + ${EndIf} +!macroend + Function CreateDesktopShortcut CreateShortcut "$DESKTOP\${MAINBINARYNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" - ApplicationID::Set "$DESKTOP\${MAINBINARYNAME}.lnk" "${BUNDLEID}" + !insertmacro SetLnkAppUserModelId "$DESKTOP\${MAINBINARYNAME}.lnk" FunctionEnd Function CreateStartMenuShortcut CreateDirectory "$SMPROGRAMS\$AppStartMenuFolder" CreateShortcut "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" - ApplicationID::Set "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk" "${BUNDLEID}" + !insertmacro SetLnkAppUserModelId "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk" FunctionEnd diff --git a/tooling/bundler/src/bundle/windows/util.rs b/tooling/bundler/src/bundle/windows/util.rs index 099819a64..80c3f64ba 100644 --- a/tooling/bundler/src/bundle/windows/util.rs +++ b/tooling/bundler/src/bundle/windows/util.rs @@ -132,6 +132,7 @@ pub fn verify_file_hash>( } /// Extracts the zips from memory into a usable path. +#[allow(dead_code)] pub fn extract_zip(data: &[u8], path: &Path) -> crate::Result<()> { let cursor = Cursor::new(data);