diff --git a/.gitignore b/.gitignore index f80c492a11..d3d50d52b8 100644 --- a/.gitignore +++ b/.gitignore @@ -130,7 +130,7 @@ CMakeCache.txt **/CMakeFiles/ /StatusImPackage/* *.AppImage -Status-Windows-x86_64.zip +Status-Windows-x86_64.exe /desktop/bin/* /desktop/lib/* /desktop/modules/* @@ -148,4 +148,3 @@ logger_settings.ini conan*.txt conanbuildinfo.* conan.cmake -/.conan_*/ diff --git a/ci/Jenkinsfile.combined b/ci/Jenkinsfile.combined index abdf96e228..1d0b84626d 100644 --- a/ci/Jenkinsfile.combined +++ b/ci/Jenkinsfile.combined @@ -77,22 +77,22 @@ pipeline { if (btype != 'release') { dmgUrl = cmn.uploadArtifact(cmn.pkgFind('dmg')) appUrl = cmn.uploadArtifact(cmn.pkgFind('AppImage')) - zipUrl = cmn.uploadArtifact(cmn.pkgFind('zip')) + exeUrl = cmn.uploadArtifact(cmn.pkgFind('exe')) } else { dmgUrl = null appUrl = null - zipUrl = null + exeUrl = null } /* special case for iOS Diawi links */ ipaUrl = ios.getBuildVariables().get('DIAWI_URL') /* add URLs to the build description */ cmn.setBuildDesc( - Apk: apkUrl, e2e: e2eUrl, iOS: ipaUrl, App: appUrl, Mac: dmgUrl, Win: zipUrl, + Apk: apkUrl, e2e: e2eUrl, iOS: ipaUrl, App: appUrl, Mac: dmgUrl, Win: exeUrl, ) /* Create latest.json with newest nightly URLs */ if (btype == 'nightly') { cmn.updateLatestNightlies( - APK: apkUrl, IOS: ipaUrl, APP: appUrl, MAC: dmgUrl, WIN: zipUrl + APK: apkUrl, IOS: ipaUrl, APP: appUrl, MAC: dmgUrl, WIN: exeUrl ) } } } @@ -101,7 +101,7 @@ pipeline { steps { script { if (env.CHANGE_ID != null) { cmn.githubNotify( - apk: apkUrl, e2e: e2eUrl, ipa: ipaUrl, app: appUrl, dmg: dmgUrl, win: zipUrl, + apk: apkUrl, e2e: e2eUrl, ipa: ipaUrl, app: appUrl, dmg: dmgUrl, win: exeUrl, ) } } } diff --git a/ci/Jenkinsfile.windows b/ci/Jenkinsfile.windows index e730fdb1e6..344e71a8c7 100644 --- a/ci/Jenkinsfile.windows +++ b/ci/Jenkinsfile.windows @@ -3,7 +3,7 @@ pipeline { /* privileged mode is necessary for fuse */ docker { label 'linux-new' - image 'statusteam/windows-desktop-ubuntu:1.0.0' + image 'statusteam/windows-desktop-ubuntu:nsis-1.0.0' args ( "--privileged "+ "-v /dev/fuse:/dev/fuse "+ diff --git a/ci/desktop.groovy b/ci/desktop.groovy index ad152c65a8..713586f7bc 100644 --- a/ci/desktop.groovy +++ b/ci/desktop.groovy @@ -65,8 +65,8 @@ def bundleWindows(type = 'nightly') { sh './scripts/build-desktop.sh bundle' dir(packageFolder) { - pkg = common.pkgFilename(type, 'zip') - sh "mv ../Status-Windows-x86_64.zip ${pkg}" + pkg = common.pkgFilename(type, 'exe') + sh "mv ../Status-x86_64-setup.exe ${pkg}" } return "${packageFolder}/${pkg}".drop(2) } diff --git a/deployment/windows/nsis/include/SnoreNotify.nsh b/deployment/windows/nsis/include/SnoreNotify.nsh new file mode 100644 index 0000000000..37744a5508 --- /dev/null +++ b/deployment/windows/nsis/include/SnoreNotify.nsh @@ -0,0 +1,23 @@ +!include LogicLib.nsh +!include WordFunc.nsh + +Function SnoreWinVer + ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + ${VersionCompare} "6.2" $R0 $R0 + ${If} $R0 == 1 + Push "NotWin8" + ${Else} + Push "AtLeastWin8" + ${EndIf} +FunctionEnd + +!macro SnoreShortcut path exe appID + Call SnoreWinVer + Pop $0 + ${If} $0 == "AtLeastWin8" + nsExec::ExecToLog '"${SnoreToastExe}" -install "${path}" "${exe}" "${appID}"' + ${Else} + DetailPrint "Creating shortcut to ${exe}" + CreateShortCut "${path}" "${exe}" + ${EndIf} +!macroend \ No newline at end of file diff --git a/deployment/windows/nsis/include/UAC.nsh b/deployment/windows/nsis/include/UAC.nsh new file mode 100644 index 0000000000..08979aba97 --- /dev/null +++ b/deployment/windows/nsis/include/UAC.nsh @@ -0,0 +1,299 @@ +/*** UAC Plug-in *** + +Interactive User (MediumIL) Admin user (HighIL) +***[Setup.exe]************* ***[Setup.exe]************** +* * * * +* +++[.OnInit]+++++++++++ * * +++[.OnInit]++++++++++++ * +* + UAC_RunElevated >---+-+----> * + + * +* + NSIS.Quit + * * + + * +* +++++++++++++++++++++++ * * ++++++++++++++++++++++++ * +* * * * +* * * * +* +++[Section]+++++++++++ * * +++[Section]++++++++++++ * +* + + * /--+-+- +** +** Get integrity level of current process +** +**/ +!macro UAC_GetIntegrityLevel outvar +UAC::_ 6 +!if "${outvar}" != "s" + Pop ${outvar} +!endif +!macroend + + + +/* UAC_IsAdmin +** +** Is the current process running with administrator privileges? Result in $0 +** +** ${If} ${UAC_IsAdmin} ... +** +**/ +!macro UAC_IsAdmin +UAC::_ 2 +!macroend +!define UAC_IsAdmin `"" UAC_IsAdmin ""` +!macro _UAC_IsAdmin _a _b _t _f +!insertmacro _UAC_MakeLL_Cmp _!= 0 2s +!macroend + + + +/* UAC_IsInnerInstance +** +** Does the current process have a NSIS/UAC parent process that is part of the elevation operation? +** +** ${If} ${UAC_IsInnerInstance} ... +** +**/ +!macro UAC_IsInnerInstance +UAC::_ 3 +!macroend +!define UAC_IsInnerInstance `"" UAC_IsInnerInstance ""` +!macro _UAC_IsInnerInstance _a _b _t _f +!insertmacro _UAC_MakeLL_Cmp _!= 0 3s +!macroend + + + +/* UAC_PageElevation_OnInit, UAC_PageElevation_OnGuiInit, +** +** Helper macros for elevation on a custom elevation page, see the DualMode example for more information. +** +**/ +!macro UAC_Notify_OnGuiInit +UAC::_ 4 +!macroend +!macro UAC_PageElevation_OnGuiInit +!insertmacro UAC_Notify_OnGuiInit +!macroend +!macro UAC_PageElevation_OnInit +UAC::_ 5 +${IfThen} ${Errors} ${|} Quit ${|} +!macroend + + + +/* UAC_AsUser_Call +** +** Calls a function or label in the user process instance. +** All the UAC_AsUser_* macros use this helper macro. +** +**/ +!define UAC_SYNCREGISTERS 0x1 +;define UAC_SYNCSTACK 0x2 +!define UAC_SYNCOUTDIR 0x4 +!define UAC_SYNCINSTDIR 0x8 +;define UAC_CLEARERRFLAG 0x10 +!macro UAC_AsUser_Call type name flags +push $0 +Get${type}Address $0 ${name} +!verbose push +!verbose ${UAC_VERBOSE} +!insertmacro _UAC_ParseDefineFlagsToInt _UAC_AsUser_Call__flags ${flags} +!verbose pop +StrCpy $0 "1$0:${_UAC_AsUser_Call__flags}" +!undef _UAC_AsUser_Call__flags +Exch $0 +UAC::_ +!macroend + + + +/* +** UAC_AsUser_GetSection +*/ +!macro UAC_AsUser_GetSection secprop secidx outvar +!insertmacro _UAC_AsUser_GenOp ${outvar} SectionGet${secprop} ${secidx} "" +!macroend + + + +/* +** UAC_AsUser_GetGlobalVar +** UAC_AsUser_GetGlobal +*/ +!macro UAC_AsUser_GetGlobalVar var +!insertmacro _UAC_AsUser_GenOp ${var} StrCpy "" ${var} +!macroend +!macro UAC_AsUser_GetGlobal outvar srcvar +!insertmacro _UAC_AsUser_GenOp ${outvar} StrCpy "" ${srcvar} +!macroend + + + +/* +** UAC_AsUser_ExecShell +** +** Call ExecShell in the user process instance. +** +*/ +!macro UAC_AsUser_ExecShell verb command params workdir show +!insertmacro _UAC_IncL +goto _UAC_L_E_${__UAC_L} +_UAC_L_F_${__UAC_L}: +ExecShell "${verb}" "${command}" '${params}' ${show} +return +_UAC_L_E_${__UAC_L}: +!if "${workdir}" != "" + push $outdir + SetOutPath "${workdir}" +!endif +!insertmacro UAC_AsUser_Call Label _UAC_L_F_${__UAC_L} ${UAC_SYNCREGISTERS}|${UAC_SYNCOUTDIR}|${UAC_SYNCINSTDIR} #|${UAC_CLEARERRFLAG} +!if "${workdir}" != "" + pop $outdir + SetOutPath $outdir +!endif +!macroend + + + +!macro _UAC_MakeLL_Cmp cmpop cmp pluginparams +!insertmacro _LOGICLIB_TEMP +UAC::_ ${pluginparams} +pop $_LOGICLIB_TEMP +!insertmacro ${cmpop} $_LOGICLIB_TEMP ${cmp} `${_t}` `${_f}` +!macroend +!macro _UAC_definemath def val1 op val2 +!define /math _UAC_definemath "${val1}" ${op} ${val2} +!ifdef ${def} + !undef ${def} +!endif +!define ${def} "${_UAC_definemath}" +!undef _UAC_definemath +!macroend +!macro _UAC_ParseDefineFlags_orin parse outflags +!searchparse /noerrors ${${parse}} "" _UAC_ParseDefineFlags_orin_f1 "|" _UAC_ParseDefineFlags_orin_f2 +!define _UAC_ParseDefineFlags_orin_this ${_UAC_ParseDefineFlags_orin_f1} +!undef ${parse} +!define ${parse} ${_UAC_ParseDefineFlags_orin_f2} +!define _UAC_ParseDefineFlags_orin_saveout ${${outflags}} +!undef ${outflags} +!define /math ${outflags} "${_UAC_ParseDefineFlags_orin_saveout}" | "${_UAC_ParseDefineFlags_orin_this}" +!undef _UAC_ParseDefineFlags_orin_saveout +!undef _UAC_ParseDefineFlags_orin_this +!ifdef _UAC_ParseDefineFlags_orin_f1 + !undef _UAC_ParseDefineFlags_orin_f1 +!endif +!ifdef _UAC_ParseDefineFlags_orin_f2 + !undef _UAC_ParseDefineFlags_orin_f2 +!endif +!macroend +!macro _UAC_ParseDefineFlags_Begin _outdef _in +!define _UAC_PDF${_outdef}_parse "${_in}" +!define _UAC_PDF${_outdef}_flags "" +!define _UAC_PDF${_outdef}_r 0 +!insertmacro _UAC_ParseDefineFlags_orin _UAC_PDF${_outdef}_parse _UAC_PDF${_outdef}_flags ;0x1 +!insertmacro _UAC_ParseDefineFlags_orin _UAC_PDF${_outdef}_parse _UAC_PDF${_outdef}_flags ;0x2 +!insertmacro _UAC_ParseDefineFlags_orin _UAC_PDF${_outdef}_parse _UAC_PDF${_outdef}_flags ;0x4 +!insertmacro _UAC_ParseDefineFlags_orin _UAC_PDF${_outdef}_parse _UAC_PDF${_outdef}_flags ;0x8 +!insertmacro _UAC_ParseDefineFlags_orin _UAC_PDF${_outdef}_parse _UAC_PDF${_outdef}_flags ;0x10 +!macroend +!macro _UAC_ParseDefineFlags_End _outdef +!define ${_outdef} ${_UAC_PDF${_outdef}_r} +!undef _UAC_PDF${_outdef}_r +!undef _UAC_PDF${_outdef}_flags +!undef _UAC_PDF${_outdef}_parse +!macroend +!macro _UAC_ParseDefineFlags_IncludeFlag _outdef flag +!if ${_UAC_PDF${_outdef}_flags} & ${flag} + !insertmacro _UAC_definemath _UAC_PDF${_outdef}_r ${_UAC_PDF${_outdef}_r} | ${flag} +!endif +!macroend +!macro _UAC_ParseDefineFlagsToInt _outdef _in +!insertmacro _UAC_ParseDefineFlags_Begin _UAC_ParseDefineFlagsToInt_tmp "${_in}" +!define ${_outdef} ${_UAC_PDF_UAC_ParseDefineFlagsToInt_tmp_flags} +!insertmacro _UAC_ParseDefineFlags_End _UAC_ParseDefineFlagsToInt_tmp +!undef _UAC_ParseDefineFlagsToInt_tmp +!macroend +!macro _UAC_IncL +!insertmacro _UAC_definemath __UAC_L "${__UAC_L}" + 1 +!macroend +!macro _UAC_AsUser_GenOp outvar op opparam1 opparam2 +!define _UAC_AUGOGR_ID _UAC_AUGOGR_OP${outvar}${op}${opparam1}${opparam2} +!ifndef ${_UAC_AUGOGR_ID} ;Has this exact action been done before? + !if ${outvar} == $0 + !define ${_UAC_AUGOGR_ID} $1 + !else + !define ${_UAC_AUGOGR_ID} $0 + !endif + !if "${opparam1}" == "" + !define _UAC_AUGOGR_OPP1 ${${_UAC_AUGOGR_ID}} + !define _UAC_AUGOGR_OPP2 ${opparam2} + !else + !define _UAC_AUGOGR_OPP1 ${opparam1} + !define _UAC_AUGOGR_OPP2 ${${_UAC_AUGOGR_ID}} + !endif + goto ${_UAC_AUGOGR_ID}_C + ${_UAC_AUGOGR_ID}_F: + ${op} ${_UAC_AUGOGR_OPP1} ${_UAC_AUGOGR_OPP2} + return + ${_UAC_AUGOGR_ID}_C: + !undef _UAC_AUGOGR_OPP1 + !undef _UAC_AUGOGR_OPP2 +!endif +push ${${_UAC_AUGOGR_ID}} +!insertmacro UAC_AsUser_Call Label ${_UAC_AUGOGR_ID}_F ${UAC_SYNCREGISTERS} +StrCpy ${outvar} ${${_UAC_AUGOGR_ID}} +pop ${${_UAC_AUGOGR_ID}} +!undef _UAC_AUGOGR_ID +!macroend + + + +!verbose pop +!endif /* UAC_HDR__INC */ \ No newline at end of file diff --git a/deployment/windows/nsis/include/nsProcess.nsh b/deployment/windows/nsis/include/nsProcess.nsh new file mode 100644 index 0000000000..84278b02b0 --- /dev/null +++ b/deployment/windows/nsis/include/nsProcess.nsh @@ -0,0 +1,28 @@ +!define nsProcess::FindProcess `!insertmacro nsProcess::FindProcess` + +!macro nsProcess::FindProcess _FILE _ERR + nsProcess::_FindProcess /NOUNLOAD `${_FILE}` + Pop ${_ERR} +!macroend + + +!define nsProcess::KillProcess `!insertmacro nsProcess::KillProcess` + +!macro nsProcess::KillProcess _FILE _ERR + nsProcess::_KillProcess /NOUNLOAD `${_FILE}` + Pop ${_ERR} +!macroend + +!define nsProcess::CloseProcess `!insertmacro nsProcess::CloseProcess` + +!macro nsProcess::CloseProcess _FILE _ERR + nsProcess::_CloseProcess /NOUNLOAD `${_FILE}` + Pop ${_ERR} +!macroend + + +!define nsProcess::Unload `!insertmacro nsProcess::Unload` + +!macro nsProcess::Unload + nsProcess::_Unload +!macroend \ No newline at end of file diff --git a/deployment/windows/nsis/plugins/x86-ansi/SimpleFC.dll b/deployment/windows/nsis/plugins/x86-ansi/SimpleFC.dll new file mode 100644 index 0000000000..73b7d9634d Binary files /dev/null and b/deployment/windows/nsis/plugins/x86-ansi/SimpleFC.dll differ diff --git a/deployment/windows/nsis/plugins/x86-ansi/UAC.dll b/deployment/windows/nsis/plugins/x86-ansi/UAC.dll new file mode 100644 index 0000000000..57a58c5399 Binary files /dev/null and b/deployment/windows/nsis/plugins/x86-ansi/UAC.dll differ diff --git a/deployment/windows/nsis/plugins/x86-ansi/nsProcess.dll b/deployment/windows/nsis/plugins/x86-ansi/nsProcess.dll new file mode 100644 index 0000000000..4ce012103f Binary files /dev/null and b/deployment/windows/nsis/plugins/x86-ansi/nsProcess.dll differ diff --git a/deployment/windows/nsis/plugins/x86-unicode/UAC.dll b/deployment/windows/nsis/plugins/x86-unicode/UAC.dll new file mode 100644 index 0000000000..97e7d15eae Binary files /dev/null and b/deployment/windows/nsis/plugins/x86-unicode/UAC.dll differ diff --git a/deployment/windows/nsis/plugins/x86-unicode/nsProcess.dll b/deployment/windows/nsis/plugins/x86-unicode/nsProcess.dll new file mode 100644 index 0000000000..2478624ee0 Binary files /dev/null and b/deployment/windows/nsis/plugins/x86-unicode/nsProcess.dll differ diff --git a/deployment/windows/nsis/setup.nsi b/deployment/windows/nsis/setup.nsi new file mode 100644 index 0000000000..b4dc997272 --- /dev/null +++ b/deployment/windows/nsis/setup.nsi @@ -0,0 +1,1033 @@ +;-------------------------------- +; Build environment +;-------------------------------- + + ;Unicode true + ;!define top_srcdir @top_srcdir@ + ;!define srcdir @srcdir@ + !define VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_BUILD} + !define VERSION_FULL ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_BUILD}.0 + ;!define PUBLISHER "Status.im" + ;!define WEBSITE_URL "https://status.im/" + !define AppUserModelId "StatusIm.Status.Desktop.1" ; app.id must match ID in modules/react-native-desktop-notification/desktop/desktopnotification.cpp + !define SnoreToastExe "$INSTDIR\SnoreToast.exe" + !define AppLinkFileName "Status.lnk" + !define AppExeName "Status.exe" + !define UninstallExeName "Uninstall.exe" + !define UninstallLinkName "Uninstall.lnk" + !define NodeJsServerExeName "ubuntu-server.exe" + !define SetupExeFileName "Status-x86_64-setup.exe" + !define OrgRegistryKeyPath "Software\${PUBLISHER}" + !define AppRegistryKeyPath "${OrgRegistryKeyPath}\Status Desktop" + !define UninstallRegKeyPath "Software\Microsoft\Windows\CurrentVersion\Uninstall\Status Desktop" + + !addplugindir plugins/x86-ansi + +;-------------------------------- +;General +;-------------------------------- + + ;Name and file + Name "Status Desktop ${VERSION}" + OutFile "${top_srcdir}/${SetupExeFileName}" + + SetCompressor /FINAL ${COMPRESSION_TYPE} ${COMPRESSION_ALGO} + + ; Default installation folder + InstallDir "$PROGRAMFILES64\${PUBLISHER}" + + ; Get installation folder from registry if available + InstallDirRegKey HKLM "${AppRegistryKeyPath}" "" + + RequestExecutionLevel user + + !define DUMP_KEY "SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" + +;-------------------------------- +; Include Modern UI and functions +;-------------------------------- + + !include "MUI2.nsh" + !include "WordFunc.nsh" + !include "Library.nsh" + !include "WinVer.nsh" + !include "FileFunc.nsh" +; !include "Memento.nsh" + !include "StrFunc.nsh" + !include "include/UAC.nsh" + !include "include/SnoreNotify.nsh" + !include "include/nsProcess.nsh" + + ${StrRep} + +;-------------------------------- +; Installer's VersionInfo +;-------------------------------- + + VIProductVersion "${VERSION_FULL}" + VIAddVersionKey "CompanyName" "${PUBLISHER}" + VIAddVersionKey "ProductName" "Status Desktop" + VIAddVersionKey "ProductVersion" "${VERSION}" + VIAddVersionKey "FileDescription" "Status Desktop Client" + VIAddVersionKey "FileVersion" "${VERSION}" + VIAddVersionKey "LegalCopyright" "${PUBLISHER}" + VIAddVersionKey "OriginalFilename" "${SetupExeFileName}" + +;-------------------------------- +; Required functions +;-------------------------------- + + !insertmacro GetParameters + !insertmacro GetOptions + !insertmacro un.GetParameters + !insertmacro un.GetOptions + +;-------------------------------- +;Variables +;-------------------------------- + + Var MUI_TEMP + Var STARTMENU_FOLDER + Var PREVIOUS_INSTALLDIR + Var PREVIOUS_VERSION + Var PREVIOUS_VERSION_STATE + Var REINSTALL_UNINSTALL + Var ALL_USERS_DEFAULT + Var ALL_USERS + Var IS_ADMIN + Var USERNAME + Var PERFORM_UPDATE + Var SKIPLICENSE + Var SKIPUAC + Var GetInstalledSize.total + Var OldRunDir + Var CommandLine + Var Quiet + +;-------------------------------- +;Interface Settings +;-------------------------------- + + !define MUI_ICON "${top_srcdir}/deployment/windows/status.ico" + ;!define MUI_UNICON "${srcdir}/uninstall.ico" + + !define MUI_ABORTWARNING + +;-------------------------------- +;Memento settings +;-------------------------------- + +;!define MEMENTO_REGISTRY_ROOT SHELL_CONTEXT +;!define MEMENTO_REGISTRY_KEY "${AppRegistryKeyPath}" + +;-------------------------------- +;Pages + + !define MUI_PAGE_CUSTOMFUNCTION_PRE PageDirectoryPre + !insertmacro MUI_PAGE_DIRECTORY + + ; Start Menu Folder Page Configuration + !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX" + !define MUI_STARTMENUPAGE_REGISTRY_KEY "${AppRegistryKeyPath}" + !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Startmenu" + !define MUI_STARTMENUPAGE_DEFAULTFOLDER "Status Desktop" + + !define MUI_PAGE_CUSTOMFUNCTION_PRE PageStartmenuPre + !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER + + !define MUI_PAGE_CUSTOMFUNCTION_LEAVE PostInstPage + !insertmacro MUI_PAGE_INSTFILES + + !define MUI_PAGE_CUSTOMFUNCTION_PRE un.ConfirmPagePre + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_INSTFILES + !define MUI_PAGE_CUSTOMFUNCTION_PRE un.FinishPagePre + !insertmacro MUI_UNPAGE_FINISH + +Function GetUserInfo + ClearErrors + UserInfo::GetName + ${If} ${Errors} + StrCpy $IS_ADMIN 1 + Return + ${EndIf} + Pop $USERNAME + + ${If} ${UAC_IsAdmin} + StrCpy $IS_ADMIN 1 + ${Else} + StrCpy $IS_ADMIN 0 + ${EndIf} + +FunctionEnd + +Function UpdateShellVarContext + + ${If} $ALL_USERS == 1 + SetShellVarContext all + DetailPrint "Installing for all users" + ${Else} + SetShellVarContext current + DetailPrint "Installing for current user" + ${EndIf} + +FunctionEnd + +!Macro MessageBoxImpl options text sdreturn checks + ${If} $Quiet == 1 + MessageBox ${options} `${text}` ${checks} + ${Else} + MessageBox ${options} `${text}` /SD ${sdreturn} ${checks} + ${Endif} + +!MacroEnd + +!define MessageBox `!insertmacro MessageBoxImpl` + +Function ReadAllUsersCommandline + + ${GetOptions} $CommandLine "/user" $R1 + + ${Unless} ${Errors} + ${If} $R1 == "current" + ${OrIf} $R1 == "=current" + StrCpy $ALL_USERS 0 + ${ElseIf} $R1 == "all" + ${OrIf} $R1 == "=all" + StrCpy $ALL_USERS 1 + ${Else} + ${MessageBox} MB_ICONSTOP "Invalid option for /user. Has to be either /user=all or /user=current" IDOK '' + Abort + ${EndIf} + ${EndUnless} + Call UpdateShellVarContext + +FunctionEnd + +Function CheckPrevInstallDirExists + + ${If} $PREVIOUS_INSTALLDIR != "" + + ; Make sure directory is valid + Push $R0 + Push $R1 + StrCpy $R0 "$PREVIOUS_INSTALLDIR" "" -1 + ${If} $R0 == '\' + ${OrIf} $R0 == '/' + StrCpy $R0 $PREVIOUS_INSTALLDIR*.* + ${Else} + StrCpy $R0 $PREVIOUS_INSTALLDIR\*.* + ${EndIf} + ${IfNot} ${FileExists} $R0 + StrCpy $PREVIOUS_INSTALLDIR "" + ${EndIf} + Pop $R1 + Pop $R0 + + ${EndIf} + +FunctionEnd + +Function ReadPreviousVersion + + ReadRegStr $PREVIOUS_INSTALLDIR HKLM "${AppRegistryKeyPath}" "" + + Call CheckPrevInstallDirExists + + ${If} $PREVIOUS_INSTALLDIR != "" + ; Detect version + ReadRegStr $PREVIOUS_VERSION HKLM "${AppRegistryKeyPath}" "Version" + ${If} $PREVIOUS_VERSION != "" + StrCpy $ALL_USERS 1 + SetShellVarContext all + return + ${EndIf} + ${EndIf} + + ReadRegStr $PREVIOUS_INSTALLDIR HKCU "${AppRegistryKeyPath}" "" + + Call CheckPrevInstallDirExists + + ${If} $PREVIOUS_INSTALLDIR != "" + ; Detect version + ReadRegStr $PREVIOUS_VERSION HKCU "${AppRegistryKeyPath}" "Version" + ${If} $PREVIOUS_VERSION != "" + StrCpy $ALL_USERS 0 + SetShellVarContext current + return + ${EndIf} + ${EndIf} + +FunctionEnd + +Function LoadPreviousSettings + + ; Component selection + ;${MementoSectionRestore} + + ; Startmenu + !define ID "Application" + + !ifdef MUI_STARTMENUPAGE_${ID}_REGISTRY_ROOT & MUI_STARTMENUPAGE_${ID}_REGISTRY_KEY & MUI_STARTMENUPAGE_${ID}_REGISTRY_VALUENAME + + ReadRegStr $mui.StartMenuPage.RegistryLocation "${MUI_STARTMENUPAGE_${ID}_REGISTRY_ROOT}" "${MUI_STARTMENUPAGE_${ID}_REGISTRY_KEY}" "${MUI_STARTMENUPAGE_${ID}_REGISTRY_VALUENAME}" + + ${if} $mui.StartMenuPage.RegistryLocation != "" + StrCpy "$STARTMENU_FOLDER" $mui.StartMenuPage.RegistryLocation + ${else} + StrCpy "$STARTMENU_FOLDER" "" + ${endif} + + !undef ID + + !endif + + ${If} $PREVIOUS_INSTALLDIR != "" + StrCpy $INSTDIR $PREVIOUS_INSTALLDIR + ${EndIf} + +FunctionEnd + +Function ReadUpdateCommandline + + ${GetOptions} $CommandLine "/update" $R1 + + ${If} ${Errors} + StrCpy $PERFORM_UPDATE 0 + ${Else} + StrCpy $PERFORM_UPDATE 1 + ${EndIf} + +FunctionEnd + +Function ReadSkipLicense + + ${GetOptions} $CommandLine "/skiplicense" $R1 + + ${If} ${Errors} + StrCpy $SKIPLICENSE 0 + ${Else} + StrCpy $SKIPLICENSE 1 + ${EndIf} + +FunctionEnd + +Function ReadSkipUAC + + ${GetOptions} $CommandLine "/skipuac" $R1 + + ${If} ${Errors} + StrCpy $SKIPUAC 0 + ${Else} + StrCpy $SKIPUAC 1 + ${EndIf} + +FunctionEnd + +Function ReadQuiet + + ${GetOptions} $CommandLine "/quiet" $R1 + + ${If} ${Errors} + StrCpy $Quiet 0 + ${Else} + StrCpy $Quiet 1 + SetSilent silent + ${EndIf} + +FunctionEnd + +Function .onInit + + Pop $OldRunDir + + ; Store command line + ${GetParameters} $CommandLine + + Call ReadQuiet + + ${Unless} ${AtLeastWin7} + ${MessageBox} MB_YESNO|MB_ICONSTOP "Unsupported operating system.$\nStatus Desktop ${VERSION} requires at least Windows 7 and may not work correctly on your system.$\nDo you really want to continue with the installation?" IDNO 'IDYES installonoldwindows' + Abort +installonoldwindows: + ${EndUnless} + ${Unless} ${RunningX64} + ${MessageBox} MB_OK|MB_ICONSTOP "Unsupported operating system.$\nThis is the installer for the 64bit version of Status Desktop ${VERSION} and does not run on your operating system which is only 32bit." IDOK '' + Abort + ${EndUnless} + + Call ReadSkipUAC + + ${If} $SKIPUAC != 1 +uac_tryagain: + !insertmacro UAC_RunElevated + + ${Switch} $0 + ${Case} 0 + ${IfThen} $1 = 1 ${|} Quit ${|} ;we are the outer process, the inner process has done its work, we are done. + ${IfThen} $3 <> 0 ${|} ${Break} ${|} ;we are admin, let the show go on + ${If} $2 = 3 ;RunAs completed successfully, but with a non-admin user + MessageBox MB_YESNO|MB_ICONEXCLAMATION|MB_TOPMOST|MB_SETFOREGROUND "Status Desktop setup requires admin privileges, try again" /SD IDNO IDYES uac_tryagain IDNO 0 + ${EndIf} + ;fall-through and die + ${Case} 1223 + ; User aborted elevation, continue regardless + ${Break} + ${Default} + ${MessageBox} mb_iconstop "Could not elevate process (errorcode $0), continuing with normal user privileges." IDOK '' + ${Break} + ${EndSwitch} + + ; The UAC plugin changes the error level even in the inner process, reset it. + SetErrorLevel -1 + ${EndIf} + + ; /update argument + Call ReadUpdateCommandline + + Call ReadSkipLicense + + Call GetUserInfo + + ; Initialize $ALL_USERS with default value + ${If} $IS_ADMIN == 1 + StrCpy $ALL_USERS 1 + ${Else} + StrCpy $ALL_USERS 0 + ${EndIf} + Call UpdateShellVarContext + + ; See if previous version exists + ; This can change ALL_USERS + Call ReadPreviousVersion + + ${If} $PREVIOUS_VERSION != "" + StrCpy $REINSTALL_UNINSTALL 1 + ${EndIf} + + ; Load _all_ previous settings. + ; Need to do it now as up to now, $ALL_USERS was possibly reflecting a + ; previous installation. After this call, $ALL_USERS reflects the requested + ; installation mode for this installation. + Call LoadPreviousSettings + + Call ReadAllUsersCommandline + + ${If} $ALL_USERS == 1 + ${If} $IS_ADMIN == 0 + + ${If} $PREVIOUS_VERSION != "" + ${MessageBox} MB_ICONSTOP "Status Desktop has been previously installed for all users.$\nPlease restart the installer with Administrator privileges." IDOK '' + Abort + ${Else} + ${MessageBox} MB_ICONSTOP "Cannot install for all users.$\nPlease restart the installer with Administrator privileges." IDOK '' + Abort + ${EndIf} + ${EndIf} + ${EndIf} + + ${If} $PREVIOUS_VERSION == "" + + StrCpy $PERFORM_UPDATE 0 + DetailPrint "No previous version of Status Desktop was found" + + ${Else} + + Push "${VERSION}" + Push $PREVIOUS_VERSION + Call StatusVersionCompare + + DetailPrint "Found previous version: $PREVIOUS_VERSION" + DetailPrint "Installing $PREVIOUS_VERSION_STATE version ${VERSION}" + + ${EndIf} + + StrCpy $ALL_USERS_DEFAULT $ALL_USERS + +FunctionEnd + +Function StatusVersionCompare + + Exch $1 + Exch + Exch $0 + + Push $2 + Push $3 + Push $4 + +versioncomparebegin: + ${If} $0 == "" + ${AndIf} $1 == "" + StrCpy $PREVIOUS_VERSION_STATE "same" + goto versioncomparedone + ${EndIf} + + StrCpy $2 0 + StrCpy $3 0 + + ; Parse rc / beta suffixes for segments + StrCpy $4 $0 2 + ${If} $4 == "rc" + StrCpy $2 100 + StrCpy $0 $0 "" 2 + ${Else} + StrCpy $4 $0 4 + ${If} $4 == "beta" + StrCpy $0 $0 "" 4 + ${Else} + StrCpy $2 10000 + ${EndIf} + ${EndIf} + + StrCpy $4 $1 2 + ${If} $4 == "rc" + StrCpy $3 100 + StrCpy $1 $1 "" 2 + ${Else} + StrCpy $4 $1 4 + ${If} $4 == "beta" + StrCpy $1 $1 "" 4 + ${Else} + StrCpy $3 10000 + ${EndIf} + ${EndIf} + +split1loop: + + StrCmp $0 "" split1loopdone + StrCpy $4 $0 1 + StrCpy $0 $0 "" 1 + StrCmp $4 "." split1loopdone + StrCmp $4 "-" split1loopdone + StrCpy $2 $2$4 + goto split1loop +split1loopdone: + +split2loop: + + StrCmp $1 "" split2loopdone + StrCpy $4 $1 1 + StrCpy $1 $1 "" 1 + StrCmp $4 "." split2loopdone + StrCmp $4 "-" split2loopdone + StrCpy $3 $3$4 + goto split2loop +split2loopdone: + + ${If} $2 > $3 + StrCpy $PREVIOUS_VERSION_STATE "newer" + ${ElseIf} $3 > $2 + StrCpy $PREVIOUS_VERSION_STATE "older" + ${Else} + goto versioncomparebegin + ${EndIf} + + +versioncomparedone: + + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 + +FunctionEnd + +Function PageDirectoryPre + + ${If} $PERFORM_UPDATE == 1 + Abort + ${EndIf} + + ${If} $REINSTALL_UNINSTALL == "1" + ${AndIf} $PREVIOUS_VERSION_STATE != "same" + + Abort + + ${EndIf} + +FunctionEnd + +Function PageStartmenuPre + + ${If} $PERFORM_UPDATE == 1 + Abort + ${EndIf} + + ${If} $REINSTALL_UNINSTALL == "1" + ${AndIf} $PREVIOUS_VERSION_STATE != "same" + + ${If} "$STARTMENU_FOLDER" == "" + + StrCpy "$STARTMENU_FOLDER" ">" + + ${EndIf} + + Abort + + ${EndIf} + +FunctionEnd + +Function .OnInstFailed +FunctionEnd + +Function .onInstSuccess + + ;${MementoSectionSave} + + + ; Detect multiple install directories + ${If} $OldRunDir != '' + ${GetFileVersion} $OldRunDir $R0 + ${GetFileVersion} "$INSTDIR\${AppExeName}" $R1 + + StrCpy $R2 $OldRunDir -14 + + ${If} $R0 != '' + ${AndIf} $R1 != '' + ${AndIf} $R0 != $R1 + ${MessageBox} MB_ICONEXCLAMATION 'Multiple installations of Status Desktop detected.$\n$\nStatus Desktop ${VERSION} has been installed to "$InstDir".$\nAn old installation of Status Desktop $R0 still exists in the "$R2" directory.$\n$\nPlease delete the old version in the "$R2" directory.' IDOK '' + ${EndIf} + ${EndIf} + +FunctionEnd + +;-------------------------------- +; Languages +;-------------------------------- + + !insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +;Installer Sections +;-------------------------------- + +Section "Status Desktop" SecMain + + ;SectionIn 1 RO + + ${nsProcess::FindProcess} "${NodeJsServerExeName}" $R0 + + ${If} $R0 == 0 + DetailPrint "${NodeJsServerExeName} is running. Closing it down" + ${nsProcess::CloseProcess} "${NodeJsServerExeName}" $R0 + DetailPrint "Waiting for ${NodeJsServerExeName} to close" + Sleep 2000 + ${Else} + DetailPrint "${NodeJsServerExeName} was not found to be running" + ${EndIf} + + ${nsProcess::Unload} + + SetOutPath "$INSTDIR" + + File "${top_srcdir}\.env" + File "${top_srcdir}\node_modules\node-notifier\vendor\snoreToast\SnoreToast.exe" + File /r "${top_srcdir}\desktop\bin\" + File /r "${top_srcdir}\StatusImPackage\Windows\" + + SetOutPath "$INSTDIR\notifier" + File "${top_srcdir}\node_modules\node-notifier\vendor\notifu\*.exe" + + SetOutPath "$INSTDIR\assets\resources\fonts" + File /r "${top_srcdir}\resources\fonts\" + + SetOutPath "$INSTDIR\assets\resources\icons" + File /r "${top_srcdir}\resources\icons\" + + SetOutPath "$INSTDIR\assets\resources\images" + File /r "${top_srcdir}\resources\images\" + + ;Create uninstaller + WriteUninstaller "$INSTDIR\${UninstallExeName}" + + WriteRegStr SHCTX "${AppRegistryKeyPath}" "" $INSTDIR + WriteRegStr SHCTX "${AppRegistryKeyPath}" "Version" "${VERSION}" + + WriteRegDWORD SHCTX "${AppRegistryKeyPath}" "Updated" $PERFORM_UPDATE + + ${StrRep} $R0 "$INSTDIR\${UninstallExeName}" '"' '""' + WriteRegExpandStr SHCTX "${UninstallRegKeyPath}" "UninstallString" '"$R0"' + WriteRegExpandStr SHCTX "${UninstallRegKeyPath}" "InstallLocation" "$INSTDIR" + WriteRegStr SHCTX "${UninstallRegKeyPath}" "DisplayName" "Status Desktop ${VERSION}" + WriteRegStr SHCTX "${UninstallRegKeyPath}" "DisplayIcon" "$INSTDIR\${AppExeName}" + WriteRegStr SHCTX "${UninstallRegKeyPath}" "DisplayVersion" "${VERSION}" + WriteRegStr SHCTX "${UninstallRegKeyPath}" "URLInfoAbout" "${WEBSITE_URL}" + WriteRegStr SHCTX "${UninstallRegKeyPath}" "URLUpdateInfo" "${WEBSITE_URL}" + WriteRegStr SHCTX "${UninstallRegKeyPath}" "HelpLink" "${WEBSITE_URL}" + WriteRegStr SHCTX "${UninstallRegKeyPath}" "Publisher" "${PUBLISHER}" + WriteRegDWORD SHCTX "${UninstallRegKeyPath}" "VersionMajor" "${VERSION_MAJOR}" + WriteRegDWORD SHCTX "${UninstallRegKeyPath}" "VersionMinor" "${VERSION_MINOR}" + WriteRegDWORD SHCTX "${UninstallRegKeyPath}" "NoModify" "1" + WriteRegDWORD SHCTX "${UninstallRegKeyPath}" "NoRepair" "1" + + Call GetInstalledSize + WriteRegDWORD SHCTX "${UninstallRegKeyPath}" "EstimatedSize" "$GetInstalledSize.total" ; Create/Write the reg key with the dword value + + ;Add applications to the firewall exception list - All Networks - All IP Version - Enabled + SimpleFC::IsApplicationAdded "$INSTDIR\${AppExeName}" + Pop $0 ; return error(1)/success(0) + ${if} $0 == "0" + Pop $1 ; return 1=Added/0=Not added + ${if} $1 == "0" + ; SimpleFC::AddApplication [name] [path] [scope] [ip_version] [remote_addresses] [status] + SimpleFC::AddApplication "Status Desktop Ethereum Node" "$INSTDIR\${AppExeName}" 0 2 "" 1 + SimpleFC::AddApplication "Status Desktop Node.js Server" "$INSTDIR\${NodeJsServerExeName}" 1 2 "" 1 + ${endif} + ${endif} + + !insertmacro MUI_STARTMENU_WRITE_BEGIN Application + + ;Create shortcuts + SetOutPath "$INSTDIR" + CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${UninstallLinkName}" "$INSTDIR\${UninstallExeName}" + + ;CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${AppLinkFileName}" "$INSTDIR\${AppExeName}" + !insertmacro SnoreShortcut "$SMPROGRAMS\$STARTMENU_FOLDER\${AppLinkFileName}" "$INSTDIR\${AppExeName}" "${AppUserModelId}" + + !insertmacro MUI_STARTMENU_WRITE_END + + ; Push $R0 + ; StrCpy $R0 "$STARTMENU_FOLDER" 1 + ; ${if} $R0 == ">" + ; ;Write folder to registry + ; WriteRegStr "${MUI_STARTMENUPAGE_Application_REGISTRY_ROOT}" "${MUI_STARTMENUPAGE_Application_REGISTRY_KEY}" "${MUI_STARTMENUPAGE_Application_REGISTRY_VALUENAME}" ">" + ; ${endif} + ; Pop $R0 + + ${If} $ALL_USERS == 1 + ; Enable mini dumps + ${If} ${RunningX64} + SetRegView 64 + ${EndIf} + WriteRegDWORD HKLM "${DUMP_KEY}\${AppExeName}" "DumpType" "1" + WriteRegDWORD HKLM "${DUMP_KEY}\${NodeJsServerExeName}" "DumpType" "1" + ${If} ${RunningX64} + SetRegView lastused + ${EndIf} + ${EndIf} + + ; Register App Path so that typing status in Win+R dialog starts Status Desktop + WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\App Paths\${AppExeName}" "" "$INSTDIR\${AppExeName}" + WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\App Paths\${AppExeName}" "Path" "$INSTDIR" + +SectionEnd + +;-------------------------------- +; Functions +;-------------------------------- + +Function PostInstPage + + ; Don't advance automatically if details expanded + FindWindow $R0 "#32770" "" $HWNDPARENT + GetDlgItem $R0 $R0 1016 + System::Call user32::IsWindowVisible(i$R0)i.s + Pop $R0 + + ${If} $R0 != 0 + SetAutoClose false + ${EndIf} + +FunctionEnd + +Function GetInstalledSize + Push $0 + Push $1 + StrCpy $GetInstalledSize.total 0 + ${ForEach} $1 0 256 + 1 + ${if} ${SectionIsSelected} $1 + SectionGetSize $1 $0 + IntOp $GetInstalledSize.total $GetInstalledSize.total + $0 + ${Endif} + ${Next} + Pop $1 + Pop $0 + IntFmt $GetInstalledSize.total "0x%08X" $GetInstalledSize.total + Push $GetInstalledSize.total +FunctionEnd + +;-------------------------------- +; Descriptions +;-------------------------------- + + ; Language strings + LangString DESC_SecMain ${LANG_ENGLISH} "Required program files." + ;LangString DESC_SecDesktop ${LANG_ENGLISH} "Create desktop icon for FileZilla" + + ; Assign language strings to sections + !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${SecMain} $(DESC_SecMain) + ;!insertmacro MUI_DESCRIPTION_TEXT ${SecDesktop} $(DESC_SecDesktop) + !insertmacro MUI_FUNCTION_DESCRIPTION_END + +;-------------------------------- +; Uninstaller Variables +;-------------------------------- + +Var un.REMOVE_ALL_USERS +Var un.REMOVE_CURRENT_USER + +;-------------------------------- +;Uninstaller Functions +;-------------------------------- + +Function un.GetUserInfo + ClearErrors + UserInfo::GetName + ${If} ${Errors} + StrCpy $IS_ADMIN 1 + Return + ${EndIf} + Pop $USERNAME + + ${If} ${UAC_IsAdmin} + StrCpy $IS_ADMIN 1 + ${Else} + StrCpy $IS_ADMIN 0 + ${EndIf} + +FunctionEnd + +Function un.ReadPreviousVersion + + ReadRegStr $R0 HKLM "${AppRegistryKeyPath}" "" + + ${If} $R0 != "" + ;Detect version + ReadRegStr $R2 HKLM "${AppRegistryKeyPath}" "Version" + ${If} $R2 == "" + StrCpy $R0 "" + ${EndIf} + ${EndIf} + + ReadRegStr $R1 HKCU "${AppRegistryKeyPath}" "" + + ${If} $R1 != "" + ;Detect version + ReadRegStr $R2 HKCU "${AppRegistryKeyPath}" "Version" + ${If} $R2 == "" + StrCpy $R1 "" + ${EndIf} + ${EndIf} + + ${If} $R1 == $INSTDIR + Strcpy $un.REMOVE_CURRENT_USER 1 + ${EndIf} + ${If} $R0 == $INSTDIR + Strcpy $un.REMOVE_ALL_USERS 1 + ${EndIf} + ${If} $un.REMOVE_CURRENT_USER != 1 + ${AndIf} $un.REMOVE_ALL_USERS != 1 + ${If} $R1 != "" + Strcpy $un.REMOVE_CURRENT_USER 1 + ${If} $R0 == $R1 + Strcpy $un.REMOVE_ALL_USERS 1 + ${EndIf} + ${Else} + StrCpy $un.REMOVE_ALL_USERS = 1 + ${EndIf} + ${EndIf} + +FunctionEnd + +Function un.onInit + + ${un.GetParameters} $CommandLine + + ${un.GetOptions} $CommandLine "/quiet" $R1 + ${If} ${Errors} + StrCpy $Quiet 0 + ${Else} + StrCpy $Quiet 1 + SetSilent silent + ${EndIf} + + Call un.GetUserInfo + Call un.ReadPreviousVersion + + ${If} $un.REMOVE_ALL_USERS == 1 + ${AndIf} $IS_ADMIN == 0 +uac_tryagain: + !insertmacro UAC_RunElevated + + ${Switch} $0 + ${Case} 0 + ${IfThen} $1 = 1 ${|} Quit ${|} ;we are the outer process, the inner process has done its work, we are done. + ${IfThen} $3 <> 0 ${|} ${Break} ${|} ;we are admin, let the show go on + ${If} $2 = 3 ;RunAs completed successfully, but with a non-admin user + MessageBox MB_YESNO|MB_ICONEXCLAMATION|MB_TOPMOST|MB_SETFOREGROUND "Status Desktop setup requires admin privileges, try again" /SD IDNO IDYES uac_tryagain IDNO 0 + Abort + ${EndIf} + ;fall-through and die + ${Default} + ${MessageBox} MB_ICONSTOP "Status Desktop has been installed for all users.$\nPlease restart the uninstaller with Administrator privileges to remove it." IDOK '' + Abort + ${EndSwitch} + + ; The UAC plugin changes the error level even in the inner process, reset it. + SetErrorLevel -1 + ${EndIf} + +FunctionEnd + +Function un.RemoveStartmenu + + !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP + + Delete "$SMPROGRAMS\$MUI_TEMP\${UninstallLinkName}" + Delete "$SMPROGRAMS\$MUI_TEMP\${AppLinkFileName}" + + ${un.GetOptions} $CommandLine "/keepstartmenudir" $R1 + ${If} ${Errors} + + ; Delete empty start menu parent diretories + StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" + + startMenuDeleteLoop: + RMDir $MUI_TEMP + GetFullPathName $MUI_TEMP "$MUI_TEMP\.." + + IfErrors startMenuDeleteLoopDone + + StrCmp $MUI_TEMP $SMPROGRAMS startMenuDeleteLoopDone startMenuDeleteLoop + startMenuDeleteLoopDone: + + ${EndUnless} + +FunctionEnd + +Function un.ConfirmPagePre + + ${un.GetOptions} $CommandLine "/frominstall" $R1 + ${Unless} ${Errors} + Abort + ${EndUnless} + +FunctionEnd + +Function un.FinishPagePre + + ${un.GetOptions} $CommandLine "/frominstall" $R1 + ${Unless} ${Errors} + SetRebootFlag false + Abort + ${EndUnless} + +FunctionEnd + +;-------------------------------- +; Uninstaller Section +;-------------------------------- + +Section "Uninstall" + + SetShellVarContext all + + SetDetailsPrint lastused + + ${nsProcess::FindProcess} "${AppExeName}" $R0 + + ${If} $R0 == 0 + DetailPrint "${AppExeName} is running. Closing it down" + ${nsProcess::CloseProcess} "${AppExeName}" $R0 + DetailPrint "Waiting for ${AppExeName} to close" + Sleep 2000 + ${Else} + DetailPrint "${AppExeName} was not found to be running" + ${EndIf} + + ${nsProcess::FindProcess} "${NodeJsServerExeName}" $R0 + + ${If} $R0 == 0 + DetailPrint "${NodeJsServerExeName} is running. Closing it down" + ${nsProcess::CloseProcess} "${NodeJsServerExeName}" $R0 + DetailPrint "Waiting for ${NodeJsServerExeName} to close" + Sleep 2000 + ${Else} + DetailPrint "${NodeJsServerExeName} was not found to be running" + ${EndIf} + + ${nsProcess::Unload} + + SimpleFC::RemoveApplication "$INSTDIR\${AppExeName}" + SimpleFC::RemoveApplication "$INSTDIR\${NodeJsServerExeName}" + + Delete "$INSTDIR\.env" + Delete "$INSTDIR\*.dll" + Delete "$INSTDIR\${AppExeName}" + Delete "$INSTDIR\reportApp.exe" + Delete "$INSTDIR\vc_redist.x64.exe" + Delete "$INSTDIR\${NodeJsServerExeName}" + Delete "$INSTDIR\${UninstallExeName}" + RMDir /r "$INSTDIR\assets" + Delete "$INSTDIR\bearer\*.dll" + RMDir "$INSTDIR\bearer" + Delete "$INSTDIR\iconengines\*.dll" + RMDir "$INSTDIR\iconengines" + Delete "$INSTDIR\imageformats\*.dll" + RMDir "$INSTDIR\imageformats" + RMDir /r "$INSTDIR\node_modules" + Delete "$INSTDIR\notifier\*.exe" + RMDir "$INSTDIR\notifier" + Delete "$INSTDIR\platforms\*.dll" + RMDir "$INSTDIR\platforms" + RMDir /r "$INSTDIR\QtGraphicalEffects" + RMDir /r "$INSTDIR\QtQml" + RMDir /r "$INSTDIR\QtQuick" + RMDir /r "$INSTDIR\QtQuick.2" + RMDir /r "$INSTDIR\QtWebSockets" + Delete "$INSTDIR\styles\*.dll" + RMDir "$INSTDIR\styles" + Delete "$INSTDIR\translations\*.qm" + RMDir "$INSTDIR\translations" + + Delete "$INSTDIR" + + ${un.GetOptions} $CommandLine "/frominstall" $R1 + ${If} ${Errors} + RMDir /r /REBOOTOK "$INSTDIR" + + DeleteRegValue SHCTX "${AppRegistryKeyPath}" "Package" + DeleteRegValue SHCTX "${AppRegistryKeyPath}" "Updated" + DeleteRegValue SHCTX "${AppRegistryKeyPath}" "Channel" + ${EndIf} + + ${If} $un.REMOVE_ALL_USERS == 1 + SetShellVarContext all + Call un.RemoveStartmenu + + DeleteRegKey /ifempty HKLM "${AppRegistryKeyPath}" + DeleteRegKey /ifempty HKLM "${OrgRegistryKeyPath}" + DeleteRegKey HKLM "${UninstallRegKeyPath}" + + Delete "$DESKTOP\${AppLinkFileName}" + + ; Remove dump key + ${If} ${RunningX64} + SetRegView 64 + ${EndIf} + DeleteRegValue HKLM "${DUMP_KEY}\${AppExeName}" "DumpType" + DeleteRegValue HKLM "${DUMP_KEY}\${NodeJsServerExeName}" "DumpType" + ${If} ${RunningX64} + SetRegView lastused + ${EndIf} + ${EndIf} + + ${If} $un.REMOVE_CURRENT_USER == 1 + SetShellVarContext current + Call un.RemoveStartmenu + + DeleteRegKey /ifempty HKCU "${AppRegistryKeyPath}" + DeleteRegKey /ifempty HKCU "${OrgRegistryKeyPath}" + DeleteRegKey HKCU "${UninstallRegKeyPath}" + + Delete "$DESKTOP\${AppLinkFileName}" + ${EndIf} + + DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\App Paths\${AppExeName}" + +SectionEnd diff --git a/desktop/CMakeModules/CompleteBundleWin.cmake.in b/desktop/CMakeModules/CompleteBundleWin.cmake.in index 23f3017924..56a03ae712 100644 --- a/desktop/CMakeModules/CompleteBundleWin.cmake.in +++ b/desktop/CMakeModules/CompleteBundleWin.cmake.in @@ -1,6 +1,12 @@ # windeployqt should be used here, but since we get the `Not implemented` error from it, we're trying to manually copy artifacts to output directory set(TARGET_DIR "${@APP_NAME@_BINARY_DIR}") +########################################################################################################## +# +# NOTE: Remember to reflect any changes on the setup generation procedure in /deployment/windows/nsis/setup.nsi +# +########################################################################################################## + set(qtmodules Core Quick QuickTemplates2 QuickControls2 WebSockets Widgets Gui Network Svg Qml Concurrent) if(USE_QTWEBKIT) set(qtmodules ${qtmodules} Multimedia WebKit WebKitWidgets WebChannel) diff --git a/desktop/docker/windows/Dockerfile b/desktop/docker/windows/Dockerfile index 57d313fc34..24e5209540 100644 --- a/desktop/docker/windows/Dockerfile +++ b/desktop/docker/windows/Dockerfile @@ -18,7 +18,7 @@ RUN apt-get update && apt-get -q -y --no-install-recommends install curl softwar apt-get update && \ DEBIAN_FRONTEND=noninteractive \ apt-get -q -y --no-install-recommends install \ - wget git zip unzip golang-go nodejs yarn file jq \ + wget git nsis unzip golang-go nodejs yarn file jq \ python python3-pip python3-setuptools python3-wheel \ apt-transport-https locales openjdk-8-jdk-headless \ extra-cmake-modules build-essential fuse \ diff --git a/desktop/docker/windows/Makefile b/desktop/docker/windows/Makefile index 63d2e6e771..ef42ef0e9c 100644 --- a/desktop/docker/windows/Makefile +++ b/desktop/docker/windows/Makefile @@ -1,7 +1,7 @@ GIT_COMMIT = $(shell git rev-parse --short HEAD) IMAGE_TAG = 1.0.0 -IMAGE_NAME = statusteam/windows-desktop-ubuntu:$(IMAGE_TAG) +IMAGE_NAME = statusteam/windows-desktop-ubuntu:nsis-$(IMAGE_TAG) build: docker build \ diff --git a/desktop/main.cpp b/desktop/main.cpp index 2ce5964d85..1a8f290d1f 100644 --- a/desktop/main.cpp +++ b/desktop/main.cpp @@ -47,7 +47,11 @@ const int MAIN_WINDOW_WIDTH = 1024; const int MAIN_WINDOW_HEIGHT = 768; const QString CRASH_REPORT_EXECUTABLE = QStringLiteral("reportApp"); const QString CRASH_REPORT_EXECUTABLE_RELATIVE_PATH = +#ifdef Q_OS_WIN + QStringLiteral(""); +#else QStringLiteral("/../reportApp"); +#endif const char *ENABLE_LOG_FILE_ENV_VAR_NAME = "STATUS_LOG_FILE_ENABLED"; const char *LOG_FILE_PATH_ENV_VAR_NAME = "STATUS_LOG_PATH"; diff --git a/scripts/build-desktop.sh b/scripts/build-desktop.sh index b0df8a07b5..733df0a538 100755 --- a/scripts/build-desktop.sh +++ b/scripts/build-desktop.sh @@ -213,7 +213,14 @@ function compile() { function bundleWindows() { local buildType="$1" - # TODO: Produce a setup program instead of a ZIP + + local version_file="${STATUSREACTPATH}/desktop_files/VERSION" + VERSION=$(cat $version_file) + if [ -z "$VERSION" ]; then + echo "${RED}Could not read version from ${version_file}!${NC}" + exit 1 + fi + pushd $WORKFOLDER rm -rf Windows mkdir Windows @@ -224,30 +231,33 @@ function bundleWindows() { fi unzip "$STATUSIM_WINDOWS_BASEIMAGE_ZIP" -d Windows/ - rm -f Status-Windows-x86_64.zip - pushd Windows - cp $STATUSREACTPATH/.env . - mkdir -p assets/resources notifier - cp $STATUSREACTPATH/node_modules/node-notifier/vendor/snoreToast/SnoreToast.exe . - cp $STATUSREACTPATH/node_modules/node-notifier/vendor/notifu/*.exe notifier/ - cp -r $STATUSREACTPATH/resources/fonts \ - $STATUSREACTPATH/resources/icons \ - $STATUSREACTPATH/resources/images \ - assets/resources/ - local _bin=$STATUSREACTPATH/desktop/bin - rm -rf $_bin/cmake_install.cmake $_bin/Makefile $_bin/CMakeFiles $_bin/Status_autogen && \ - cp -r $_bin/* . - - local zipOptions="-mr9" - if [ -z $buildType ]; then - zipOptions="-mr1" - elif [ "$buildType" = "pr" ]; then - zipOptions="-mr2" - fi - zip $zipOptions ../../Status-Windows-x86_64.zip . + pushd $STATUSREACTPATH/desktop/bin + rm -rf cmake_install.cmake Makefile CMakeFiles Status_autogen popd - rm -rf Windows popd + + local compressionAlgo="lzma" + local compressionType="/SOLID" + if [ -z $buildType ]; then + compressionAlgo="bzip2" + compressionType="" + elif [ "$buildType" = "pr" ]; then + compressionAlgo="zlib" + fi + + local top_srcdir=$(joinExistingPath "$STATUSREACTPATH" '.') + VERSION_MAJOR="$(cut -d'.' -f1 <<<"$VERSION")" + VERSION_MINOR="$(cut -d'.' -f2 <<<"$VERSION")" + VERSION_BUILD="$(cut -d'.' -f3 <<<"$VERSION")" + makensis -Dtop_srcdir=${top_srcdir} \ + -DCOMPRESSION_ALGO=${compressionAlgo} \ + -DCOMPRESSION_TYPE=${compressionType} \ + -DVERSION_MAJOR=$VERSION_MAJOR \ + -DVERSION_MINOR=$VERSION_MINOR \ + -DVERSION_BUILD=$VERSION_BUILD \ + -DPUBLISHER=Status.im \ + -DWEBSITE_URL="https://status.im/" \ + ./deployment/windows/nsis/setup.nsi } function bundleLinux() { diff --git a/scripts/lib/setup/installers.sh b/scripts/lib/setup/installers.sh index 370d9193e5..cec5a07bd8 100755 --- a/scripts/lib/setup/installers.sh +++ b/scripts/lib/setup/installers.sh @@ -10,6 +10,11 @@ function downloadUrl() { fi } +function install_nsis() { + # NSIS (Nullsoft Scriptable Install System) is a professional open source system to create Windows installers. It is designed to be as small and flexible as possible and is therefore very suitable for internet distribution. + linux_install nsis +} + function install_node() { if nvm_installed; then install_node_via_nvm diff --git a/scripts/setup b/scripts/setup index 7c591ce532..cb2ed82805 100755 --- a/scripts/setup +++ b/scripts/setup @@ -28,6 +28,7 @@ install_wget install_java8 install_clojure_cli install_leiningen +install_nsis install_node install_watchman install_react_native_cli