installer.nsi 28 KB

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