installer.nsi 28 KB

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