From b704d52400d91b7f2d2e09abfccad28fe892f1b9 Mon Sep 17 00:00:00 2001 From: anders_k Date: Mon, 13 Apr 2020 19:16:10 +0000 Subject: [PATCH] Added a file association example to install-per-user.nsi git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@7167 212acab6-be3b-0410-9dea-997c60f758d6 --- Docs/src/registry.but | 6 ++ Examples/example1.nsi | 2 + Examples/example2.nsi | 17 +++--- Examples/install-per-user.nsi | 100 ++++++++++++++++++++++++++++++++-- Examples/install-shared.nsi | 7 +-- Source/exehead/fileform.h | 1 + 6 files changed, 114 insertions(+), 19 deletions(-) diff --git a/Docs/src/registry.but b/Docs/src/registry.but index f8890780..756a3928 100644 --- a/Docs/src/registry.but +++ b/Docs/src/registry.but @@ -144,6 +144,12 @@ This command writes a block of binary data to the registry. Valid values for roo \c WriteRegBin HKLM "Software\My Company\My Software" "Binary Value" DEADBEEF01223211151 +\S2{writeregnone} WriteRegNone + +\c root_key subkey key_name + +Writes a value without data to the registry. + \S2{writeregdword} WriteRegDWORD \c root_key subkey key_name value diff --git a/Examples/example1.nsi b/Examples/example1.nsi index 81dc9979..89c04943 100644 --- a/Examples/example1.nsi +++ b/Examples/example1.nsi @@ -4,6 +4,8 @@ ; optional settings are left to their default settings. The installer simply ; prompts the user asking them where to install, and drops a copy of example1.nsi ; there. +; +; example2.nsi expands on this by adding a uninstaller and start menu shortcuts. ;-------------------------------- diff --git a/Examples/example2.nsi b/Examples/example2.nsi index 74d44ed4..791d7702 100644 --- a/Examples/example2.nsi +++ b/Examples/example2.nsi @@ -3,7 +3,10 @@ ; This script is based on example1.nsi, but it remember the directory, ; has uninstall support and (optionally) installs start menu shortcuts. ; -; It will install example2.nsi into a directory that the user selects, +; It will install example2.nsi into a directory that the user selects. +; +; See install-shared.nsi for a more robust way of checking for administrator rights. +; See install-per-user.nsi for a file association example. ;-------------------------------- @@ -13,7 +16,7 @@ Name "Example2" ; The file to write OutFile "example2.exe" -; Request application privileges for Windows Vista +; Request application privileges for Windows Vista and higher RequestExecutionLevel admin ; Build Unicode installer @@ -66,9 +69,9 @@ SectionEnd Section "Start Menu Shortcuts" CreateDirectory "$SMPROGRAMS\Example2" - CreateShortcut "$SMPROGRAMS\Example2\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 - CreateShortcut "$SMPROGRAMS\Example2\Example2 (MakeNSISW).lnk" "$INSTDIR\example2.nsi" "" "$INSTDIR\example2.nsi" 0 - + CreateShortcut "$SMPROGRAMS\Example2\Uninstall.lnk" "$INSTDIR\uninstall.exe" + CreateShortcut "$SMPROGRAMS\Example2\Example2 (MakeNSISW).lnk" "$INSTDIR\example2.nsi" + SectionEnd ;-------------------------------- @@ -86,9 +89,9 @@ Section "Uninstall" Delete $INSTDIR\uninstall.exe ; Remove shortcuts, if any - Delete "$SMPROGRAMS\Example2\*.*" + Delete "$SMPROGRAMS\Example2\*.lnk" - ; Remove directories used + ; Remove directories RMDir "$SMPROGRAMS\Example2" RMDir "$INSTDIR" diff --git a/Examples/install-per-user.nsi b/Examples/install-per-user.nsi index 85128135..7fcebb42 100644 --- a/Examples/install-per-user.nsi +++ b/Examples/install-per-user.nsi @@ -43,6 +43,9 @@ Function .onInit ${EndIf} FunctionEnd +Function un.onInit + SetShellVarContext Current +FunctionEnd Section "Program files (Required)" SectionIn Ro @@ -50,29 +53,114 @@ Section "Program files (Required)" SetOutPath $InstDir WriteUninstaller "$InstDir\Uninst.exe" WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "DisplayName" "${NAME}" + WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "DisplayIcon" "$InstDir\MyApp.exe,0" WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "UninstallString" '"$InstDir\Uninst.exe"' WriteRegDWORD HKCU "${REGPATH_UNINSTSUBKEY}" "NoModify" 1 WriteRegDWORD HKCU "${REGPATH_UNINSTSUBKEY}" "NoRepair" 1 File "/oname=$InstDir\MyApp.exe" "${NSISDIR}\Bin\MakeLangId.exe" ; Pretend that we have a real application to install - - ;WriteRegStr HKCU "Software\Classes\.myfileext" "myfiletype" - ;WriteRegStr HKCU "Software\Classes\myfiletype\shell\myapp\command" "" '"$InstDir\MyApp.exe" "%1"' SectionEnd Section "Start Menu shortcut" CreateShortcut /NoWorkingDir "$SMPrograms\${NAME}.lnk" "$InstDir\MyApp.exe" SectionEnd +/* +This Section registers a fictional .test-nullsoft file extension and the Nullsoft.Test ProgId. +Proprietary file types are encouraged (by Microsoft) to use long file extensions and ProgIds that include the company name. + +When registering with "Open With" your executable should ideally have a somewhat unique name, +otherwise there could be a naming collision with a different application (with the same name) installed on the same machine. + +REGISTER_DEFAULTPROGRAMS is not defined because proprietary file types do not typically use the Default Programs functionality. +If your application registers a standard file type such as .mp3 or .html or a protocol like HTTP it should register as a Default Program. +It should also register as a client (https://docs.microsoft.com/en-us/windows/win32/shell/reg-middleware-apps#common-registration-elements-for-all-client-types). +*/ +!define ASSOC_EXT ".test-nullsoft" +!define ASSOC_PROGID "Nullsoft.Test" +!define ASSOC_VERB "MyApp" +!define ASSOC_APPEXE "MyApp.exe" +Section -ShellAssoc + # Register file type + WriteRegStr ShCtx "Software\Classes\${ASSOC_PROGID}\DefaultIcon" "" "$InstDir\${ASSOC_APPEXE},0" + ;WriteRegStr ShCtx "Software\Classes\${ASSOC_PROGID}\shell\${ASSOC_VERB}" "" "Nullsoft Test App" [Optional] + ;WriteRegStr ShCtx "Software\Classes\${ASSOC_PROGID}\shell\${ASSOC_VERB}" "MUIVerb" "@$InstDir\${ASSOC_APPEXE},-42" ; WinXP+ [Optional] Localizable verb display name + WriteRegStr ShCtx "Software\Classes\${ASSOC_PROGID}\shell\${ASSOC_VERB}\command" "" '"$InstDir\${ASSOC_APPEXE}" "%1"' + WriteRegStr ShCtx "Software\Classes\${ASSOC_EXT}" "" "${ASSOC_PROGID}" + + # Register "Open With" [Optional] + WriteRegNone ShCtx "Software\Classes\${ASSOC_EXT}\OpenWithList" "${ASSOC_APPEXE}" ; Win2000+ [Optional] + ;WriteRegNone ShCtx "Software\Classes\${ASSOC_EXT}\OpenWithProgids" "${ASSOC_PROGID}" ; WinXP+ [Optional] + WriteRegStr ShCtx "Software\Classes\Applications\${ASSOC_APPEXE}\shell\open\command" "" '"$InstDir\${ASSOC_APPEXE}" "%1"' + WriteRegStr ShCtx "Software\Classes\Applications\${ASSOC_APPEXE}" "FriendlyAppName" "Nullsoft Test App" ; [Optional] + WriteRegStr ShCtx "Software\Classes\Applications\${ASSOC_APPEXE}" "ApplicationCompany" "Nullsoft" ; [Optional] + WriteRegNone ShCtx "Software\Classes\Applications\${ASSOC_APPEXE}\SupportedTypes" "${ASSOC_EXT}" ; [Optional] Only allow "Open With" with specific extension(s) on WinXP+ + + # Register "Default Programs" [Optional] + !ifdef REGISTER_DEFAULTPROGRAMS + WriteRegStr ShCtx "Software\Classes\Applications\${ASSOC_APPEXE}\Capabilities" "ApplicationDescription" "Shell association example test application" + WriteRegStr ShCtx "Software\Classes\Applications\${ASSOC_APPEXE}\Capabilities\FileAssociations" "${ASSOC_EXT}" "${ASSOC_PROGID}" + WriteRegStr ShCtx "Software\RegisteredApplications" "Nullsoft Test App" "Software\Classes\Applications\${ASSOC_APPEXE}\Capabilities" + !endif + + System::Call 'SHELL32::SHChangeNotify(i0x08000000, i0, p0, p0)' ; Notify the shell with SHCNE_ASSOCCHANGED +SectionEnd + + +Section -un.ShellAssoc + # Unregister file type + ClearErrors + DeleteRegKey ShCtx "Software\Classes\${ASSOC_PROGID}\shell\${ASSOC_VERB}" + DeleteRegKey /IfEmpty ShCtx "Software\Classes\${ASSOC_PROGID}\shell" + ${IfNot} ${Errors} + DeleteRegKey ShCtx "Software\Classes\${ASSOC_PROGID}\DefaultIcon" + ${EndIf} + ReadRegStr $0 ShCtx "Software\Classes\${ASSOC_EXT}" "" + DeleteRegKey /IfEmpty ShCtx "Software\Classes\${ASSOC_PROGID}" + ${IfNot} ${Errors} + ${AndIf} $0 == "${ASSOC_PROGID}" + DeleteRegValue ShCtx "Software\Classes\${ASSOC_EXT}" "" + DeleteRegKey /IfEmpty ShCtx "Software\Classes\${ASSOC_EXT}" + ${EndIf} + + # Unregister "Open With" + DeleteRegKey ShCtx "Software\Classes\Applications\${ASSOC_APPEXE}" + DeleteRegValue ShCtx "Software\Classes\${ASSOC_EXT}\OpenWithList" "${ASSOC_APPEXE}" + DeleteRegKey /IfEmpty ShCtx "Software\Classes\${ASSOC_EXT}\OpenWithList" + DeleteRegValue ShCtx "Software\Classes\${ASSOC_EXT}\OpenWithProgids" "${ASSOC_PROGID}" + DeleteRegKey /IfEmpty ShCtx "Software\Classes\${ASSOC_EXT}\OpenWithProgids" + DeleteRegKey /IfEmpty ShCtx "Software\Classes\${ASSOC_EXT}" + + # Unregister "Default Programs" + !ifdef REGISTER_DEFAULTPROGRAMS + DeleteRegValue ShCtx "Software\RegisteredApplications" "Nullsoft Test App" + DeleteRegKey ShCtx "Software\Classes\Applications\${ASSOC_APPEXE}\Capabilities" + DeleteRegKey /IfEmpty ShCtx "Software\Classes\Applications\${ASSOC_APPEXE}" + !endif + + # Attempt to clean up junk left behind by the Windows shell + DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Search\JumplistData" "$InstDir\${ASSOC_APPEXE}" + DeleteRegValue HKCU "Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\MuiCache" "$InstDir\${ASSOC_APPEXE}.FriendlyAppName" + DeleteRegValue HKCU "Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\MuiCache" "$InstDir\${ASSOC_APPEXE}.ApplicationCompany" + DeleteRegValue HKCU "Software\Microsoft\Windows\ShellNoRoam\MUICache" "$InstDir\${ASSOC_APPEXE}" ; WinXP + DeleteRegValue HKCU "Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Compatibility Assistant\Store" "$InstDir\${ASSOC_APPEXE}" + DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\ApplicationAssociationToasts" "${ASSOC_PROGID}_${ASSOC_EXT}" + DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\ApplicationAssociationToasts" "Applications\${ASSOC_APPEXE}_${ASSOC_EXT}" + DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\${ASSOC_EXT}\OpenWithProgids" "${ASSOC_PROGID}" + DeleteRegKey /IfEmpty HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\${ASSOC_EXT}\OpenWithProgids" + DeleteRegKey /IfEmpty HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\${ASSOC_EXT}\OpenWithList" + DeleteRegKey /IfEmpty HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\${ASSOC_EXT}" + ;DeleteRegKey HKCU "Software\Microsoft\Windows\Roaming\OpenWith\FileExts\${ASSOC_EXT}" + ;DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs\${ASSOC_EXT}" + + System::Call 'SHELL32::SHChangeNotify(i0x08000000, i0, p0, p0)' ; Notify the shell with SHCNE_ASSOCCHANGED +SectionEnd Section -Uninstall Delete "$InstDir\MyApp.exe" Delete "$InstDir\Uninst.exe" RMDir "$InstDir" DeleteRegKey HKCU "${REGPATH_UNINSTSUBKEY}" - ;DeleteRegKey HKCU "Software\Classes\myfiletype\shell\myapp" - ;DeleteRegKey /IfEmpty HKCU "Software\Classes\myfiletype\shell" - ;DeleteRegKey /IfEmpty HKCU "Software\Classes\myfiletype" Delete "$SMPrograms\${NAME}.lnk" SectionEnd diff --git a/Examples/install-shared.nsi b/Examples/install-shared.nsi index df52eeaf..c5964e89 100644 --- a/Examples/install-shared.nsi +++ b/Examples/install-shared.nsi @@ -56,14 +56,12 @@ Section "Program files (Required)" SetOutPath $InstDir WriteUninstaller "$InstDir\Uninst.exe" WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "DisplayName" "${NAME}" + WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "DisplayIcon" "$InstDir\MyApp.exe,0" WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "UninstallString" '"$InstDir\Uninst.exe"' WriteRegDWORD HKLM "${REGPATH_UNINSTSUBKEY}" "NoModify" 1 WriteRegDWORD HKLM "${REGPATH_UNINSTSUBKEY}" "NoRepair" 1 File "/oname=$InstDir\MyApp.exe" "${NSISDIR}\Bin\MakeLangId.exe" ; Pretend that we have a real application to install - - ;WriteRegStr HKLM "Software\Classes\.myfileext" "myfiletype" - ;WriteRegStr HKLM "Software\Classes\myfiletype\shell\myapp\command" "" '"$InstDir\MyApp.exe" "%1"' SectionEnd Section "Start Menu shortcut" @@ -76,9 +74,6 @@ Section -Uninstall Delete "$InstDir\Uninst.exe" RMDir "$InstDir" DeleteRegKey HKLM "${REGPATH_UNINSTSUBKEY}" - ;DeleteRegKey HKLM "Software\Classes\myfiletype\shell\myapp" - ;DeleteRegKey /IfEmpty HKLM "Software\Classes\myfiletype\shell" - ;DeleteRegKey /IfEmpty HKLM "Software\Classes\myfiletype" Delete "$SMPrograms\${NAME}.lnk" SectionEnd diff --git a/Source/exehead/fileform.h b/Source/exehead/fileform.h index a33797a8..38d1e0e5 100644 --- a/Source/exehead/fileform.h +++ b/Source/exehead/fileform.h @@ -552,6 +552,7 @@ typedef struct { #define DELREG_KEY 1 // TOK_DELETEREGKEY #define DELREGKEY_ONLYIFNOSUBKEYS 0x01 // Note: Shifted (stored as 2 in the binary) for compatibility with <= v3.1 #define DELREGKEY_ONLYIFNOVALUES 0x02 +// DELREGKEY_SAMVIEWMASK REGROOTVIEWTOSAMVIEW(REGROOTVIEW32|REGROOTVIEW64) // Reserved for KEY_WOW64_xxKEY, cannot be used as flags! #define DELREGKEYFLAGSSHIFT 1 // exehead removes the DELREG_KEY bit in parm4 by shifting. After shifting the bits are DELREGKEY_*.