From 3b155b16721cae04b0b7f3f2af0e1db29080cb1c Mon Sep 17 00:00:00 2001 From: Vincent Quagliaro Date: Sun, 29 Nov 2015 17:40:14 +0100 Subject: [PATCH 1/4] add an option to define a file association on Windows --- assets/win/FileAssociation.nsh | 190 +++++++++++++++++++++++++++++++++ lib/win.js | 16 ++- templates/installer.nsi.tpl | 10 ++ 3 files changed, 211 insertions(+), 5 deletions(-) create mode 100644 assets/win/FileAssociation.nsh diff --git a/assets/win/FileAssociation.nsh b/assets/win/FileAssociation.nsh new file mode 100644 index 00000000000..cc2f9858393 --- /dev/null +++ b/assets/win/FileAssociation.nsh @@ -0,0 +1,190 @@ +/* +_____________________________________________________________________________ + + File Association +_____________________________________________________________________________ + + Based on code taken from http://nsis.sourceforge.net/File_Association + + Usage in script: + 1. !include "FileAssociation.nsh" + 2. [Section|Function] + ${FileAssociationFunction} "Param1" "Param2" "..." $var + [SectionEnd|FunctionEnd] + + FileAssociationFunction=[RegisterExtension|UnRegisterExtension] + +_____________________________________________________________________________ + + ${RegisterExtension} "[executable]" "[extension]" "[description]" + +"[executable]" ; executable which opens the file format + ; +"[extension]" ; extension, which represents the file format to open + ; +"[description]" ; description for the extension. This will be display in Windows Explorer. + ; + + + ${UnRegisterExtension} "[extension]" "[description]" + +"[extension]" ; extension, which represents the file format to open + ; +"[description]" ; description for the extension. This will be display in Windows Explorer. + ; + +_____________________________________________________________________________ + + Macros +_____________________________________________________________________________ + + Change log window verbosity (default: 3=no script) + + Example: + !include "FileAssociation.nsh" + !insertmacro RegisterExtension + ${FileAssociation_VERBOSE} 4 # all verbosity + !insertmacro UnRegisterExtension + ${FileAssociation_VERBOSE} 3 # no script +*/ + + +!ifndef FileAssociation_INCLUDED +!define FileAssociation_INCLUDED + +!include Util.nsh + +!verbose push +!verbose 3 +!ifndef _FileAssociation_VERBOSE + !define _FileAssociation_VERBOSE 3 +!endif +!verbose ${_FileAssociation_VERBOSE} +!define FileAssociation_VERBOSE `!insertmacro FileAssociation_VERBOSE` +!verbose pop + +!macro FileAssociation_VERBOSE _VERBOSE + !verbose push + !verbose 3 + !undef _FileAssociation_VERBOSE + !define _FileAssociation_VERBOSE ${_VERBOSE} + !verbose pop +!macroend + + + +!macro RegisterExtensionCall _EXECUTABLE _EXTENSION _DESCRIPTION + !verbose push + !verbose ${_FileAssociation_VERBOSE} + Push `${_DESCRIPTION}` + Push `${_EXTENSION}` + Push `${_EXECUTABLE}` + ${CallArtificialFunction} RegisterExtension_ + !verbose pop +!macroend + +!macro UnRegisterExtensionCall _EXTENSION _DESCRIPTION + !verbose push + !verbose ${_FileAssociation_VERBOSE} + Push `${_EXTENSION}` + Push `${_DESCRIPTION}` + ${CallArtificialFunction} UnRegisterExtension_ + !verbose pop +!macroend + + + +!define RegisterExtension `!insertmacro RegisterExtensionCall` +!define un.RegisterExtension `!insertmacro RegisterExtensionCall` + +!macro RegisterExtension +!macroend + +!macro un.RegisterExtension +!macroend + +!macro RegisterExtension_ + !verbose push + !verbose ${_FileAssociation_VERBOSE} + + Exch $R2 ;exe + Exch + Exch $R1 ;ext + Exch + Exch 2 + Exch $R0 ;desc + Exch 2 + Push $0 + Push $1 + + ReadRegStr $1 HKCR $R1 "" ; read current file association + StrCmp "$1" "" NoBackup ; is it empty + StrCmp "$1" "$R0" NoBackup ; is it our own + WriteRegStr HKCR $R1 "backup_val" "$1" ; backup current value +NoBackup: + WriteRegStr HKCR $R1 "" "$R0" ; set our file association + + ReadRegStr $0 HKCR $R0 "" + StrCmp $0 "" 0 Skip + WriteRegStr HKCR "$R0" "" "$R0" + WriteRegStr HKCR "$R0\shell" "" "open" + WriteRegStr HKCR "$R0\DefaultIcon" "" "$R2,0" +Skip: + WriteRegStr HKCR "$R0\shell\open\command" "" '"$R2" "%1"' + WriteRegStr HKCR "$R0\shell\edit" "" "Edit $R0" + WriteRegStr HKCR "$R0\shell\edit\command" "" '"$R2" "%1"' + + Pop $1 + Pop $0 + Pop $R2 + Pop $R1 + Pop $R0 + + !verbose pop +!macroend + + + +!define UnRegisterExtension `!insertmacro UnRegisterExtensionCall` +!define un.UnRegisterExtension `!insertmacro UnRegisterExtensionCall` + +!macro UnRegisterExtension +!macroend + +!macro un.UnRegisterExtension +!macroend + +!macro UnRegisterExtension_ + !verbose push + !verbose ${_FileAssociation_VERBOSE} + + Exch $R1 ;desc + Exch + Exch $R0 ;ext + Exch + Push $0 + Push $1 + + ReadRegStr $1 HKCR $R0 "" + StrCmp $1 $R1 0 NoOwn ; only do this if we own it + ReadRegStr $1 HKCR $R0 "backup_val" + StrCmp $1 "" 0 Restore ; if backup="" then delete the whole key + DeleteRegKey HKCR $R0 + Goto NoOwn + +Restore: + WriteRegStr HKCR $R0 "" $1 + DeleteRegValue HKCR $R0 "backup_val" + DeleteRegKey HKCR $R1 ;Delete key with association name settings + +NoOwn: + + Pop $1 + Pop $0 + Pop $R1 + Pop $R0 + + !verbose pop +!macroend + +!endif # !FileAssociation_INCLUDED diff --git a/lib/win.js b/lib/win.js index 16f0317a35e..1a8f0c55ea5 100644 --- a/lib/win.js +++ b/lib/win.js @@ -30,11 +30,12 @@ var WinBuilder = { var nsiTemplate = options.config.win.nsiTemplate || path.join( __dirname, '..', 'templates/installer.nsi.tpl' ); var configFilePath = writeConfigFile( nsiTemplate, { - appPath : _windowsify( options.appPath ), - name : options.config.win.title, - version : options.config.win.version, - out : _windowsify( options.out ) - } ); + appPath : _windowsify( options.appPath ), + name : options.config.win.title, + version : options.config.win.version, + fileAssociation : options.config.win.fileAssociation, + out : _windowsify( options.out ) + }); _copyAssetsToTmpFolder( options ); @@ -106,6 +107,11 @@ function _copyAssetsToTmpFolder( options ) { path.join( tmpDir, 'nsProcess.nsh' ) ); + fs.copySync( + path.join( __dirname, '..', 'assets', 'win', 'FileAssociation.nsh' ), + path.join( tmpDir, 'FileAssociation.nsh' ) + ); + fs.copySync( path.join( __dirname, '..', 'assets', 'win', 'nsProcess.dll' ), path.join( tmpDir, 'nsProcess.dll' ) diff --git a/templates/installer.nsi.tpl b/templates/installer.nsi.tpl index 8dd2be67f8f..45a7dcf92da 100644 --- a/templates/installer.nsi.tpl +++ b/templates/installer.nsi.tpl @@ -12,6 +12,11 @@ Name "${APP_NAME}" !addplugindir . !include "nsProcess.nsh" +<% if(fileAssociation){ %> +# include file association script +!include "FileAssociation.nsh" +<% } %> + BrandingText "${APP_NAME} ${APP_VERSION}" # define the resulting installer's name @@ -61,6 +66,11 @@ Section # specify icon to go in the output path File "icon.ico" + <% if(fileAssociation){ %> + # specify file association + ${registerExtension} "$INSTDIR\${APP_NAME}.exe" "<%= fileAssociation.extension %>" "<%= fileAssociation.fileType %>" + <% } %> + # create the uninstaller WriteUninstaller "$INSTDIR\Uninstall ${APP_NAME}.exe" From 4cfd2bf57e97962739b9180d92fbcaa46848250f Mon Sep 17 00:00:00 2001 From: Vincent Quagliaro Date: Sun, 29 Nov 2015 17:57:41 +0100 Subject: [PATCH 2/4] [doc] add an option to define a file association on Windows --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6547a8bf0f0..1c91fd32f35 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,11 @@ config.json.sample: "title" : "Loopline Systems", "version" : "x.x.x.x", "icon" : "assets/win/icon.ico", - "nsiTemplate" : "path/to/custom/installer.nsi.tpl" + "nsiTemplate" : "path/to/custom/installer.nsi.tpl", // optional + "fileAssociation": { // optional + "extension": ".loop", + "fileType": "Loopline Systems File" + } } } ``` @@ -139,6 +143,10 @@ Icon to be shown in installation process. ### `win.nsiTemplate` *( optional )* Option to define a custom NSI installation file. +### `win.fileAssociation` *( optional )* +Option to define a custom file association on Windows. +Caution: `win.fileAssociation` does not work when `win.nsiTemplate` is defined. + **Note:** You need to add something that might have value for others? Please consider a PR. ;) From 69806c42e4f8a7747f51a7dd91a7c0e946025aef Mon Sep 17 00:00:00 2001 From: Vincent Quagliaro Date: Sun, 29 Nov 2015 18:59:34 +0100 Subject: [PATCH 3/4] [test] add an option to define a file association on Windows --- lib/win.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/win.js b/lib/win.js index 1a8f0c55ea5..aed8afec7a1 100644 --- a/lib/win.js +++ b/lib/win.js @@ -35,7 +35,7 @@ var WinBuilder = { version : options.config.win.version, fileAssociation : options.config.win.fileAssociation, out : _windowsify( options.out ) - }); + } ); _copyAssetsToTmpFolder( options ); From e3b170a9992fefba8e99ea24ed43024f0067b57c Mon Sep 17 00:00:00 2001 From: Vincent Quagliaro Date: Mon, 30 Nov 2015 15:27:57 +0100 Subject: [PATCH 4/4] [File associations in Windows] update documentation --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c91fd32f35..7ffcd161d10 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,8 @@ Option to define a custom NSI installation file. ### `win.fileAssociation` *( optional )* Option to define a custom file association on Windows. -Caution: `win.fileAssociation` does not work when `win.nsiTemplate` is defined. +Caution: when you use `win.nsiTemplate` option, `win.fileAssociation` option should only work +if the custom nsi template is based on the original one. **Note:** You need to add something that might have value for others? Please consider a PR. ;)