diff --git a/Gruntfile.js b/Gruntfile.js index c040be48..595a4706 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -178,11 +178,14 @@ module.exports = function(grunt) { dest: 'tmp/desktop/KeeWeb-win32-x64/', nonull: true }, - 'desktop-win32-dist': { - cwd: 'tmp/desktop', - src: ['KeeWeb.win.x64.exe', 'KeeWeb.win.ia32.exe'], - dest: 'dist/desktop/', - expand: true, + 'desktop-win32-dist-x64': { + src: 'tmp/desktop/KeeWeb.win.x64.exe', + dest: `dist/desktop/KeeWeb-${pkg.version}.win.x64.exe`, + nonull: true + }, + 'desktop-win32-dist-ia32': { + src: 'tmp/desktop/KeeWeb.win.ia32.exe', + dest: `dist/desktop/KeeWeb-${pkg.version}.win.ia32.exe`, nonull: true } }, @@ -353,19 +356,19 @@ module.exports = function(grunt) { files: [{ cwd: 'tmp/desktop/app', src: '**', expand: true }] }, 'win32-x64': { - options: { archive: 'dist/desktop/KeeWeb.win.x64.zip' }, + options: { archive: `dist/desktop/KeeWeb-${pkg.version}.win.x64.zip` }, files: [{ cwd: 'tmp/desktop/KeeWeb-win32-x64', src: '**', expand: true }] }, 'win32-ia32': { - options: { archive: 'dist/desktop/KeeWeb.win.ia32.zip' }, + options: { archive: `dist/desktop/KeeWeb-${pkg.version}.win.ia32.zip` }, files: [{ cwd: 'tmp/desktop/KeeWeb-win32-ia32', src: '**', expand: true }] }, 'linux-x64': { - options: { archive: 'dist/desktop/KeeWeb.linux.x64.zip' }, + options: { archive: `dist/desktop/KeeWeb-${pkg.version}.linux.x64.zip` }, files: [{ cwd: 'tmp/desktop/KeeWeb-linux-x64', src: '**', expand: true }] }, 'linux-ia32': { - options: { archive: 'dist/desktop/KeeWeb.linux.ia32.zip' }, + options: { archive: `dist/desktop/KeeWeb-${pkg.version}.linux.ia32.zip` }, files: [{ cwd: 'tmp/desktop/KeeWeb-linux-ia32', src: '**', expand: true }] } }, @@ -383,12 +386,11 @@ module.exports = function(grunt) { ] }, app: { - dest: 'dist/desktop/KeeWeb.mac.dmg' + dest: `dist/desktop/KeeWeb-${pkg.version}.mac.dmg` } }, nsis: { options: { - installScript: 'package/nsis/main.nsi', vars: { version: pkg.version, rev: function() { return grunt.config.get('gitinfo.local.branch.current.shortSHA'); }, @@ -397,15 +399,31 @@ module.exports = function(grunt) { }, 'win32-x64': { options: { + installScript: 'package/nsis/main.nsi', arch: 'x64', output: 'tmp/desktop/KeeWeb.win.x64.exe' } }, + 'win32-un-x64': { + options: { + installScript: 'package/nsis/main-un.nsi', + arch: 'x64', + output: 'tmp/desktop/KeeWeb-win32-x64/uninst.exe' + } + }, 'win32-ia32': { options: { + installScript: 'package/nsis/main.nsi', arch: 'ia32', output: 'tmp/desktop/KeeWeb.win.ia32.exe' } + }, + 'win32-un-ia32': { + options: { + installScript: 'package/nsis/main-un.nsi', + arch: 'ia32', + output: 'tmp/desktop/KeeWeb-win32-ia32/uninst.exe' + } } }, deb: { @@ -423,7 +441,7 @@ module.exports = function(grunt) { info: { arch: 'amd64', targetDir: 'dist/desktop', - pkgName: 'KeeWeb.linux.x64.deb', + pkgName: `KeeWeb-${pkg.version}.linux.x64.deb`, appName: 'KeeWeb', depends: 'libappindicator1', scripts: { @@ -488,16 +506,54 @@ module.exports = function(grunt) { keytarPasswordService: 'code-sign-win32-keeweb', keytarPasswordAccount: 'code-sign-win32-keeweb' }, + 'win32-build-x64': { + options: { + files: { + 'tmp/desktop/KeeWeb-win32-x64/KeeWeb.exe': 'KeeWeb', + 'tmp/desktop/KeeWeb-win32-x64/ffmpeg.dll': '', + 'tmp/desktop/KeeWeb-win32-x64/libEGL.dll': 'ANGLE libEGL Dynamic Link Library', + 'tmp/desktop/KeeWeb-win32-x64/libGLESv2.dll': 'ANGLE libGLESv2 Dynamic Link Library', + 'tmp/desktop/KeeWeb-win32-x64/node.dll': 'Node.js' + } + } + }, + 'win32-build-ia32': { + options: { + files: { + 'tmp/desktop/KeeWeb-win32-ia32/KeeWeb.exe': 'KeeWeb', + 'tmp/desktop/KeeWeb-win32-ia32/ffmpeg.dll': '', + 'tmp/desktop/KeeWeb-win32-ia32/libEGL.dll': 'ANGLE libEGL Dynamic Link Library', + 'tmp/desktop/KeeWeb-win32-ia32/libGLESv2.dll': 'ANGLE libGLESv2 Dynamic Link Library', + 'tmp/desktop/KeeWeb-win32-ia32/node.dll': 'Node.js' + } + } + }, + 'win32-uninst-x64': { + options: { + files: { + 'tmp/desktop/KeeWeb-win32-x64/uninst.exe': 'KeeWeb Uninstaller' + } + } + }, + 'win32-uninst-ia32': { + options: { + files: { + 'tmp/desktop/KeeWeb-win32-ia32/uninst.exe': 'KeeWeb Uninstaller' + } + } + }, 'win32-installer-x64': { options: { - file: 'tmp/desktop/KeeWeb.win.x64.exe', - name: 'KeeWeb Setup' + files: { + 'tmp/desktop/KeeWeb.win.x64.exe': 'KeeWeb Setup' + } } }, 'win32-installer-ia32': { options: { - file: 'tmp/desktop/KeeWeb.win.ia32.exe', - name: 'KeeWeb Setup' + files: { + 'tmp/desktop/KeeWeb.win.ia32.exe': 'KeeWeb Setup' + } } } }, @@ -547,6 +603,8 @@ module.exports = function(grunt) { grunt.registerTask('build-desktop-executables', [ 'electron', + 'sign-exe:win32-build-x64', + 'sign-exe:win32-build-ia32', 'copy:desktop-windows-helper-ia32', 'copy:desktop-windows-helper-x64' ]); @@ -563,11 +621,16 @@ module.exports = function(grunt) { ]); grunt.registerTask('build-desktop-dist-win32', [ + 'nsis:win32-un-x64', + 'nsis:win32-un-ia32', + 'sign-exe:win32-uninst-x64', + 'sign-exe:win32-uninst-ia32', 'nsis:win32-x64', 'nsis:win32-ia32', 'sign-exe:win32-installer-x64', 'sign-exe:win32-installer-ia32', - 'copy:desktop-win32-dist' + 'copy:desktop-win32-dist-x64', + 'copy:desktop-win32-dist-ia32' ]); grunt.registerTask('build-desktop-dist-linux', [ diff --git a/grunt/tasks/grunt-nsis.js b/grunt/tasks/grunt-nsis.js index 1d9288fb..3c4de6ce 100644 --- a/grunt/tasks/grunt-nsis.js +++ b/grunt/tasks/grunt-nsis.js @@ -12,11 +12,14 @@ module.exports = function (grunt) { if (typeof value === 'function') { value = value(); } - args.push(`${prefix}D${key}=${value}`); + if (value) { + args.push(`${prefix}D${key}=${value}`); + } }); args.push(`${prefix}Darch=${opt.arch}`); args.push(`${prefix}Doutput=${opt.output}`); args.push(`${prefix}NOCD`); + args.push(`${prefix}V2`); args.push(opt.installScript); let executable = win ? 'C:\\Program Files (x86)\\NSIS\\makensis.exe' : 'makensis'; grunt.log.writeln('Running NSIS:', args.join(' ')); diff --git a/grunt/tasks/grunt-sign-exe.js b/grunt/tasks/grunt-sign-exe.js index 04429350..e239ed2e 100644 --- a/grunt/tasks/grunt-sign-exe.js +++ b/grunt/tasks/grunt-sign-exe.js @@ -2,6 +2,8 @@ // https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Signing_an_executable_with_Authenticode +const fs = require('fs'); + module.exports = function (grunt) { grunt.registerMultiTask('sign-exe', 'Signs exe file with authenticode certificate', function () { const keytar = require('keytar'); @@ -11,30 +13,44 @@ module.exports = function (grunt) { if (!password) { return grunt.warn('Code sign password not found'); } - let spawned = grunt.util.spawn({ - cmd: 'signcode', - args: [ + let promises = Object.keys(opt.files).map(file => signFile(file, opt.files[file], opt, password)); + Promise.all(promises).then(done); + }); + + function signFile(file, name, opt, password) { + let signedFile = file + '.sign'; + return new Promise((resolve, reject) => { + let args = [ '-spc', opt.spc, - '-v', opt.pvk, - '-a', opt.algo, - '-$', 'commercial', - '-n', opt.name, + '-key', require('path').resolve(opt.pvk), + '-h', opt.algo, + '-n', name, '-i', opt.url, '-t', 'http://timestamp.verisign.com/scripts/timstamp.dll', - '-tr', 10, - opt.file - ] - }, (error, result, code) => { - if (error || code) { - spawned.kill(); - return grunt.warn(`signtool error ${code}: ${error}`); - } - done(); + '-pass', password, + '-in', file, + '-out', signedFile + ]; + let spawned = grunt.util.spawn({ + cmd: 'osslsigncode', + args: args + }, (error, result, code) => { + if (error || code) { + spawned.kill(); + grunt.warn(`Cannot sign file ${file}, signtool error ${code}: ${error}`); + return reject(); + } + if (fs.existsSync(file)) { + fs.renameSync(signedFile, file); + } + grunt.log.writeln(`Signed: ${file}: ${name}`); + resolve(); + }); + // spawned.stdout.pipe(process.stdout); + spawned.stderr.pipe(process.stderr); + // spawned.stdin.setEncoding('utf-8'); + // spawned.stdin.write(password); + // spawned.stdin.write('\n'); }); - spawned.stdout.pipe(process.stdout); - spawned.stderr.pipe(process.stderr); - spawned.stdin.setEncoding('utf-8'); - spawned.stdin.write(password); - spawned.stdin.write('\n'); - }); + } }; diff --git a/package/nsis/check-running.nsh b/package/nsis/check-running.nsh old mode 100644 new mode 100755 index e33d1c6b..d709516d --- a/package/nsis/check-running.nsh +++ b/package/nsis/check-running.nsh @@ -1,21 +1,21 @@ -!macro EnsureAppIsNotRunning - ${Do} - nsExec::ExecToStack /OEM 'tasklist /NH /FI "IMAGENAME eq ${PRODUCT_EXE}"' - Pop $0 - ${If} $0 != 0 - DetailPrint "Error checking ${PRODUCT_EXE}: $0" - MessageBox MB_ICONSTOP|MB_OK "Failed to check whether process is running" - Quit - ${EndIf} - Pop $1 - ${StrContains} $0 "${PRODUCT_EXE}" $1 - ${If} $0 == "" - DetailPrint "${PRODUCT_EXE} is not running" - ${ExitDo} - ${Else} - MessageBox MB_ICONQUESTION|MB_OKCANCEL|MB_DEFBUTTON1 "To proceed, please close ${PRODUCT_NAME} and click OK" /SD IDCANCEL IDOK ok - Quit - ok: - ${EndIf} - ${Loop} -!macroend +!macro EnsureAppIsNotRunning + ${Do} + nsExec::ExecToStack /OEM 'tasklist /NH /FI "IMAGENAME eq ${PRODUCT_EXE}"' + Pop $0 + ${If} $0 != 0 + DetailPrint "Error checking ${PRODUCT_EXE}: $0" + MessageBox MB_ICONSTOP|MB_OK "Failed to check whether process is running" /SD IDOK + Quit + ${EndIf} + Pop $1 + ${StrStr} $0 $1 "${PRODUCT_EXE}" + ${If} $0 == "" + DetailPrint "${PRODUCT_EXE} is not running" + ${ExitDo} + ${Else} + MessageBox MB_ICONQUESTION|MB_OKCANCEL|MB_DEFBUTTON1 "To proceed, please close ${PRODUCT_NAME} and click OK" /SD IDCANCEL IDOK ok + Quit + ok: + ${EndIf} + ${Loop} +!macroend diff --git a/package/nsis/config.nsh b/package/nsis/config.nsh deleted file mode 100644 index 29d9c5c4..00000000 --- a/package/nsis/config.nsh +++ /dev/null @@ -1,5 +0,0 @@ -Name "${PRODUCT_NAME}" -OutFile "${output}" -InstallDir "$PROGRAMFILES\KeeWeb" -ShowInstDetails show -ShowUnInstDetails show diff --git a/package/nsis/defines.nsh b/package/nsis/defines.nsh old mode 100644 new mode 100755 index 6cc7584c..eab30481 --- a/package/nsis/defines.nsh +++ b/package/nsis/defines.nsh @@ -1,18 +1,22 @@ -!define PRODUCT_NAME "KeeWeb" -!define PRODUCT_VERSION "${version}" -!define PRODUCT_PUBLISHER "KeeWeb" -!define PRODUCT_WEB_SITE "${homepage}" -!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" -!define PRODUCT_UNINST_ROOT_KEY "HKLM" +!define PRODUCT_NAME "KeeWeb" +!define PRODUCT_VERSION "${version}" +!define PRODUCT_PUBLISHER "KeeWeb" +!define PRODUCT_WEB_SITE "${homepage}" +!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" +!define PRODUCT_UNINST_ROOT_KEY "HKLM" !define PRODUCT_EXE "KeeWeb.exe" - -!define MUI_ABORTWARNING +!define PRODUCT_UNINST_TEMP_EXE "KeeWebUninst.exe" + +!define MUI_ABORTWARNING !define MUI_ICON "graphics\icon.ico" -!define MUI_UNICON "graphics\icon.ico" -!define MUI_FINISHPAGE_RUN "$INSTDIR\KeeWeb.exe" - -!define MULTIUSER_EXECUTIONLEVEL Highest -!define MULTIUSER_MUI -!define MULTIUSER_INSTALLMODE_COMMANDLINE +!define MUI_FINISHPAGE_RUN "$INSTDIR\${PRODUCT_EXE}" +!define MULTIUSER_EXECUTIONLEVEL Highest +!define MULTIUSER_MUI +!define MULTIUSER_INSTALLMODE_COMMANDLINE + SetCompressor lzma +Name "${PRODUCT_NAME}" +OutFile "${output}" +InstallDir "$PROGRAMFILES\${PRODUCT_NAME}" +ShowInstDetails show diff --git a/package/nsis/includes.nsh b/package/nsis/includes.nsh old mode 100644 new mode 100755 index 7ff2138a..eebcc595 --- a/package/nsis/includes.nsh +++ b/package/nsis/includes.nsh @@ -1,10 +1,10 @@ -!include MultiUser.nsh -!include MUI2.nsh -!include Util.nsh -!include x64.nsh -!include nsDialogs.nsh +!include MultiUser.nsh +!include MUI2.nsh +!include Util.nsh +!include x64.nsh +!include nsDialogs.nsh !include LogicLib.nsh +!include StrFunc.nsh !include WinVer.nsh - + !include package\nsis\lib\FileAssoc.nsh -!include package\nsis\lib\StrContains.nsh diff --git a/package/nsis/install.nsh b/package/nsis/install.nsh old mode 100644 new mode 100755 index 6e757a05..3a74563c --- a/package/nsis/install.nsh +++ b/package/nsis/install.nsh @@ -1,71 +1,82 @@ +!insertmacro MUI_PAGE_WELCOME +#!insertmacro MULTIUSER_PAGE_INSTALLMODE +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_PAGE_FINISH + +!insertmacro MUI_LANGUAGE "English" + Function .onInit - ${If} ${RunningX64} - ${If} ${arch} == "x64" - SetRegView 64 - StrCpy $InstDir "$PROGRAMFILES64\KeeWeb" - ${Else} - MessageBox MB_ICONSTOP|MB_OK "Please use 64-bit installer on 64-bit system" - Quit - ${EndIf} - ${Else} - ${If} ${arch} == "x64" - MessageBox MB_ICONSTOP|MB_OK "Please use 32-bit installer on 32-bit system" - Quit - ${EndIf} - ${EndIf} - - ${IfNot} ${AtLeastWin7} - MessageBox MB_ICONSTOP|MB_OK "Windows 7 and above required" - Quit - ${EndIf} - - System::Call 'kernel32::CreateMutex(i 0, i 0, t "KeeWeb-Installer-Mutex-8843DCD0") ?e' - Pop $R0 - ${If} $R0 != 0 - MessageBox MB_ICONSTOP|MB_OK "The installer is already running." - Abort - ${EndIf} - - !insertmacro MULTIUSER_INIT -FunctionEnd - -Section "MainSection" SEC01 + ${If} ${RunningX64} + ${If} ${arch} == "x64" + SetRegView 64 + StrCpy $InstDir "$PROGRAMFILES64\${PRODUCT_NAME}" + ${Else} + MessageBox MB_ICONSTOP|MB_OK "Please use 64-bit installer on 64-bit system" + Quit + ${EndIf} + ${Else} + ${If} ${arch} == "x64" + MessageBox MB_ICONSTOP|MB_OK "Please use 32-bit installer on 32-bit system" + Quit + ${EndIf} + ${EndIf} + + ${IfNot} ${AtLeastWin7} + MessageBox MB_ICONSTOP|MB_OK "Windows 7 and above required" + Quit + ${EndIf} + + System::Call 'kernel32::CreateMutex(i 0, i 0, t "KeeWeb-Installer-Mutex-8843DCD0") ?e' + Pop $R0 + ${If} $R0 != 0 + MessageBox MB_ICONSTOP|MB_OK "The installer is already running." + Abort + ${EndIf} + + !insertmacro MULTIUSER_INIT +FunctionEnd + +Section "MainSection" SEC01 !insertmacro EnsureAppIsNotRunning - ReadRegStr $R0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" + SetOverwrite on + + ReadRegStr $R0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" ${If} $R0 != "" - ExecWait '$R0 /S _?=$INSTDIR' - ${EndIf} - - ReadRegStr $R0 "HKCU" "${PRODUCT_UNINST_KEY}" "QuietUninstallString" - ${If} $R0 != "" - ExecWait '$R0' - ${EndIf} - - ReadRegStr $R0 "HKCU" "${PRODUCT_UNINST_KEY}" "UninstallString" - ${If} $R0 != "" - ExecWait '$R0' - ${EndIf} - - SetOutPath "$INSTDIR" - SetOverwrite ifnewer - File /r "tmp\desktop\KeeWeb-win32-${arch}\*" - CreateDirectory "$SMPROGRAMS\KeeWeb" - CreateShortCut "$SMPROGRAMS\KeeWeb\KeeWeb.lnk" "$INSTDIR\KeeWeb.exe" - CreateShortCut "$DESKTOP\KeeWeb.lnk" "$INSTDIR\KeeWeb.exe" - - !insertmacro APP_ASSOCIATE "kdbx" "kdbxfile" "KeePass Password Database" \ - "$INSTDIR\KeeWeb.exe,0" "Open with KeeWeb" "$INSTDIR\KeeWeb.exe $\"%1$\"" - !insertmacro UPDATEFILEASSOC -SectionEnd - + CopyFiles "$R0" "$TEMP\${PRODUCT_UNINST_TEMP_EXE}" + ExecWait '"$TEMP\${PRODUCT_UNINST_TEMP_EXE}" /S' + ${EndIf} + + ReadRegStr $R0 "HKCU" "${PRODUCT_UNINST_KEY}" "QuietUninstallString" + ${If} $R0 != "" + ExecWait '$R0' + ${EndIf} + + ReadRegStr $R0 "HKCU" "${PRODUCT_UNINST_KEY}" "UninstallString" + ${If} $R0 != "" + ExecWait '$R0' + ${EndIf} + + SetOutPath "$INSTDIR" + SetOverwrite on + File /r "tmp\desktop\KeeWeb-win32-${arch}\*" + CreateDirectory "$SMPROGRAMS\KeeWeb" + CreateShortCut "$SMPROGRAMS\KeeWeb\KeeWeb.lnk" "$INSTDIR\${PRODUCT_EXE}" + CreateShortCut "$DESKTOP\KeeWeb.lnk" "$INSTDIR\${PRODUCT_EXE}" + + !insertmacro APP_ASSOCIATE "kdbx" "kdbxfile" "KeePass Password Database" \ + "$INSTDIR\${PRODUCT_EXE},0" "Open with KeeWeb" "$INSTDIR\${PRODUCT_EXE} $\"%1$\"" + !insertmacro UPDATEFILEASSOC +SectionEnd + Section -Post - WriteUninstaller "$INSTDIR\uninst.exe" - WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)" - WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" '"$INSTDIR\uninst.exe"' - WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "QuietUninstallString" '"$INSTDIR\uninst.exe" /S' - WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\KeeWeb.exe" - WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}" - WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}" + WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)" + WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" '"$INSTDIR\uninst.exe"' + WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "QuietUninstallString" '"$INSTDIR\uninst.exe" /S' + WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXE}" + WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}" + WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}" -SectionEnd + WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "InstallDir" "$INSTDIR" +SectionEnd diff --git a/package/nsis/lib/FileAssoc.nsh b/package/nsis/lib/FileAssoc.nsh old mode 100644 new mode 100755 index dd01eca7..84b7c8aa --- a/package/nsis/lib/FileAssoc.nsh +++ b/package/nsis/lib/FileAssoc.nsh @@ -1,121 +1,121 @@ -# http://nsis.sourceforge.net/FileAssoc - -; fileassoc.nsh -; File association helper macros -; Written by Saivert -; -; Features automatic backup system and UPDATEFILEASSOC macro for -; shell change notification. -; -; |> How to use <| -; To associate a file with an application so you can double-click it in explorer, use -; the APP_ASSOCIATE macro like this: -; -; Example: -; !insertmacro APP_ASSOCIATE "txt" "myapp.textfile" "Description of txt files" \ -; "$INSTDIR\myapp.exe,0" "Open with myapp" "$INSTDIR\myapp.exe $\"%1$\"" -; -; Never insert the APP_ASSOCIATE macro multiple times, it is only ment -; to associate an application with a single file and using the -; the "open" verb as default. To add more verbs (actions) to a file -; use the APP_ASSOCIATE_ADDVERB macro. -; -; Example: -; !insertmacro APP_ASSOCIATE_ADDVERB "myapp.textfile" "edit" "Edit with myapp" \ -; "$INSTDIR\myapp.exe /edit $\"%1$\"" -; -; To have access to more options when registering the file association use the -; APP_ASSOCIATE_EX macro. Here you can specify the verb and what verb is to be the -; standard action (default verb). -; -; And finally: To remove the association from the registry use the APP_UNASSOCIATE -; macro. Here is another example just to wrap it up: -; !insertmacro APP_UNASSOCIATE "txt" "myapp.textfile" -; -; |> Note <| -; When defining your file class string always use the short form of your application title -; then a period (dot) and the type of file. This keeps the file class sort of unique. -; Examples: -; Winamp.Playlist -; NSIS.Script -; Photoshop.JPEGFile -; -; |> Tech info <| -; The registry key layout for a file association is: -; HKEY_CLASSES_ROOT -; = <"description"> -; shell -; = <"menu-item text"> -; command = <"command string"> -; - -!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND - ; Backup the previously associated file class - ReadRegStr $R0 HKCR ".${EXT}" "" - WriteRegStr HKCR ".${EXT}" "${FILECLASS}_backup" "$R0" - - WriteRegStr HKCR ".${EXT}" "" "${FILECLASS}" - - WriteRegStr HKCR "${FILECLASS}" "" `${DESCRIPTION}` - WriteRegStr HKCR "${FILECLASS}\DefaultIcon" "" `${ICON}` - WriteRegStr HKCR "${FILECLASS}\shell" "" "open" - WriteRegStr HKCR "${FILECLASS}\shell\open" "" `${COMMANDTEXT}` - WriteRegStr HKCR "${FILECLASS}\shell\open\command" "" `${COMMAND}` -!macroend - -!macro APP_ASSOCIATE_EX EXT FILECLASS DESCRIPTION ICON VERB DEFAULTVERB SHELLNEW COMMANDTEXT COMMAND - ; Backup the previously associated file class - ReadRegStr $R0 HKCR ".${EXT}" "" - WriteRegStr HKCR ".${EXT}" "${FILECLASS}_backup" "$R0" - - WriteRegStr HKCR ".${EXT}" "" "${FILECLASS}" - StrCmp "${SHELLNEW}" "0" +2 - WriteRegStr HKCR ".${EXT}\ShellNew" "NullFile" "" - - WriteRegStr HKCR "${FILECLASS}" "" `${DESCRIPTION}` - WriteRegStr HKCR "${FILECLASS}\DefaultIcon" "" `${ICON}` - WriteRegStr HKCR "${FILECLASS}\shell" "" `${DEFAULTVERB}` - WriteRegStr HKCR "${FILECLASS}\shell\${VERB}" "" `${COMMANDTEXT}` - WriteRegStr HKCR "${FILECLASS}\shell\${VERB}\command" "" `${COMMAND}` -!macroend - -!macro APP_ASSOCIATE_ADDVERB FILECLASS VERB COMMANDTEXT COMMAND - WriteRegStr HKCR "${FILECLASS}\shell\${VERB}" "" `${COMMANDTEXT}` - WriteRegStr HKCR "${FILECLASS}\shell\${VERB}\command" "" `${COMMAND}` -!macroend - -!macro APP_ASSOCIATE_REMOVEVERB FILECLASS VERB - DeleteRegKey HKCR `${FILECLASS}\shell\${VERB}` -!macroend - - -!macro APP_UNASSOCIATE EXT FILECLASS - ; Backup the previously associated file class - ReadRegStr $R0 HKCR ".${EXT}" `${FILECLASS}_backup` - WriteRegStr HKCR ".${EXT}" "" "$R0" - - DeleteRegKey HKCR `${FILECLASS}` -!macroend - -!macro APP_ASSOCIATE_GETFILECLASS OUTPUT EXT - ReadRegStr ${OUTPUT} HKCR ".${EXT}" "" -!macroend - - -; !defines for use with SHChangeNotify -!ifdef SHCNE_ASSOCCHANGED -!undef SHCNE_ASSOCCHANGED -!endif -!define SHCNE_ASSOCCHANGED 0x08000000 -!ifdef SHCNF_FLUSH -!undef SHCNF_FLUSH -!endif -!define SHCNF_FLUSH 0x1000 - -!macro UPDATEFILEASSOC -; Using the system.dll plugin to call the SHChangeNotify Win32 API function so we -; can update the shell. - System::Call "shell32::SHChangeNotify(i,i,i,i) (${SHCNE_ASSOCCHANGED}, ${SHCNF_FLUSH}, 0, 0)" -!macroend - -;EOF +# http://nsis.sourceforge.net/FileAssoc + +; fileassoc.nsh +; File association helper macros +; Written by Saivert +; +; Features automatic backup system and UPDATEFILEASSOC macro for +; shell change notification. +; +; |> How to use <| +; To associate a file with an application so you can double-click it in explorer, use +; the APP_ASSOCIATE macro like this: +; +; Example: +; !insertmacro APP_ASSOCIATE "txt" "myapp.textfile" "Description of txt files" \ +; "$INSTDIR\myapp.exe,0" "Open with myapp" "$INSTDIR\myapp.exe $\"%1$\"" +; +; Never insert the APP_ASSOCIATE macro multiple times, it is only ment +; to associate an application with a single file and using the +; the "open" verb as default. To add more verbs (actions) to a file +; use the APP_ASSOCIATE_ADDVERB macro. +; +; Example: +; !insertmacro APP_ASSOCIATE_ADDVERB "myapp.textfile" "edit" "Edit with myapp" \ +; "$INSTDIR\myapp.exe /edit $\"%1$\"" +; +; To have access to more options when registering the file association use the +; APP_ASSOCIATE_EX macro. Here you can specify the verb and what verb is to be the +; standard action (default verb). +; +; And finally: To remove the association from the registry use the APP_UNASSOCIATE +; macro. Here is another example just to wrap it up: +; !insertmacro APP_UNASSOCIATE "txt" "myapp.textfile" +; +; |> Note <| +; When defining your file class string always use the short form of your application title +; then a period (dot) and the type of file. This keeps the file class sort of unique. +; Examples: +; Winamp.Playlist +; NSIS.Script +; Photoshop.JPEGFile +; +; |> Tech info <| +; The registry key layout for a file association is: +; HKEY_CLASSES_ROOT +; = <"description"> +; shell +; = <"menu-item text"> +; command = <"command string"> +; + +!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND + ; Backup the previously associated file class + ReadRegStr $R0 HKCR ".${EXT}" "" + WriteRegStr HKCR ".${EXT}" "${FILECLASS}_backup" "$R0" + + WriteRegStr HKCR ".${EXT}" "" "${FILECLASS}" + + WriteRegStr HKCR "${FILECLASS}" "" `${DESCRIPTION}` + WriteRegStr HKCR "${FILECLASS}\DefaultIcon" "" `${ICON}` + WriteRegStr HKCR "${FILECLASS}\shell" "" "open" + WriteRegStr HKCR "${FILECLASS}\shell\open" "" `${COMMANDTEXT}` + WriteRegStr HKCR "${FILECLASS}\shell\open\command" "" `${COMMAND}` +!macroend + +!macro APP_ASSOCIATE_EX EXT FILECLASS DESCRIPTION ICON VERB DEFAULTVERB SHELLNEW COMMANDTEXT COMMAND + ; Backup the previously associated file class + ReadRegStr $R0 HKCR ".${EXT}" "" + WriteRegStr HKCR ".${EXT}" "${FILECLASS}_backup" "$R0" + + WriteRegStr HKCR ".${EXT}" "" "${FILECLASS}" + StrCmp "${SHELLNEW}" "0" +2 + WriteRegStr HKCR ".${EXT}\ShellNew" "NullFile" "" + + WriteRegStr HKCR "${FILECLASS}" "" `${DESCRIPTION}` + WriteRegStr HKCR "${FILECLASS}\DefaultIcon" "" `${ICON}` + WriteRegStr HKCR "${FILECLASS}\shell" "" `${DEFAULTVERB}` + WriteRegStr HKCR "${FILECLASS}\shell\${VERB}" "" `${COMMANDTEXT}` + WriteRegStr HKCR "${FILECLASS}\shell\${VERB}\command" "" `${COMMAND}` +!macroend + +!macro APP_ASSOCIATE_ADDVERB FILECLASS VERB COMMANDTEXT COMMAND + WriteRegStr HKCR "${FILECLASS}\shell\${VERB}" "" `${COMMANDTEXT}` + WriteRegStr HKCR "${FILECLASS}\shell\${VERB}\command" "" `${COMMAND}` +!macroend + +!macro APP_ASSOCIATE_REMOVEVERB FILECLASS VERB + DeleteRegKey HKCR `${FILECLASS}\shell\${VERB}` +!macroend + + +!macro APP_UNASSOCIATE EXT FILECLASS + ; Backup the previously associated file class + ReadRegStr $R0 HKCR ".${EXT}" `${FILECLASS}_backup` + WriteRegStr HKCR ".${EXT}" "" "$R0" + + DeleteRegKey HKCR `${FILECLASS}` +!macroend + +!macro APP_ASSOCIATE_GETFILECLASS OUTPUT EXT + ReadRegStr ${OUTPUT} HKCR ".${EXT}" "" +!macroend + + +; !defines for use with SHChangeNotify +!ifdef SHCNE_ASSOCCHANGED +!undef SHCNE_ASSOCCHANGED +!endif +!define SHCNE_ASSOCCHANGED 0x08000000 +!ifdef SHCNF_FLUSH +!undef SHCNF_FLUSH +!endif +!define SHCNF_FLUSH 0x1000 + +!macro UPDATEFILEASSOC +; Using the system.dll plugin to call the SHChangeNotify Win32 API function so we +; can update the shell. + System::Call "shell32::SHChangeNotify(i,i,i,i) (${SHCNE_ASSOCCHANGED}, ${SHCNF_FLUSH}, 0, 0)" +!macroend + +;EOF diff --git a/package/nsis/lib/StrContains.nsh b/package/nsis/lib/StrContains.nsh deleted file mode 100644 index 910393c9..00000000 --- a/package/nsis/lib/StrContains.nsh +++ /dev/null @@ -1,50 +0,0 @@ -# http://nsis.sourceforge.net/StrContains - -; StrContains -; This function does a case sensitive searches for an occurrence of a substring in a string. -; It returns the substring if it is found. -; Otherwise it returns null(""). -; Written by kenglish_hi -; Adapted from StrReplace written by dandaman32 - - -Var STR_HAYSTACK -Var STR_NEEDLE -Var STR_CONTAINS_VAR_1 -Var STR_CONTAINS_VAR_2 -Var STR_CONTAINS_VAR_3 -Var STR_CONTAINS_VAR_4 -Var STR_RETURN_VAR - -Function StrContains - Exch $STR_NEEDLE - Exch 1 - Exch $STR_HAYSTACK - ; Uncomment to debug - ;MessageBox MB_OK 'STR_NEEDLE = $STR_NEEDLE STR_HAYSTACK = $STR_HAYSTACK ' - StrCpy $STR_RETURN_VAR "" - StrCpy $STR_CONTAINS_VAR_1 -1 - StrLen $STR_CONTAINS_VAR_2 $STR_NEEDLE - StrLen $STR_CONTAINS_VAR_4 $STR_HAYSTACK - loop: - IntOp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_1 + 1 - StrCpy $STR_CONTAINS_VAR_3 $STR_HAYSTACK $STR_CONTAINS_VAR_2 $STR_CONTAINS_VAR_1 - StrCmp $STR_CONTAINS_VAR_3 $STR_NEEDLE found - StrCmp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_4 done - Goto loop - found: - StrCpy $STR_RETURN_VAR $STR_NEEDLE - Goto done - done: - Pop $STR_NEEDLE ;Prevent "invalid opcode" errors and keep the - Exch $STR_RETURN_VAR -FunctionEnd - -!macro _StrContainsConstructor OUT NEEDLE HAYSTACK - Push `${HAYSTACK}` - Push `${NEEDLE}` - Call StrContains - Pop `${OUT}` -!macroend - -!define StrContains '!insertmacro "_StrContainsConstructor"' diff --git a/package/nsis/main-un.nsi b/package/nsis/main-un.nsi new file mode 100755 index 00000000..f2492340 --- /dev/null +++ b/package/nsis/main-un.nsi @@ -0,0 +1,4 @@ +!include package\nsis\defines.nsh +!include package\nsis\includes.nsh +!include package\nsis\check-running.nsh +!include package\nsis\uninstall.nsh diff --git a/package/nsis/main.nsi b/package/nsis/main.nsi old mode 100644 new mode 100755 index 44f6c7f5..2543ea80 --- a/package/nsis/main.nsi +++ b/package/nsis/main.nsi @@ -1,7 +1,4 @@ -!include package\nsis\defines.nsh -!include package\nsis\includes.nsh -!include package\nsis\mui.nsh -!include package\nsis\config.nsh +!include package\nsis\defines.nsh +!include package\nsis\includes.nsh !include package\nsis\check-running.nsh !include package\nsis\install.nsh -!include package\nsis\uninstall.nsh diff --git a/package/nsis/mui.nsh b/package/nsis/mui.nsh deleted file mode 100644 index a207873e..00000000 --- a/package/nsis/mui.nsh +++ /dev/null @@ -1,9 +0,0 @@ -!insertmacro MUI_PAGE_WELCOME -#!insertmacro MULTIUSER_PAGE_INSTALLMODE -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES -!insertmacro MUI_PAGE_FINISH - -!insertmacro MUI_UNPAGE_INSTFILES - -!insertmacro MUI_LANGUAGE "English" diff --git a/package/nsis/uninstall.nsh b/package/nsis/uninstall.nsh old mode 100644 new mode 100755 index 964169cb..143db015 --- a/package/nsis/uninstall.nsh +++ b/package/nsis/uninstall.nsh @@ -1,29 +1,78 @@ -Function un.onInit - MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Remove $(^Name) from your computer?" /SD IDYES IDYES yes - Abort - yes: +!insertmacro MUI_PAGE_INSTFILES + +!insertmacro MUI_LANGUAGE "English" + +Function .onInit ${If} ${RunningX64} SetRegView 64 + StrCpy $InstDir "$PROGRAMFILES64\${PRODUCT_NAME}" ${EndIf} - !insertmacro MULTIUSER_UNINIT -FunctionEnd -Function un.onUninstSuccess - HideWindow - MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer." /SD IDOK -FunctionEnd + !insertmacro MULTIUSER_INIT -Section Uninstall + ${StrStr} $0 "$EXEPATH" "${PRODUCT_UNINST_TEMP_EXE}" + ${If} $0 == "" + MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Remove $(^Name) from your computer?" /SD IDYES IDYES yes + Abort + yes: + !insertmacro EnsureAppIsNotRunning + + SetOverwrite on + CopyFiles "$EXEPATH" "$TEMP\${PRODUCT_UNINST_TEMP_EXE}" + ${If} ${Silent} + Exec '"$TEMP\${PRODUCT_UNINST_TEMP_EXE}" /S' + ${Else} + Exec '"$TEMP\${PRODUCT_UNINST_TEMP_EXE}"' + ${EndIf} + Quit + ${EndIf} +FunctionEnd + +Function .onInstSuccess + HideWindow + MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer." /SD IDOK +FunctionEnd + +Section "MainSection" SEC01 + !insertmacro EnsureAppIsNotRunning + + DetailPrint "Removing desktop shortcut" Delete "$DESKTOP\KeeWeb.lnk" - Delete "$SMPROGRAMS\KeeWeb\KeeWeb.lnk" + DetailPrint "Removing menu shortcut" + Delete "$SMPROGRAMS\KeeWeb\KeeWeb.lnk" + DetailPrint "Removing menu items" RMDir "$SMPROGRAMS\KeeWeb" - RMDir /r "$INSTDIR" - DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" + ReadRegStr $R0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "InstallDir" + ${If} $R0 == "" + DetailPrint "InstallDir key is absent" + Abort + ${EndIf} + StrCpy $InstDir "$R0" + ClearErrors + DetailPrint "Removing app files from $InstDir" + Var /GLOBAL deleteRetry + ${ForEach} $deleteRetry 1 3 + 1 + RMDir /r "$InstDir" + ${If} ${Errors} + ClearErrors + DetailPrint "Error removing files, retrying in a second" + Sleep 1000 + ${Else} + ${ExitFor} + ${EndIf} + ${Next} + + DetailPrint "Deleting registry keys" + DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" + + DetailPrint "Unregistering file associations" !insertmacro APP_UNASSOCIATE "kdbx" "kdbxfile" - !insertmacro UPDATEFILEASSOC + DetailPrint "Updating file associations" + !insertmacro UPDATEFILEASSOC + DetailPrint "Done" SetAutoClose true -SectionEnd +SectionEnd