installer.nsi 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918
  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 verge-mihomo-alpha.exe is running
  391. !if "${INSTALLMODE}" == "currentUser"
  392. nsis_tauri_utils::FindProcessCurrentUser "verge-mihomo-alpha.exe"
  393. !else
  394. nsis_tauri_utils::FindProcess "verge-mihomo-alpha.exe"
  395. !endif
  396. Pop $R0
  397. ${If} $R0 = 0
  398. DetailPrint "Kill verge-mihomo-alpha.exe..."
  399. !if "${INSTALLMODE}" == "currentUser"
  400. nsis_tauri_utils::KillProcessCurrentUser "verge-mihomo-alpha.exe"
  401. !else
  402. nsis_tauri_utils::KillProcess "verge-mihomo-alpha.exe"
  403. !endif
  404. ${EndIf}
  405. ; Check if verge-mihomo.exe is running
  406. !if "${INSTALLMODE}" == "currentUser"
  407. nsis_tauri_utils::FindProcessCurrentUser "verge-mihomo.exe"
  408. !else
  409. nsis_tauri_utils::FindProcess "verge-mihomo.exe"
  410. !endif
  411. Pop $R0
  412. ${If} $R0 = 0
  413. DetailPrint "Kill verge-mihomo.exe..."
  414. !if "${INSTALLMODE}" == "currentUser"
  415. nsis_tauri_utils::KillProcessCurrentUser "verge-mihomo.exe"
  416. !else
  417. nsis_tauri_utils::KillProcess "verge-mihomo.exe"
  418. !endif
  419. ${EndIf}
  420. ; Check if clash-meta-alpha.exe is running
  421. !if "${INSTALLMODE}" == "currentUser"
  422. nsis_tauri_utils::FindProcessCurrentUser "clash-meta-alpha.exe"
  423. !else
  424. nsis_tauri_utils::FindProcess "clash-meta-alpha.exe"
  425. !endif
  426. Pop $R0
  427. ${If} $R0 = 0
  428. DetailPrint "Kill clash-meta-alpha.exe..."
  429. !if "${INSTALLMODE}" == "currentUser"
  430. nsis_tauri_utils::KillProcessCurrentUser "clash-meta-alpha.exe"
  431. !else
  432. nsis_tauri_utils::KillProcess "clash-meta-alpha.exe"
  433. !endif
  434. ${EndIf}
  435. ; Check if clash-meta.exe is running
  436. !if "${INSTALLMODE}" == "currentUser"
  437. nsis_tauri_utils::FindProcessCurrentUser "clash-meta.exe"
  438. !else
  439. nsis_tauri_utils::FindProcess "clash-meta.exe"
  440. !endif
  441. Pop $R0
  442. ${If} $R0 = 0
  443. DetailPrint "Kill clash-meta.exe..."
  444. !if "${INSTALLMODE}" == "currentUser"
  445. nsis_tauri_utils::KillProcessCurrentUser "clash-meta.exe"
  446. !else
  447. nsis_tauri_utils::KillProcess "clash-meta.exe"
  448. !endif
  449. ${EndIf}
  450. !macroend
  451. !macro StartVergeService
  452. ; Check if the service exists
  453. SimpleSC::ExistsService "clash_verge_service"
  454. Pop $0 ; 0:service exists;other: service not exists
  455. ; Service exists
  456. ${If} $0 == 0
  457. Push $0
  458. ; Check if the service is running
  459. SimpleSC::ServiceIsRunning "clash_verge_service"
  460. Pop $0 ; returns an errorcode (<>0) otherwise success (0)
  461. Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)
  462. ${If} $0 == 0
  463. Push $0
  464. ${If} $1 == 0
  465. DetailPrint "Restart Clash Verge Service..."
  466. SimpleSC::StartService "clash_verge_service" "" 30
  467. ${EndIf}
  468. ${ElseIf} $0 != 0
  469. Push $0
  470. SimpleSC::GetErrorMessage
  471. Pop $0
  472. MessageBox MB_OK|MB_ICONSTOP "Check Service Status Error ($0)"
  473. ${EndIf}
  474. ${EndIf}
  475. !macroend
  476. !macro RemoveVergeService
  477. ; Check if the service exists
  478. SimpleSC::ExistsService "clash_verge_service"
  479. Pop $0 ; 0:service exists;other: service not exists
  480. ; Service exists
  481. ${If} $0 == 0
  482. Push $0
  483. ; Check if the service is running
  484. SimpleSC::ServiceIsRunning "clash_verge_service"
  485. Pop $0 ; returns an errorcode (<>0) otherwise success (0)
  486. Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)
  487. ${If} $0 == 0
  488. Push $0
  489. ${If} $1 == 1
  490. DetailPrint "Stop Clash Verge Service..."
  491. SimpleSC::StopService "clash_verge_service" 1 30
  492. Pop $0 ; returns an errorcode (<>0) otherwise success (0)
  493. ${If} $0 == 0
  494. DetailPrint "Removing Clash Verge Service..."
  495. SimpleSC::RemoveService "clash_verge_service"
  496. ${ElseIf} $0 != 0
  497. Push $0
  498. SimpleSC::GetErrorMessage
  499. Pop $0
  500. MessageBox MB_OK|MB_ICONSTOP "Clash Verge Service Stop Error ($0)"
  501. ${EndIf}
  502. ${ElseIf} $1 == 0
  503. DetailPrint "Removing Clash Verge Service..."
  504. SimpleSC::RemoveService "clash_verge_service"
  505. ${EndIf}
  506. ${ElseIf} $0 != 0
  507. Push $0
  508. SimpleSC::GetErrorMessage
  509. Pop $0
  510. MessageBox MB_OK|MB_ICONSTOP "Check Service Status Error ($0)"
  511. ${EndIf}
  512. ${EndIf}
  513. !macroend
  514. Section EarlyChecks
  515. ; Abort silent installer if downgrades is disabled
  516. !if "${ALLOWDOWNGRADES}" == "false"
  517. IfSilent 0 silent_downgrades_done
  518. ; If downgrading
  519. ${If} $R0 == -1
  520. System::Call 'kernel32::AttachConsole(i -1)i.r0'
  521. ${If} $0 != 0
  522. System::Call 'kernel32::GetStdHandle(i -11)i.r0'
  523. System::call 'kernel32::SetConsoleTextAttribute(i r0, i 0x0004)' ; set red color
  524. FileWrite $0 "$(silentDowngrades)"
  525. ${EndIf}
  526. Abort
  527. ${EndIf}
  528. silent_downgrades_done:
  529. !endif
  530. SectionEnd
  531. Section WebView2
  532. ; Check if Webview2 is already installed and skip this section
  533. ${If} ${RunningX64}
  534. ReadRegStr $4 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
  535. ${Else}
  536. ReadRegStr $4 HKLM "SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
  537. ${EndIf}
  538. ReadRegStr $5 HKCU "SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
  539. StrCmp $4 "" 0 webview2_done
  540. StrCmp $5 "" 0 webview2_done
  541. ; Webview2 install modes
  542. !if "${INSTALLWEBVIEW2MODE}" == "downloadBootstrapper"
  543. Delete "$TEMP\MicrosoftEdgeWebview2Setup.exe"
  544. DetailPrint "$(webview2Downloading)"
  545. NSISdl::download "https://go.microsoft.com/fwlink/p/?LinkId=2124703" "$TEMP\MicrosoftEdgeWebview2Setup.exe"
  546. Pop $0
  547. ${If} $0 == 0
  548. DetailPrint "$(webview2DownloadSuccess)"
  549. ${Else}
  550. DetailPrint "$(webview2DownloadError)"
  551. Abort "$(webview2AbortError)"
  552. ${EndIf}
  553. StrCpy $6 "$TEMP\MicrosoftEdgeWebview2Setup.exe"
  554. Goto install_webview2
  555. !endif
  556. !if "${INSTALLWEBVIEW2MODE}" == "embedBootstrapper"
  557. Delete "$TEMP\MicrosoftEdgeWebview2Setup.exe"
  558. File "/oname=$TEMP\MicrosoftEdgeWebview2Setup.exe" "${WEBVIEW2BOOTSTRAPPERPATH}"
  559. DetailPrint "$(installingWebview2)"
  560. StrCpy $6 "$TEMP\MicrosoftEdgeWebview2Setup.exe"
  561. Goto install_webview2
  562. !endif
  563. !if "${INSTALLWEBVIEW2MODE}" == "offlineInstaller"
  564. Delete "$TEMP\MicrosoftEdgeWebView2RuntimeInstaller.exe"
  565. File "/oname=$TEMP\MicrosoftEdgeWebView2RuntimeInstaller.exe" "${WEBVIEW2INSTALLERPATH}"
  566. DetailPrint "$(installingWebview2)"
  567. StrCpy $6 "$TEMP\MicrosoftEdgeWebView2RuntimeInstaller.exe"
  568. Goto install_webview2
  569. !endif
  570. Goto webview2_done
  571. install_webview2:
  572. DetailPrint "$(installingWebview2)"
  573. ; $6 holds the path to the webview2 installer
  574. ExecWait "$6 ${WEBVIEW2INSTALLERARGS} /install" $1
  575. ${If} $1 == 0
  576. DetailPrint "$(webview2InstallSuccess)"
  577. ${Else}
  578. DetailPrint "$(webview2InstallError)"
  579. Abort "$(webview2AbortError)"
  580. ${EndIf}
  581. webview2_done:
  582. SectionEnd
  583. !macro CheckIfAppIsRunning
  584. !if "${INSTALLMODE}" == "currentUser"
  585. nsis_tauri_utils::FindProcessCurrentUser "${MAINBINARYNAME}.exe"
  586. !else
  587. nsis_tauri_utils::FindProcess "${MAINBINARYNAME}.exe"
  588. !endif
  589. Pop $R0
  590. ${If} $R0 = 0
  591. IfSilent kill 0
  592. ${IfThen} $PassiveMode != 1 ${|} MessageBox MB_OKCANCEL "$(appRunningOkKill)" IDOK kill IDCANCEL cancel ${|}
  593. kill:
  594. !if "${INSTALLMODE}" == "currentUser"
  595. nsis_tauri_utils::KillProcessCurrentUser "${MAINBINARYNAME}.exe"
  596. !else
  597. nsis_tauri_utils::KillProcess "${MAINBINARYNAME}.exe"
  598. !endif
  599. Pop $R0
  600. Sleep 500
  601. ${If} $R0 = 0
  602. Goto app_check_done
  603. ${Else}
  604. IfSilent silent ui
  605. silent:
  606. System::Call 'kernel32::AttachConsole(i -1)i.r0'
  607. ${If} $0 != 0
  608. System::Call 'kernel32::GetStdHandle(i -11)i.r0'
  609. System::call 'kernel32::SetConsoleTextAttribute(i r0, i 0x0004)' ; set red color
  610. FileWrite $0 "$(appRunning)$\n"
  611. ${EndIf}
  612. Abort
  613. ui:
  614. Abort "$(failedToKillApp)"
  615. ${EndIf}
  616. cancel:
  617. Abort "$(appRunning)"
  618. ${EndIf}
  619. app_check_done:
  620. !macroend
  621. Section Install
  622. SetOutPath $INSTDIR
  623. !insertmacro CheckIfAppIsRunning
  624. !insertmacro CheckAllVergeProcesses
  625. ; Copy main executable
  626. File "${MAINBINARYSRCPATH}"
  627. ; Copy resources
  628. {{#each resources_dirs}}
  629. CreateDirectory "$INSTDIR\\{{this}}"
  630. {{/each}}
  631. {{#each resources}}
  632. File /a "/oname={{this.[1]}}" "{{@key}}"
  633. {{/each}}
  634. ; Copy external binaries
  635. {{#each binaries}}
  636. File /a "/oname={{this}}" "{{@key}}"
  637. {{/each}}
  638. !insertmacro StartVergeService
  639. ; Create uninstaller
  640. WriteUninstaller "$INSTDIR\uninstall.exe"
  641. ; Save $INSTDIR in registry for future installations
  642. WriteRegStr SHCTX "${MANUPRODUCTKEY}" "" $INSTDIR
  643. !if "${INSTALLMODE}" == "both"
  644. ; Save install mode to be selected by default for the next installation such as updating
  645. ; or when uninstalling
  646. WriteRegStr SHCTX "${UNINSTKEY}" $MultiUser.InstallMode 1
  647. !endif
  648. ; Registry information for add/remove programs
  649. WriteRegStr SHCTX "${UNINSTKEY}" "DisplayName" "${PRODUCTNAME}"
  650. WriteRegStr SHCTX "${UNINSTKEY}" "DisplayIcon" "$\"$INSTDIR\${MAINBINARYNAME}.exe$\""
  651. WriteRegStr SHCTX "${UNINSTKEY}" "DisplayVersion" "${VERSION}"
  652. WriteRegStr SHCTX "${UNINSTKEY}" "Publisher" "${MANUFACTURER}"
  653. WriteRegStr SHCTX "${UNINSTKEY}" "InstallLocation" "$\"$INSTDIR$\""
  654. WriteRegStr SHCTX "${UNINSTKEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
  655. WriteRegDWORD SHCTX "${UNINSTKEY}" "NoModify" "1"
  656. WriteRegDWORD SHCTX "${UNINSTKEY}" "NoRepair" "1"
  657. WriteRegDWORD SHCTX "${UNINSTKEY}" "EstimatedSize" "${ESTIMATEDSIZE}"
  658. ; Create start menu shortcut (GUI)
  659. !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
  660. Call CreateStartMenuShortcut
  661. !insertmacro MUI_STARTMENU_WRITE_END
  662. ; Create shortcuts for silent and passive installers, which
  663. ; can be disabled by passing `/NS` flag
  664. ; GUI installer has buttons for users to control creating them
  665. IfSilent check_ns_flag 0
  666. ${IfThen} $PassiveMode == 1 ${|} Goto check_ns_flag ${|}
  667. Goto shortcuts_done
  668. check_ns_flag:
  669. ${GetOptions} $CMDLINE "/NS" $R0
  670. IfErrors 0 shortcuts_done
  671. Call CreateDesktopShortcut
  672. Call CreateStartMenuShortcut
  673. shortcuts_done:
  674. ; Auto close this page for passive mode
  675. ${IfThen} $PassiveMode == 1 ${|} SetAutoClose true ${|}
  676. SectionEnd
  677. Function .onInstSuccess
  678. ; Check for `/R` flag only in silent and passive installers because
  679. ; GUI installer has a toggle for the user to (re)start the app
  680. IfSilent check_r_flag 0
  681. ${IfThen} $PassiveMode == 1 ${|} Goto check_r_flag ${|}
  682. Goto run_done
  683. check_r_flag:
  684. ${GetOptions} $CMDLINE "/R" $R0
  685. IfErrors run_done 0
  686. ${GetOptions} $CMDLINE "/ARGS" $R0
  687. nsis_tauri_utils::RunAsUser "$INSTDIR\${MAINBINARYNAME}.exe" "$R0"
  688. run_done:
  689. FunctionEnd
  690. Function un.onInit
  691. !insertmacro SetContext
  692. !if "${INSTALLMODE}" == "both"
  693. !insertmacro MULTIUSER_UNINIT
  694. !endif
  695. !insertmacro MUI_UNGETLANGUAGE
  696. FunctionEnd
  697. !macro DeleteAppUserModelId
  698. !insertmacro ComHlpr_CreateInProcInstance ${CLSID_DestinationList} ${IID_ICustomDestinationList} r1 ""
  699. ${If} $1 P<> 0
  700. ${ICustomDestinationList::DeleteList} $1 '("${BUNDLEID}")'
  701. ${IUnknown::Release} $1 ""
  702. ${EndIf}
  703. !insertmacro ComHlpr_CreateInProcInstance ${CLSID_ApplicationDestinations} ${IID_IApplicationDestinations} r1 ""
  704. ${If} $1 P<> 0
  705. ${IApplicationDestinations::SetAppID} $1 '("${BUNDLEID}")i.r0'
  706. ${If} $0 >= 0
  707. ${IApplicationDestinations::RemoveAllDestinations} $1 ''
  708. ${EndIf}
  709. ${IUnknown::Release} $1 ""
  710. ${EndIf}
  711. !macroend
  712. ; From https://stackoverflow.com/a/42816728/16993372
  713. !macro UnpinShortcut shortcut
  714. !insertmacro ComHlpr_CreateInProcInstance ${CLSID_StartMenuPin} ${IID_IStartMenuPinnedList} r0 ""
  715. ${If} $0 P<> 0
  716. System::Call 'SHELL32::SHCreateItemFromParsingName(ws, p0, g "${IID_IShellItem}", *p0r1)' "${shortcut}"
  717. ${If} $1 P<> 0
  718. ${IStartMenuPinnedList::RemoveFromList} $0 '(r1)'
  719. ${IUnknown::Release} $1 ""
  720. ${EndIf}
  721. ${IUnknown::Release} $0 ""
  722. ${EndIf}
  723. !macroend
  724. Section Uninstall
  725. !insertmacro CheckIfAppIsRunning
  726. !insertmacro CheckAllVergeProcesses
  727. !insertmacro RemoveVergeService
  728. ; Delete the app directory and its content from disk
  729. ; Copy main executable
  730. Delete "$INSTDIR\${MAINBINARYNAME}.exe"
  731. ; Delete resources
  732. {{#each resources}}
  733. Delete "$INSTDIR\\{{this.[1]}}"
  734. {{/each}}
  735. Delete "$INSTDIR\resources"
  736. ; Delete external binaries
  737. {{#each binaries}}
  738. Delete "$INSTDIR\\{{this}}"
  739. {{/each}}
  740. ; Delete uninstaller
  741. Delete "$INSTDIR\uninstall.exe"
  742. {{#each resources_ancestors}}
  743. RMDir /REBOOTOK "$INSTDIR\\{{this}}"
  744. {{/each}}
  745. RMDir "$INSTDIR"
  746. !insertmacro DeleteAppUserModelId
  747. !insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk"
  748. !insertmacro UnpinShortcut "$DESKTOP\${MAINBINARYNAME}.lnk"
  749. ; Remove start menu shortcut
  750. !insertmacro MUI_STARTMENU_GETFOLDER Application $AppStartMenuFolder
  751. Delete "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk"
  752. RMDir "$SMPROGRAMS\$AppStartMenuFolder"
  753. ; Remove desktop shortcuts
  754. Delete "$DESKTOP\${MAINBINARYNAME}.lnk"
  755. ; Remove registry information for add/remove programs
  756. !if "${INSTALLMODE}" == "both"
  757. DeleteRegKey SHCTX "${UNINSTKEY}"
  758. !else if "${INSTALLMODE}" == "perMachine"
  759. DeleteRegKey HKLM "${UNINSTKEY}"
  760. !else
  761. DeleteRegKey HKCU "${UNINSTKEY}"
  762. !endif
  763. DeleteRegValue HKCU "${MANUPRODUCTKEY}" "Installer Language"
  764. ; Delete app data
  765. ${If} $DeleteAppDataCheckboxState == 1
  766. SetShellVarContext current
  767. RmDir /r "$APPDATA\${BUNDLEID}"
  768. RmDir /r "$LOCALAPPDATA\${BUNDLEID}"
  769. ${EndIf}
  770. ${GetOptions} $CMDLINE "/P" $R0
  771. IfErrors +2 0
  772. SetAutoClose true
  773. SectionEnd
  774. Function RestorePreviousInstallLocation
  775. ReadRegStr $4 SHCTX "${MANUPRODUCTKEY}" ""
  776. StrCmp $4 "" +2 0
  777. StrCpy $INSTDIR $4
  778. FunctionEnd
  779. Function SkipIfPassive
  780. ${IfThen} $PassiveMode == 1 ${|} Abort ${|}
  781. FunctionEnd
  782. !macro SetLnkAppUserModelId shortcut
  783. !insertmacro ComHlpr_CreateInProcInstance ${CLSID_ShellLink} ${IID_IShellLink} r0 ""
  784. ${If} $0 P<> 0
  785. ${IUnknown::QueryInterface} $0 '("${IID_IPersistFile}",.r1)'
  786. ${If} $1 P<> 0
  787. ${IPersistFile::Load} $1 '("${shortcut}", ${STGM_READWRITE})'
  788. ${IUnknown::QueryInterface} $0 '("${IID_IPropertyStore}",.r2)'
  789. ${If} $2 P<> 0
  790. System::Call 'Oleaut32::SysAllocString(w "${BUNDLEID}") i.r3'
  791. System::Call '*${SYSSTRUCT_PROPERTYKEY}(${PKEY_AppUserModel_ID})p.r4'
  792. System::Call '*${SYSSTRUCT_PROPVARIANT}(${VT_BSTR},,&i4 $3)p.r5'
  793. ${IPropertyStore::SetValue} $2 '($4,$5)'
  794. System::Call 'Oleaut32::SysFreeString($3)'
  795. System::Free $4
  796. System::Free $5
  797. ${IPropertyStore::Commit} $2 ""
  798. ${IUnknown::Release} $2 ""
  799. ${IPersistFile::Save} $1 '("${shortcut}",1)'
  800. ${EndIf}
  801. ${IUnknown::Release} $1 ""
  802. ${EndIf}
  803. ${IUnknown::Release} $0 ""
  804. ${EndIf}
  805. !macroend
  806. Function CreateDesktopShortcut
  807. CreateShortcut "$DESKTOP\${MAINBINARYNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe"
  808. !insertmacro SetLnkAppUserModelId "$DESKTOP\${MAINBINARYNAME}.lnk"
  809. FunctionEnd
  810. Function CreateStartMenuShortcut
  811. CreateDirectory "$SMPROGRAMS\$AppStartMenuFolder"
  812. CreateShortcut "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe"
  813. !insertmacro SetLnkAppUserModelId "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk"
  814. FunctionEnd