Skip to content

Commit

Permalink
feat(nsis): implement file associations per user
Browse files Browse the repository at this point in the history
Close #2861, Close #2860
  • Loading branch information
nikku authored and develar committed May 3, 2018
1 parent 821320c commit 4adfbdd
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 48 deletions.
4 changes: 0 additions & 4 deletions packages/electron-builder-lib/src/targets/nsis/NsisTarget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -554,10 +554,6 @@ export class NsisTarget extends Target {

const fileAssociations = packager.fileAssociations
if (fileAssociations.length !== 0) {
if (options.perMachine !== true && options.oneClick !== false) {
// https://github.com/electron-userland/electron-builder/issues/772
throw new InvalidConfigurationError(`Please set perMachine to true — file associations works on Windows only if installed for all users`)
}

scriptGenerator.include(path.join(path.join(nsisTemplatesDir, "include"), "FileAssociation.nsh"))
if (isInstaller) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
; APP_ASSOCIATE_EX macro. Here you can specify the verb and what verb is to be the
; standard action (default verb).
;
; Note, that this script takes into account user versus global installs.
; To properly work you must initialize the SHELL_CONTEXT variable via SetShellVarContext.
;
; 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"
Expand All @@ -39,67 +42,79 @@
; Photoshop.JPEGFile
;
; |> Tech info <|
; The registry key layout for a file association is:
; HKEY_CLASSES_ROOT
; The registry key layout for a global file association is:
;
; HKEY_LOCAL_MACHINE\Software\Classes
; <".ext"> = <applicationID>
; <applicationID> = <"description">
; shell
; <verb> = <"menu-item text">
; command = <"command string">
;
;
; The registry key layout for a per-user file association is:
;
; HKEY_CURRENT_USER\Software\Classes
; <".ext"> = <applicationID>
; <applicationID> = <"description">
; shell
; <verb> = <"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}`
ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" ""
WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0"

WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}"

WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}`
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}`
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open"
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}`
WriteRegStr SHELL_CONTEXT "Software\Classes\${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}"
ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" ""
WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0"

WriteRegStr SHELL_CONTEXT "Software\Classes\.${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}`
WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}\ShellNew" "NullFile" ""

WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}`
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}`
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" `${DEFAULTVERB}`
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\${VERB}" "" `${COMMANDTEXT}`
WriteRegStr SHELL_CONTEXT "Software\Classes\${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}`
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\${VERB}" "" `${COMMANDTEXT}`
WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\${VERB}\command" "" `${COMMAND}`
!macroend

!macro APP_ASSOCIATE_REMOVEVERB FILECLASS VERB
DeleteRegKey HKCR `${FILECLASS}\shell\${VERB}`
DeleteRegKey SHELL_CONTEXT `Software\Classes\${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}`
ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup`
WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0"

DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}`
!macroend

!macro APP_ASSOCIATE_GETFILECLASS OUTPUT EXT
ReadRegStr ${OUTPUT} HKCR ".${EXT}" ""
ReadRegStr ${OUTPUT} SHELL_CONTEXT "Software\Classes\.${EXT}" ""
!macroend


; !defines for use with SHChangeNotify
!ifdef SHCNE_ASSOCCHANGED
!undef SHCNE_ASSOCCHANGED
Expand All @@ -109,7 +124,7 @@
!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.
Expand Down
24 changes: 23 additions & 1 deletion test/out/windows/__snapshots__/oneClickInstallerTest.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,29 @@ Object {
}
`;

exports[`file associations only perMachine 1`] = `"ERR_ELECTRON_BUILDER_INVALID_CONFIGURATION"`;
exports[`file associations per user 1`] = `
Object {
"win": Array [
Object {
"arch": "ia32",
"file": "Test App ßW Setup 1.1.0.exe",
"safeArtifactName": "TestApp-Setup-1.1.0.exe",
"updateInfo": Object {
"sha512": "@sha512",
"size": "@size",
},
},
Object {
"file": "Test App ßW Setup 1.1.0.exe.blockmap",
"safeArtifactName": "TestApp-Setup-1.1.0.exe.blockmap",
"updateInfo": Object {
"sha512": "@sha512",
"size": "@size",
},
},
],
}
`;

exports[`html license 1`] = `
Object {
Expand Down
4 changes: 2 additions & 2 deletions test/src/windows/oneClickInstallerTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Arch, Platform } from "electron-builder"
import { copy, writeFile } from "fs-extra-p"
import * as path from "path"
import { assertThat } from "../helpers/fileAssert"
import { app, appThrows, assertPack, copyTestAsset, modifyPackageJson } from "../helpers/packTester"
import { app, assertPack, copyTestAsset, modifyPackageJson } from "../helpers/packTester"
import { checkHelpers, doTest, expectUpdateMetadata } from "../helpers/winHelper"

const nsisTarget = Platform.WINDOWS.createTarget(["nsis"])
Expand Down Expand Up @@ -209,7 +209,7 @@ test.ifNotCiMac("string menuCategory", app({
}
}))

test.ifDevOrLinuxCi("file associations only perMachine", appThrows({
test.ifDevOrLinuxCi("file associations per user", app({
targets: Platform.WINDOWS.createTarget(["nsis"], Arch.ia32),
config: {
publish: null,
Expand Down

0 comments on commit 4adfbdd

Please sign in to comment.