installer.nsi 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  1. ; This file is copied from https://github.com/tauri-apps/tauri/blob/tauri-v1.5/tooling/bundler/src/bundle/windows/templates/installer.nsi
  2. ; and edit to fit the needs of the project. the latest tauri 2.x has a different base nsi script.
  3. Unicode true
  4. ; Set the compression algorithm. Default is LZMA.
  5. !if "{{compression}}" == ""
  6. SetCompressor /SOLID lzma
  7. !else
  8. SetCompressor /SOLID "{{compression}}"
  9. !endif
  10. !include MUI2.nsh
  11. !include FileFunc.nsh
  12. !include x64.nsh
  13. !include WordFunc.nsh
  14. !include "StrFunc.nsh"
  15. !include "Win\COM.nsh"
  16. !include "Win\Propkey.nsh"
  17. !addplugindir "$%AppData%\Local\NSIS\"
  18. ${StrCase}
  19. ${StrLoc}
  20. !define MANUFACTURER "{{manufacturer}}"
  21. !define PRODUCTNAME "{{product_name}}"
  22. !define VERSION "{{version}}"
  23. !define VERSIONWITHBUILD "{{version_with_build}}"
  24. !define SHORTDESCRIPTION "{{short_description}}"
  25. !define INSTALLMODE "{{install_mode}}"
  26. !define LICENSE "{{license}}"
  27. !define INSTALLERICON "{{installer_icon}}"
  28. !define SIDEBARIMAGE "{{sidebar_image}}"
  29. !define HEADERIMAGE "{{header_image}}"
  30. !define MAINBINARYNAME "{{main_binary_name}}"
  31. !define MAINBINARYSRCPATH "{{main_binary_path}}"
  32. !define BUNDLEID "{{bundle_id}}"
  33. !define COPYRIGHT "{{copyright}}"
  34. !define OUTFILE "{{out_file}}"
  35. !define ARCH "{{arch}}"
  36. !define PLUGINSPATH "{{additional_plugins_path}}"
  37. !define ALLOWDOWNGRADES "{{allow_downgrades}}"
  38. !define DISPLAYLANGUAGESELECTOR "{{display_language_selector}}"
  39. !define INSTALLWEBVIEW2MODE "{{install_webview2_mode}}"
  40. !define WEBVIEW2INSTALLERARGS "{{webview2_installer_args}}"
  41. !define WEBVIEW2BOOTSTRAPPERPATH "{{webview2_bootstrapper_path}}"
  42. !define WEBVIEW2INSTALLERPATH "{{webview2_installer_path}}"
  43. !define UNINSTKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCTNAME}"
  44. !define MANUPRODUCTKEY "Software\${MANUFACTURER}\${PRODUCTNAME}"
  45. !define UNINSTALLERSIGNCOMMAND "{{uninstaller_sign_cmd}}"
  46. !define ESTIMATEDSIZE "{{estimated_size}}"
  47. Name "${PRODUCTNAME}"
  48. BrandingText "${COPYRIGHT}"
  49. OutFile "${OUTFILE}"
  50. VIProductVersion "${VERSIONWITHBUILD}"
  51. VIAddVersionKey "ProductName" "${PRODUCTNAME}"
  52. VIAddVersionKey "FileDescription" "${SHORTDESCRIPTION}"
  53. VIAddVersionKey "LegalCopyright" "${COPYRIGHT}"
  54. VIAddVersionKey "FileVersion" "${VERSION}"
  55. VIAddVersionKey "ProductVersion" "${VERSION}"
  56. ; Plugins path, currently exists for linux only
  57. !if "${PLUGINSPATH}" != ""
  58. !addplugindir "${PLUGINSPATH}"
  59. !endif
  60. !if "${UNINSTALLERSIGNCOMMAND}" != ""
  61. !uninstfinalize '${UNINSTALLERSIGNCOMMAND}'
  62. !endif
  63. ; Handle install mode, `perUser`, `perMachine` or `both`
  64. !if "${INSTALLMODE}" == "perMachine"
  65. RequestExecutionLevel highest
  66. !endif
  67. !if "${INSTALLMODE}" == "currentUser"
  68. RequestExecutionLevel user
  69. !endif
  70. !if "${INSTALLMODE}" == "both"
  71. !define MULTIUSER_MUI
  72. !define MULTIUSER_INSTALLMODE_INSTDIR "${PRODUCTNAME}"
  73. !define MULTIUSER_INSTALLMODE_COMMANDLINE
  74. !if "${ARCH}" == "x64"
  75. !define MULTIUSER_USE_PROGRAMFILES64
  76. !else if "${ARCH}" == "arm64"
  77. !define MULTIUSER_USE_PROGRAMFILES64
  78. !endif
  79. !define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY "${UNINSTKEY}"
  80. !define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME "CurrentUser"
  81. !define MULTIUSER_INSTALLMODEPAGE_SHOWUSERNAME
  82. !define MULTIUSER_INSTALLMODE_FUNCTION RestorePreviousInstallLocation
  83. !define MULTIUSER_EXECUTIONLEVEL Highest
  84. !include MultiUser.nsh
  85. !endif
  86. ; installer icon
  87. !if "${INSTALLERICON}" != ""
  88. !define MUI_ICON "${INSTALLERICON}"
  89. !endif
  90. ; installer sidebar image
  91. !if "${SIDEBARIMAGE}" != ""
  92. !define MUI_WELCOMEFINISHPAGE_BITMAP "${SIDEBARIMAGE}"
  93. !endif
  94. ; installer header image
  95. !if "${HEADERIMAGE}" != ""
  96. !define MUI_HEADERIMAGE
  97. !define MUI_HEADERIMAGE_BITMAP "${HEADERIMAGE}"
  98. !endif
  99. ; Define registry key to store installer language
  100. !define MUI_LANGDLL_REGISTRY_ROOT "HKCU"
  101. !define MUI_LANGDLL_REGISTRY_KEY "${MANUPRODUCTKEY}"
  102. !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language"
  103. ; Installer pages, must be ordered as they appear
  104. ; 1. Welcome Page
  105. !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive
  106. !insertmacro MUI_PAGE_WELCOME
  107. ; 2. License Page (if defined)
  108. !if "${LICENSE}" != ""
  109. !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive
  110. !insertmacro MUI_PAGE_LICENSE "${LICENSE}"
  111. !endif
  112. ; 3. Install mode (if it is set to `both`)
  113. !if "${INSTALLMODE}" == "both"
  114. !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive
  115. !insertmacro MULTIUSER_PAGE_INSTALLMODE
  116. !endif
  117. ; 4. Custom page to ask user if he wants to reinstall/uninstall
  118. ; only if a previous installtion was detected
  119. Var ReinstallPageCheck
  120. Page custom PageReinstall PageLeaveReinstall
  121. Function PageReinstall
  122. ; Uninstall previous WiX installation if exists.
  123. ;
  124. ; A WiX installer stores the isntallation info in registry
  125. ; using a UUID and so we have to loop through all keys under
  126. ; `HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall`
  127. ; and check if `DisplayName` and `Publisher` keys match ${PRODUCTNAME} and ${MANUFACTURER}
  128. ;
  129. ; This has a potentional issue that there maybe another installation that matches
  130. ; our ${PRODUCTNAME} and ${MANUFACTURER} but wasn't installed by our WiX installer,
  131. ; however, this should be fine since the user will have to confirm the uninstallation
  132. ; and they can chose to abort it if doesn't make sense.
  133. StrCpy $0 0
  134. wix_loop:
  135. EnumRegKey $1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" $0
  136. StrCmp $1 "" wix_done ; Exit loop if there is no more keys to loop on
  137. IntOp $0 $0 + 1
  138. ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$1" "DisplayName"
  139. ReadRegStr $R1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$1" "Publisher"
  140. StrCmp "$R0$R1" "${PRODUCTNAME}${MANUFACTURER}" 0 wix_loop
  141. ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$1" "UninstallString"
  142. ${StrCase} $R1 $R0 "L"
  143. ${StrLoc} $R0 $R1 "msiexec" ">"
  144. StrCmp $R0 0 0 wix_done
  145. StrCpy $R7 "wix"
  146. StrCpy $R6 "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$1"
  147. Goto compare_version
  148. wix_done:
  149. ; Check if there is an existing installation, if not, abort the reinstall page
  150. ReadRegStr $R0 SHCTX "${UNINSTKEY}" ""
  151. ReadRegStr $R1 SHCTX "${UNINSTKEY}" "UninstallString"
  152. ${IfThen} "$R0$R1" == "" ${|} Abort ${|}
  153. ; Compare this installar version with the existing installation
  154. ; and modify the messages presented to the user accordingly
  155. compare_version:
  156. StrCpy $R4 "$(older)"
  157. ${If} $R7 == "wix"
  158. ReadRegStr $R0 HKLM "$R6" "DisplayVersion"
  159. ${Else}
  160. ReadRegStr $R0 SHCTX "${UNINSTKEY}" "DisplayVersion"
  161. ${EndIf}
  162. ${IfThen} $R0 == "" ${|} StrCpy $R4 "$(unknown)" ${|}
  163. nsis_tauri_utils::SemverCompare "${VERSION}" $R0
  164. Pop $R0
  165. ; Reinstalling the same version
  166. ${If} $R0 == 0
  167. StrCpy $R1 "$(alreadyInstalledLong)"
  168. StrCpy $R2 "$(addOrReinstall)"
  169. StrCpy $R3 "$(uninstallApp)"
  170. !insertmacro MUI_HEADER_TEXT "$(alreadyInstalled)" "$(chooseMaintenanceOption)"
  171. StrCpy $R5 "2"
  172. ; Upgrading
  173. ${ElseIf} $R0 == 1
  174. StrCpy $R1 "$(olderOrUnknownVersionInstalled)"
  175. StrCpy $R2 "$(uninstallBeforeInstalling)"
  176. StrCpy $R3 "$(dontUninstall)"
  177. !insertmacro MUI_HEADER_TEXT "$(alreadyInstalled)" "$(choowHowToInstall)"
  178. StrCpy $R5 "1"
  179. ; Downgrading
  180. ${ElseIf} $R0 == -1
  181. StrCpy $R1 "$(newerVersionInstalled)"
  182. StrCpy $R2 "$(uninstallBeforeInstalling)"
  183. !if "${ALLOWDOWNGRADES}" == "true"
  184. StrCpy $R3 "$(dontUninstall)"
  185. !else
  186. StrCpy $R3 "$(dontUninstallDowngrade)"
  187. !endif
  188. !insertmacro MUI_HEADER_TEXT "$(alreadyInstalled)" "$(choowHowToInstall)"
  189. StrCpy $R5 "1"
  190. ${Else}
  191. Abort
  192. ${EndIf}
  193. Call SkipIfPassive
  194. nsDialogs::Create 1018
  195. Pop $R4
  196. ${IfThen} $(^RTL) == 1 ${|} nsDialogs::SetRTL $(^RTL) ${|}
  197. ${NSD_CreateLabel} 0 0 100% 24u $R1
  198. Pop $R1
  199. ${NSD_CreateRadioButton} 30u 50u -30u 8u $R2
  200. Pop $R2
  201. ${NSD_OnClick} $R2 PageReinstallUpdateSelection
  202. ${NSD_CreateRadioButton} 30u 70u -30u 8u $R3
  203. Pop $R3
  204. ; disable this radio button if downgrading and downgrades are disabled
  205. !if "${ALLOWDOWNGRADES}" == "false"
  206. ${IfThen} $R0 == -1 ${|} EnableWindow $R3 0 ${|}
  207. !endif
  208. ${NSD_OnClick} $R3 PageReinstallUpdateSelection
  209. ; Check the first radio button if this the first time
  210. ; we enter this page or if the second button wasn't
  211. ; selected the last time we were on this page
  212. ${If} $ReinstallPageCheck != 2
  213. SendMessage $R2 ${BM_SETCHECK} ${BST_CHECKED} 0
  214. ${Else}
  215. SendMessage $R3 ${BM_SETCHECK} ${BST_CHECKED} 0
  216. ${EndIf}
  217. ${NSD_SetFocus} $R2
  218. nsDialogs::Show
  219. FunctionEnd
  220. Function PageReinstallUpdateSelection
  221. ${NSD_GetState} $R2 $R1
  222. ${If} $R1 == ${BST_CHECKED}
  223. StrCpy $ReinstallPageCheck 1
  224. ${Else}
  225. StrCpy $ReinstallPageCheck 2
  226. ${EndIf}
  227. FunctionEnd
  228. Function PageLeaveReinstall
  229. ${NSD_GetState} $R2 $R1
  230. ; $R5 holds whether we are reinstalling the same version or not
  231. ; $R5 == "1" -> different versions
  232. ; $R5 == "2" -> same version
  233. ;
  234. ; $R1 holds the radio buttons state. its meaning is dependant on the context
  235. StrCmp $R5 "1" 0 +2 ; Existing install is not the same version?
  236. StrCmp $R1 "1" reinst_uninstall reinst_done ; $R1 == "1", then user chose to uninstall existing version, otherwise skip uninstalling
  237. StrCmp $R1 "1" reinst_done ; Same version? skip uninstalling
  238. reinst_uninstall:
  239. HideWindow
  240. ClearErrors
  241. ${If} $R7 == "wix"
  242. ReadRegStr $R1 HKLM "$R6" "UninstallString"
  243. ExecWait '$R1' $0
  244. ${Else}
  245. ReadRegStr $4 SHCTX "${MANUPRODUCTKEY}" ""
  246. ReadRegStr $R1 SHCTX "${UNINSTKEY}" "UninstallString"
  247. ExecWait '$R1 /P _?=$4' $0
  248. ${EndIf}
  249. BringToFront
  250. ${IfThen} ${Errors} ${|} StrCpy $0 2 ${|} ; ExecWait failed, set fake exit code
  251. ${If} $0 <> 0
  252. ${OrIf} ${FileExists} "$INSTDIR\${MAINBINARYNAME}.exe"
  253. ${If} $0 = 1 ; User aborted uninstaller?
  254. StrCmp $R5 "2" 0 +2 ; Is the existing install the same version?
  255. Quit ; ...yes, already installed, we are done
  256. Abort
  257. ${EndIf}
  258. MessageBox MB_ICONEXCLAMATION "$(unableToUninstall)"
  259. Abort
  260. ${Else}
  261. StrCpy $0 $R1 1
  262. ${IfThen} $0 == '"' ${|} StrCpy $R1 $R1 -1 1 ${|} ; Strip quotes from UninstallString
  263. Delete $R1
  264. RMDir $INSTDIR
  265. ${EndIf}
  266. reinst_done:
  267. FunctionEnd
  268. ; 5. Choose install directoy page
  269. !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive
  270. !insertmacro MUI_PAGE_DIRECTORY
  271. ; 6. Start menu shortcut page
  272. !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive
  273. Var AppStartMenuFolder
  274. !insertmacro MUI_PAGE_STARTMENU Application $AppStartMenuFolder
  275. ; 7. Installation page
  276. !insertmacro MUI_PAGE_INSTFILES
  277. ; 8. Finish page
  278. ;
  279. ; Don't auto jump to finish page after installation page,
  280. ; because the installation page has useful info that can be used debug any issues with the installer.
  281. !define MUI_FINISHPAGE_NOAUTOCLOSE
  282. ; Use show readme button in the finish page as a button create a desktop shortcut
  283. !define MUI_FINISHPAGE_SHOWREADME
  284. !define MUI_FINISHPAGE_SHOWREADME_TEXT "$(createDesktop)"
  285. !define MUI_FINISHPAGE_SHOWREADME_FUNCTION CreateDesktopShortcut
  286. ; Show run app after installation.
  287. !define MUI_FINISHPAGE_RUN
  288. !define MUI_FINISHPAGE_RUN_FUNCTION RunMainBinary
  289. !define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive
  290. !insertmacro MUI_PAGE_FINISH
  291. Function RunMainBinary
  292. nsis_tauri_utils::RunAsUser "$INSTDIR\${MAINBINARYNAME}.exe" ""
  293. FunctionEnd
  294. ; Uninstaller Pages
  295. ; 1. Confirm uninstall page
  296. Var DeleteAppDataCheckbox
  297. Var DeleteAppDataCheckboxState
  298. !define /ifndef WS_EX_LAYOUTRTL 0x00400000
  299. !define MUI_PAGE_CUSTOMFUNCTION_SHOW un.ConfirmShow
  300. Function un.ConfirmShow
  301. FindWindow $1 "#32770" "" $HWNDPARENT ; Find inner dialog
  302. ${If} $(^RTL) == 1
  303. System::Call 'USER32::CreateWindowEx(i${__NSD_CheckBox_EXSTYLE}|${WS_EX_LAYOUTRTL},t"${__NSD_CheckBox_CLASS}",t "$(deleteAppData)",i${__NSD_CheckBox_STYLE},i 50,i 100,i 400, i 25,i$1,i0,i0,i0)i.s'
  304. ${Else}
  305. System::Call 'USER32::CreateWindowEx(i${__NSD_CheckBox_EXSTYLE},t"${__NSD_CheckBox_CLASS}",t "$(deleteAppData)",i${__NSD_CheckBox_STYLE},i 0,i 100,i 400, i 25,i$1,i0,i0,i0)i.s'
  306. ${EndIf}
  307. Pop $DeleteAppDataCheckbox
  308. SendMessage $HWNDPARENT ${WM_GETFONT} 0 0 $1
  309. SendMessage $DeleteAppDataCheckbox ${WM_SETFONT} $1 1
  310. FunctionEnd
  311. !define MUI_PAGE_CUSTOMFUNCTION_LEAVE un.ConfirmLeave
  312. Function un.ConfirmLeave
  313. SendMessage $DeleteAppDataCheckbox ${BM_GETCHECK} 0 0 $DeleteAppDataCheckboxState
  314. FunctionEnd
  315. !insertmacro MUI_UNPAGE_CONFIRM
  316. ; 2. Uninstalling Page
  317. !insertmacro MUI_UNPAGE_INSTFILES
  318. ;Languages
  319. {{#each languages}}
  320. !insertmacro MUI_LANGUAGE "{{this}}"
  321. {{/each}}
  322. !insertmacro MUI_RESERVEFILE_LANGDLL
  323. {{#each language_files}}
  324. !include "{{this}}"
  325. {{/each}}
  326. !macro SetContext
  327. !if "${INSTALLMODE}" == "currentUser"
  328. SetShellVarContext current
  329. !else if "${INSTALLMODE}" == "perMachine"
  330. SetShellVarContext all
  331. !endif
  332. ${If} ${RunningX64}
  333. !if "${ARCH}" == "x64"
  334. SetRegView 64
  335. !else if "${ARCH}" == "arm64"
  336. SetRegView 64
  337. !else
  338. SetRegView 32
  339. !endif
  340. ${EndIf}
  341. !macroend
  342. Var PassiveMode
  343. Function .onInit
  344. ${GetOptions} $CMDLINE "/P" $PassiveMode
  345. IfErrors +2 0
  346. StrCpy $PassiveMode 1
  347. !if "${DISPLAYLANGUAGESELECTOR}" == "true"
  348. !insertmacro MUI_LANGDLL_DISPLAY
  349. !endif
  350. !insertmacro SetContext
  351. ${If} $INSTDIR == ""
  352. ; Set default install location
  353. !if "${INSTALLMODE}" == "perMachine"
  354. ${If} ${RunningX64}
  355. !if "${ARCH}" == "x64"
  356. StrCpy $INSTDIR "$PROGRAMFILES64\${PRODUCTNAME}"
  357. !else if "${ARCH}" == "arm64"
  358. StrCpy $INSTDIR "$PROGRAMFILES64\${PRODUCTNAME}"
  359. !else
  360. StrCpy $INSTDIR "$PROGRAMFILES\${PRODUCTNAME}"
  361. !endif
  362. ${Else}
  363. StrCpy $INSTDIR "$PROGRAMFILES\${PRODUCTNAME}"
  364. ${EndIf}
  365. !else if "${INSTALLMODE}" == "currentUser"
  366. StrCpy $INSTDIR "$LOCALAPPDATA\${PRODUCTNAME}"
  367. !endif
  368. Call RestorePreviousInstallLocation
  369. ${EndIf}
  370. !if "${INSTALLMODE}" == "both"
  371. !insertmacro MULTIUSER_INIT
  372. !endif
  373. FunctionEnd
  374. !macro CheckAllVergeProcesses
  375. ; Check if clash-verge-service.exe is running
  376. !if "${INSTALLMODE}" == "currentUser"
  377. nsis_tauri_utils::FindProcessCurrentUser "clash-verge-service.exe"
  378. !else
  379. nsis_tauri_utils::FindProcess "clash-verge-service.exe"
  380. !endif
  381. Pop $R0
  382. ${If} $R0 = 0
  383. DetailPrint "Kill clash-verge-service.exe..."
  384. !if "${INSTALLMODE}" == "currentUser"
  385. nsis_tauri_utils::KillProcessCurrentUser "clash-verge-service.exe"
  386. !else
  387. nsis_tauri_utils::KillProcess "clash-verge-service.exe"
  388. !endif
  389. ${EndIf}
  390. ; Check if clash-meta-alpha.exe is running
  391. !if "${INSTALLMODE}" == "currentUser"
  392. nsis_tauri_utils::FindProcessCurrentUser "clash-meta-alpha.exe"
  393. !else
  394. nsis_tauri_utils::FindProcess "clash-meta-alpha.exe"
  395. !endif
  396. Pop $R0
  397. ${If} $R0 = 0
  398. DetailPrint "Kill clash-meta-alpha.exe..."
  399. !if "${INSTALLMODE}" == "currentUser"
  400. nsis_tauri_utils::KillProcessCurrentUser "clash-meta-alpha.exe"
  401. !else
  402. nsis_tauri_utils::KillProcess "clash-meta-alpha.exe"
  403. !endif
  404. ${EndIf}
  405. ; Check if clash-meta.exe is running
  406. !if "${INSTALLMODE}" == "currentUser"
  407. nsis_tauri_utils::FindProcessCurrentUser "clash-meta.exe"
  408. !else
  409. nsis_tauri_utils::FindProcess "clash-meta.exe"
  410. !endif
  411. Pop $R0
  412. ${If} $R0 = 0
  413. DetailPrint "Kill clash-meta.exe..."
  414. !if "${INSTALLMODE}" == "currentUser"
  415. nsis_tauri_utils::KillProcessCurrentUser "clash-meta.exe"
  416. !else
  417. nsis_tauri_utils::KillProcess "clash-meta.exe"
  418. !endif
  419. ${EndIf}
  420. !macroend
  421. !macro StartVergeService
  422. ; Check if the service exists
  423. SimpleSC::ExistsService "clash_verge_service"
  424. Pop $0 ; 0:service exists;other: service not exists
  425. ; Service exists
  426. ${If} $0 == 0
  427. Push $0
  428. ; Check if the service is running
  429. SimpleSC::ServiceIsRunning "clash_verge_service"
  430. Pop $0 ; returns an errorcode (<>0) otherwise success (0)
  431. Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)
  432. ${If} $0 == 0
  433. Push $0
  434. ${If} $1 == 0
  435. DetailPrint "Restart Clash Verge Service..."
  436. SimpleSC::StartService "clash_verge_service" "" 30
  437. ${EndIf}
  438. ${ElseIf} $0 != 0
  439. Push $0
  440. SimpleSC::GetErrorMessage
  441. Pop $0
  442. MessageBox MB_OK|MB_ICONSTOP "Check Service Status Error ($0)"
  443. ${EndIf}
  444. ${EndIf}
  445. !macroend
  446. !macro RemoveVergeService
  447. ; Check if the service exists
  448. SimpleSC::ExistsService "clash_verge_service"
  449. Pop $0 ; 0:service exists;other: service not exists
  450. ; Service exists
  451. ${If} $0 == 0
  452. Push $0
  453. ; Check if the service is running
  454. SimpleSC::ServiceIsRunning "clash_verge_service"
  455. Pop $0 ; returns an errorcode (<>0) otherwise success (0)
  456. Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)
  457. ${If} $0 == 0
  458. Push $0
  459. ${If} $1 == 1
  460. DetailPrint "Stop Clash Verge Service..."
  461. SimpleSC::StopService "clash_verge_service" 1 30
  462. Pop $0 ; returns an errorcode (<>0) otherwise success (0)
  463. ${If} $0 == 0
  464. DetailPrint "Removing Clash Verge Service..."
  465. SimpleSC::RemoveService "clash_verge_service"
  466. ${ElseIf} $0 != 0
  467. Push $0
  468. SimpleSC::GetErrorMessage
  469. Pop $0
  470. MessageBox MB_OK|MB_ICONSTOP "Clash Verge Service Stop Error ($0)"
  471. ${EndIf}
  472. ${ElseIf} $1 == 0
  473. DetailPrint "Removing Clash Verge Service..."
  474. SimpleSC::RemoveService "clash_verge_service"
  475. ${EndIf}
  476. ${ElseIf} $0 != 0
  477. Push $0
  478. SimpleSC::GetErrorMessage
  479. Pop $0
  480. MessageBox MB_OK|MB_ICONSTOP "Check Service Status Error ($0)"
  481. ${EndIf}
  482. ${EndIf}
  483. !macroend
  484. Section EarlyChecks
  485. ; Abort silent installer if downgrades is disabled
  486. !if "${ALLOWDOWNGRADES}" == "false"
  487. IfSilent 0 silent_downgrades_done
  488. ; If downgrading
  489. ${If} $R0 == -1
  490. System::Call 'kernel32::AttachConsole(i -1)i.r0'
  491. ${If} $0 != 0
  492. System::Call 'kernel32::GetStdHandle(i -11)i.r0'
  493. System::call 'kernel32::SetConsoleTextAttribute(i r0, i 0x0004)' ; set red color
  494. FileWrite $0 "$(silentDowngrades)"
  495. ${EndIf}
  496. Abort
  497. ${EndIf}
  498. silent_downgrades_done:
  499. !endif
  500. SectionEnd
  501. Section WebView2
  502. ; Check if Webview2 is already installed and skip this section
  503. ${If} ${RunningX64}
  504. ReadRegStr $4 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
  505. ${Else}
  506. ReadRegStr $4 HKLM "SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
  507. ${EndIf}
  508. ReadRegStr $5 HKCU "SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
  509. StrCmp $4 "" 0 webview2_done
  510. StrCmp $5 "" 0 webview2_done
  511. ; Webview2 install modes
  512. !if "${INSTALLWEBVIEW2MODE}" == "downloadBootstrapper"
  513. Delete "$TEMP\MicrosoftEdgeWebview2Setup.exe"
  514. DetailPrint "$(webview2Downloading)"
  515. NSISdl::download "https://go.microsoft.com/fwlink/p/?LinkId=2124703" "$TEMP\MicrosoftEdgeWebview2Setup.exe"
  516. Pop $0
  517. ${If} $0 == 0
  518. DetailPrint "$(webview2DownloadSuccess)"
  519. ${Else}
  520. DetailPrint "$(webview2DownloadError)"
  521. Abort "$(webview2AbortError)"
  522. ${EndIf}
  523. StrCpy $6 "$TEMP\MicrosoftEdgeWebview2Setup.exe"
  524. Goto install_webview2
  525. !endif
  526. !if "${INSTALLWEBVIEW2MODE}" == "embedBootstrapper"
  527. Delete "$TEMP\MicrosoftEdgeWebview2Setup.exe"
  528. File "/oname=$TEMP\MicrosoftEdgeWebview2Setup.exe" "${WEBVIEW2BOOTSTRAPPERPATH}"
  529. DetailPrint "$(installingWebview2)"
  530. StrCpy $6 "$TEMP\MicrosoftEdgeWebview2Setup.exe"
  531. Goto install_webview2
  532. !endif
  533. !if "${INSTALLWEBVIEW2MODE}" == "offlineInstaller"
  534. Delete "$TEMP\MicrosoftEdgeWebView2RuntimeInstaller.exe"
  535. File "/oname=$TEMP\MicrosoftEdgeWebView2RuntimeInstaller.exe" "${WEBVIEW2INSTALLERPATH}"
  536. DetailPrint "$(installingWebview2)"
  537. StrCpy $6 "$TEMP\MicrosoftEdgeWebView2RuntimeInstaller.exe"
  538. Goto install_webview2
  539. !endif
  540. Goto webview2_done
  541. install_webview2:
  542. DetailPrint "$(installingWebview2)"
  543. ; $6 holds the path to the webview2 installer
  544. ExecWait "$6 ${WEBVIEW2INSTALLERARGS} /install" $1
  545. ${If} $1 == 0
  546. DetailPrint "$(webview2InstallSuccess)"
  547. ${Else}
  548. DetailPrint "$(webview2InstallError)"
  549. Abort "$(webview2AbortError)"
  550. ${EndIf}
  551. webview2_done:
  552. SectionEnd
  553. !macro CheckIfAppIsRunning
  554. !if "${INSTALLMODE}" == "currentUser"
  555. nsis_tauri_utils::FindProcessCurrentUser "${MAINBINARYNAME}.exe"
  556. !else
  557. nsis_tauri_utils::FindProcess "${MAINBINARYNAME}.exe"
  558. !endif
  559. Pop $R0
  560. ${If} $R0 = 0
  561. IfSilent kill 0
  562. ${IfThen} $PassiveMode != 1 ${|} MessageBox MB_OKCANCEL "$(appRunningOkKill)" IDOK kill IDCANCEL cancel ${|}
  563. kill:
  564. !if "${INSTALLMODE}" == "currentUser"
  565. nsis_tauri_utils::KillProcessCurrentUser "${MAINBINARYNAME}.exe"
  566. !else
  567. nsis_tauri_utils::KillProcess "${MAINBINARYNAME}.exe"
  568. !endif
  569. Pop $R0
  570. Sleep 500
  571. ${If} $R0 = 0
  572. Goto app_check_done
  573. ${Else}
  574. IfSilent silent ui
  575. silent:
  576. System::Call 'kernel32::AttachConsole(i -1)i.r0'
  577. ${If} $0 != 0
  578. System::Call 'kernel32::GetStdHandle(i -11)i.r0'
  579. System::call 'kernel32::SetConsoleTextAttribute(i r0, i 0x0004)' ; set red color
  580. FileWrite $0 "$(appRunning)$\n"
  581. ${EndIf}
  582. Abort
  583. ui:
  584. Abort "$(failedToKillApp)"
  585. ${EndIf}
  586. cancel:
  587. Abort "$(appRunning)"
  588. ${EndIf}
  589. app_check_done:
  590. !macroend
  591. Section Install
  592. SetOutPath $INSTDIR
  593. !insertmacro CheckIfAppIsRunning
  594. !insertmacro CheckAllVergeProcesses
  595. ; Copy main executable
  596. File "${MAINBINARYSRCPATH}"
  597. ; Copy resources
  598. {{#each resources_dirs}}
  599. CreateDirectory "$INSTDIR\\{{this}}"
  600. {{/each}}
  601. {{#each resources}}
  602. File /a "/oname={{this.[1]}}" "{{@key}}"
  603. {{/each}}
  604. ; Copy external binaries
  605. {{#each binaries}}
  606. File /a "/oname={{this}}" "{{@key}}"
  607. {{/each}}
  608. !insertmacro StartVergeService
  609. ; Create uninstaller
  610. WriteUninstaller "$INSTDIR\uninstall.exe"
  611. ; Save $INSTDIR in registry for future installations
  612. WriteRegStr SHCTX "${MANUPRODUCTKEY}" "" $INSTDIR
  613. !if "${INSTALLMODE}" == "both"
  614. ; Save install mode to be selected by default for the next installation such as updating
  615. ; or when uninstalling
  616. WriteRegStr SHCTX "${UNINSTKEY}" $MultiUser.InstallMode 1
  617. !endif
  618. ; Registry information for add/remove programs
  619. WriteRegStr SHCTX "${UNINSTKEY}" "DisplayName" "${PRODUCTNAME}"
  620. WriteRegStr SHCTX "${UNINSTKEY}" "DisplayIcon" "$\"$INSTDIR\${MAINBINARYNAME}.exe$\""
  621. WriteRegStr SHCTX "${UNINSTKEY}" "DisplayVersion" "${VERSION}"
  622. WriteRegStr SHCTX "${UNINSTKEY}" "Publisher" "${MANUFACTURER}"
  623. WriteRegStr SHCTX "${UNINSTKEY}" "InstallLocation" "$\"$INSTDIR$\""
  624. WriteRegStr SHCTX "${UNINSTKEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
  625. WriteRegDWORD SHCTX "${UNINSTKEY}" "NoModify" "1"
  626. WriteRegDWORD SHCTX "${UNINSTKEY}" "NoRepair" "1"
  627. WriteRegDWORD SHCTX "${UNINSTKEY}" "EstimatedSize" "${ESTIMATEDSIZE}"
  628. ; Create start menu shortcut (GUI)
  629. !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
  630. Call CreateStartMenuShortcut
  631. !insertmacro MUI_STARTMENU_WRITE_END
  632. ; Create shortcuts for silent and passive installers, which
  633. ; can be disabled by passing `/NS` flag
  634. ; GUI installer has buttons for users to control creating them
  635. IfSilent check_ns_flag 0
  636. ${IfThen} $PassiveMode == 1 ${|} Goto check_ns_flag ${|}
  637. Goto shortcuts_done
  638. check_ns_flag:
  639. ${GetOptions} $CMDLINE "/NS" $R0
  640. IfErrors 0 shortcuts_done
  641. Call CreateDesktopShortcut
  642. Call CreateStartMenuShortcut
  643. shortcuts_done:
  644. ; Auto close this page for passive mode
  645. ${IfThen} $PassiveMode == 1 ${|} SetAutoClose true ${|}
  646. SectionEnd
  647. Function .onInstSuccess
  648. ; Check for `/R` flag only in silent and passive installers because
  649. ; GUI installer has a toggle for the user to (re)start the app
  650. IfSilent check_r_flag 0
  651. ${IfThen} $PassiveMode == 1 ${|} Goto check_r_flag ${|}
  652. Goto run_done
  653. check_r_flag:
  654. ${GetOptions} $CMDLINE "/R" $R0
  655. IfErrors run_done 0
  656. ${GetOptions} $CMDLINE "/ARGS" $R0
  657. nsis_tauri_utils::RunAsUser "$INSTDIR\${MAINBINARYNAME}.exe" "$R0"
  658. run_done:
  659. FunctionEnd
  660. Function un.onInit
  661. !insertmacro SetContext
  662. !if "${INSTALLMODE}" == "both"
  663. !insertmacro MULTIUSER_UNINIT
  664. !endif
  665. !insertmacro MUI_UNGETLANGUAGE
  666. FunctionEnd
  667. !macro DeleteAppUserModelId
  668. !insertmacro ComHlpr_CreateInProcInstance ${CLSID_DestinationList} ${IID_ICustomDestinationList} r1 ""
  669. ${If} $1 P<> 0
  670. ${ICustomDestinationList::DeleteList} $1 '("${BUNDLEID}")'
  671. ${IUnknown::Release} $1 ""
  672. ${EndIf}
  673. !insertmacro ComHlpr_CreateInProcInstance ${CLSID_ApplicationDestinations} ${IID_IApplicationDestinations} r1 ""
  674. ${If} $1 P<> 0
  675. ${IApplicationDestinations::SetAppID} $1 '("${BUNDLEID}")i.r0'
  676. ${If} $0 >= 0
  677. ${IApplicationDestinations::RemoveAllDestinations} $1 ''
  678. ${EndIf}
  679. ${IUnknown::Release} $1 ""
  680. ${EndIf}
  681. !macroend
  682. ; From https://stackoverflow.com/a/42816728/16993372
  683. !macro UnpinShortcut shortcut
  684. !insertmacro ComHlpr_CreateInProcInstance ${CLSID_StartMenuPin} ${IID_IStartMenuPinnedList} r0 ""
  685. ${If} $0 P<> 0
  686. System::Call 'SHELL32::SHCreateItemFromParsingName(ws, p0, g "${IID_IShellItem}", *p0r1)' "${shortcut}"
  687. ${If} $1 P<> 0
  688. ${IStartMenuPinnedList::RemoveFromList} $0 '(r1)'
  689. ${IUnknown::Release} $1 ""
  690. ${EndIf}
  691. ${IUnknown::Release} $0 ""
  692. ${EndIf}
  693. !macroend
  694. Section Uninstall
  695. !insertmacro CheckIfAppIsRunning
  696. !insertmacro CheckAllVergeProcesses
  697. !insertmacro RemoveVergeService
  698. ; Delete the app directory and its content from disk
  699. ; Copy main executable
  700. Delete "$INSTDIR\${MAINBINARYNAME}.exe"
  701. ; Delete resources
  702. {{#each resources}}
  703. Delete "$INSTDIR\\{{this.[1]}}"
  704. {{/each}}
  705. Delete "$INSTDIR\resources"
  706. ; Delete external binaries
  707. {{#each binaries}}
  708. Delete "$INSTDIR\\{{this}}"
  709. {{/each}}
  710. ; Delete uninstaller
  711. Delete "$INSTDIR\uninstall.exe"
  712. {{#each resources_ancestors}}
  713. RMDir /REBOOTOK "$INSTDIR\\{{this}}"
  714. {{/each}}
  715. RMDir "$INSTDIR"
  716. !insertmacro DeleteAppUserModelId
  717. !insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk"
  718. !insertmacro UnpinShortcut "$DESKTOP\${MAINBINARYNAME}.lnk"
  719. ; Remove start menu shortcut
  720. !insertmacro MUI_STARTMENU_GETFOLDER Application $AppStartMenuFolder
  721. Delete "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk"
  722. RMDir "$SMPROGRAMS\$AppStartMenuFolder"
  723. ; Remove desktop shortcuts
  724. Delete "$DESKTOP\${MAINBINARYNAME}.lnk"
  725. ; Remove registry information for add/remove programs
  726. !if "${INSTALLMODE}" == "both"
  727. DeleteRegKey SHCTX "${UNINSTKEY}"
  728. !else if "${INSTALLMODE}" == "perMachine"
  729. DeleteRegKey HKLM "${UNINSTKEY}"
  730. !else
  731. DeleteRegKey HKCU "${UNINSTKEY}"
  732. !endif
  733. DeleteRegValue HKCU "${MANUPRODUCTKEY}" "Installer Language"
  734. ; Delete app data
  735. ${If} $DeleteAppDataCheckboxState == 1
  736. SetShellVarContext current
  737. RmDir /r "$APPDATA\${BUNDLEID}"
  738. RmDir /r "$LOCALAPPDATA\${BUNDLEID}"
  739. ${EndIf}
  740. ${GetOptions} $CMDLINE "/P" $R0
  741. IfErrors +2 0
  742. SetAutoClose true
  743. SectionEnd
  744. Function RestorePreviousInstallLocation
  745. ReadRegStr $4 SHCTX "${MANUPRODUCTKEY}" ""
  746. StrCmp $4 "" +2 0
  747. StrCpy $INSTDIR $4
  748. FunctionEnd
  749. Function SkipIfPassive
  750. ${IfThen} $PassiveMode == 1 ${|} Abort ${|}
  751. FunctionEnd
  752. !macro SetLnkAppUserModelId shortcut
  753. !insertmacro ComHlpr_CreateInProcInstance ${CLSID_ShellLink} ${IID_IShellLink} r0 ""
  754. ${If} $0 P<> 0
  755. ${IUnknown::QueryInterface} $0 '("${IID_IPersistFile}",.r1)'
  756. ${If} $1 P<> 0
  757. ${IPersistFile::Load} $1 '("${shortcut}", ${STGM_READWRITE})'
  758. ${IUnknown::QueryInterface} $0 '("${IID_IPropertyStore}",.r2)'
  759. ${If} $2 P<> 0
  760. System::Call 'Oleaut32::SysAllocString(w "${BUNDLEID}") i.r3'
  761. System::Call '*${SYSSTRUCT_PROPERTYKEY}(${PKEY_AppUserModel_ID})p.r4'
  762. System::Call '*${SYSSTRUCT_PROPVARIANT}(${VT_BSTR},,&i4 $3)p.r5'
  763. ${IPropertyStore::SetValue} $2 '($4,$5)'
  764. System::Call 'Oleaut32::SysFreeString($3)'
  765. System::Free $4
  766. System::Free $5
  767. ${IPropertyStore::Commit} $2 ""
  768. ${IUnknown::Release} $2 ""
  769. ${IPersistFile::Save} $1 '("${shortcut}",1)'
  770. ${EndIf}
  771. ${IUnknown::Release} $1 ""
  772. ${EndIf}
  773. ${IUnknown::Release} $0 ""
  774. ${EndIf}
  775. !macroend
  776. Function CreateDesktopShortcut
  777. CreateShortcut "$DESKTOP\${MAINBINARYNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe"
  778. !insertmacro SetLnkAppUserModelId "$DESKTOP\${MAINBINARYNAME}.lnk"
  779. FunctionEnd
  780. Function CreateStartMenuShortcut
  781. CreateDirectory "$SMPROGRAMS\$AppStartMenuFolder"
  782. CreateShortcut "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe"
  783. !insertmacro SetLnkAppUserModelId "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk"
  784. FunctionEnd