1
mirror of https://invent.kde.org/network/falkon.git synced 2024-09-21 17:52:10 +02:00
falkonOfficial/windows/AllAssociation.nsh
S. Razi Alavizadeh 25410eb00f NSIS script improved:
-'FileAssociation.nsh' rewritten and renamed to 'AllAssociation.nsh'
-Now supports new association method on Vista and newer version of Windows.
-Support register as protocol handler and add option for set as default browser.
-Backup old association even on Vista and newer version of Windows and restore them when uninstalling.
-Support 'Default Programs' on Vista and newer version of Windows.
2012-11-19 21:59:04 +03:30

457 lines
14 KiB
Plaintext

/*
_____________________________________________________________________________
All Association
_____________________________________________________________________________
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Date: 2012-Nov-18, S. Razi Alavizadeh, v0.1 ;
; Some Codes are based on code taken from: ;
; http://nsis.sourceforge.net/File_Association ;
; Ability to register protocol and extention associations. ;
; It supports old association method and new method by using ;
; IApplicationAssociationRegistration APIs. ;
; that needed 'AppAssocReg' plugins, downloadable from: ;
; http://nsis.sourceforge.net/SetVistaDefaultApp_plug-in ;
; and also add support for set as default backuped association when ;
; uninstalling. This needed 'Registery' plugins. ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Requirment:
1. 'AppAssocReg' plugins.
2. 'Registery' plugins.
Usage in script:
1. !include "AllAssociation.nsh"
2. [Section|Function]
${AllAssociationFunction} "Param1" "Param2" "..." $var
[SectionEnd|FunctionEnd]
AllAssociationFunction=[RegisterAssociation|UnRegisterAssociation|CreateProgId|UpdateSystemIcons|SetAsDefaultNoAppName]
_____________________________________________________________________________
${RegisterAssociation} "[assoc_name]" "[executable]" "[prog_id]" "[description]" "[icon]" "[type]"
"[assoc_name]" ; assoc_name, which is file format's extention if type is "file" and is protocol's name if type is "protocol".
;
"[executable]" ; executable which opens the file format or is protocol handler.
;
"[prog_id]" ; registery internal id for assoc_name, on Vista+ if type is "protocol" this is our registered ProgId for assoc_name and is used for comparison.
;
"[description]" ; description for the assoc_name. This will be display in Windows Explorer.
;
"[icon]" ; icon path for this association.
;
"[type]" ; type of association. "file" for extention and "protocol" for protocol handler.
;
${UnRegisterAssociation} "[assoc_name]" "[prog_id]" "[executable]" "[type]"
"[assoc_name]" ; assoc_name, which is file format's extention if type is "file" and is protocol's name if type is "protocol".
;
"[prog_id]" ; registery internal id for assoc_name
;
"[executable]" ; executable which opens the file format or is protocol handler.
;
"[type]" ; type of association. "file" for extention and "protocol" for protocol handler.
;
${CreateProgId} "[prog_id]" "[executable]" "[description]" "[icon]"
"[prog_id]" ; registery internal id for assoc_name
;
"[executable]" ; executable which opens the file format or is protocol handler.
;
"[description]" ; description for the assoc_name. This will be display in Windows Explorer.
;
"[icon]" ; icon path for this prog_id.
;
${SetAsDefaultNoAppName} "[prog_id]" "[assoc_name]" "[type]"
"[prog_id]" ; registery internal id for assoc_name
;
"[assoc_name]" ; assoc_name, which is file format's extention if type is "file" and is protocol's name if type is "protocol".
;
"[type]" ; type of association. "file" for extention and "protocol" for protocol handler.
;
${UpdateSystemIcons} ; it has not arguments and just notifies OS for updating icons for new associations.
_____________________________________________________________________________
Macros
_____________________________________________________________________________
Change log window verbosity (default: 3=no script)
Example:
!include "AllAssociation.nsh"
!insertmacro RegisterAssociation
${AllAssociation_VERBOSE} 4 # all verbosity
!insertmacro UnRegisterAssociation
${AllAssociation_VERBOSE} 3 # no script
*/
!ifndef AllAssociation_INCLUDED
!define AllAssociation_INCLUDED
!include Util.nsh
!verbose push
!verbose 3
!ifndef _AllAssociation_VERBOSE
!define _AllAssociation_VERBOSE 3
!endif
!verbose ${_AllAssociation_VERBOSE}
!define AllAssociation_VERBOSE `!insertmacro AllAssociation_VERBOSE`
!verbose pop
!macro AllAssociation_VERBOSE _VERBOSE
!verbose push
!verbose 3
!undef _AllAssociation_VERBOSE
!define _AllAssociation_VERBOSE ${_VERBOSE}
!verbose pop
!macroend
; define some registery macros
!define RegistryRead `!insertmacro RegistryRead`
!macro RegistryRead _PATH _VALUE _STRING _TYPE
registry::_Read /NOUNLOAD `${_PATH}` `${_VALUE}`
Pop ${_STRING}
Pop ${_TYPE}
!macroend
!define RegistryWrite `!insertmacro RegistryWrite`
!macro RegistryWrite _PATH _VALUE _STRING _TYPE _ERR
registry::_Write /NOUNLOAD `${_PATH}` `${_VALUE}` `${_STRING}` `${_TYPE}`
Pop ${_ERR}
!macroend
!define RegistryFind `!insertmacro RegistryFind`
!macro RegistryFind _HANDLE _PATH _VALUEORKEY _STRING _TYPE
registry::_Find /NOUNLOAD `${_HANDLE}`
Pop ${_PATH}
Pop ${_VALUEORKEY}
Pop ${_STRING}
Pop ${_TYPE}
!macroend
!define RegistryOpen `!insertmacro RegistryOpen`
!macro RegistryOpen _PATH _OPTIONS _HANDLE
registry::_Open /NOUNLOAD `${_PATH}` `${_OPTIONS}`
Pop ${_HANDLE}
!macroend
!macro RegisterAssociationCall _EXTENSION _EXECUTABLE _PROG_ID _DESCRIPTION _ICON _TYPE
!verbose push
!verbose ${_AllAssociation_VERBOSE}
Push `${_EXECUTABLE}`
Push `${_PROG_ID}`
Push `${_DESCRIPTION}`
Push `${_ICON}`
${CallArtificialFunction} CreateProgId_
Push `${_PROG_ID}`
Push `${_EXECUTABLE}`
Push `${_EXTENSION}`
Push `${_TYPE}`
${CallArtificialFunction} RegisterAssociation_
!verbose pop
!macroend
!macro UnRegisterAssociationCall _EXTENSION _PROG_ID _EXECUTABLE _TYPE
!verbose push
!verbose ${_AllAssociation_VERBOSE}
Push `${_EXTENSION}`
Push `${_EXECUTABLE}`
Push `${_PROG_ID}`
Push `${_TYPE}`
${CallArtificialFunction} UnRegisterAssociation_
; backuped ProgId was pushed from UnRegisterAssociation_
Push `${_EXTENSION}`
Push `${_TYPE}` ; type of association
${CallArtificialFunction} SetAsDefaultNoAppName_
!verbose pop
!macroend
!macro CreateProgIdCall _PROG_ID _EXECUTABLE _DESCRIPTION _ICON
!verbose push
!verbose ${_AllAssociation_VERBOSE}
Push `${_EXECUTABLE}`
Push `${_PROG_ID}`
Push `${_DESCRIPTION}`
Push `${_ICON}`
${CallArtificialFunction} CreateProgId_
!verbose pop
!macroend
!macro SetAsDefaultNoAppNameCall _PROG_ID _EXTENSION _TYPE
!verbose push
!verbose ${_AllAssociation_VERBOSE}
Push `${_PROG_ID}`
Push `${_EXTENSION}`
Push `${_TYPE}`
${CallArtificialFunction} SetAsDefaultNoAppName_
!verbose pop
!macroend
!define SetAsDefaultNoAppName `!insertmacro SetAsDefaultNoAppNameCall`
!define un.SetAsDefaultNoAppName `!insertmacro SetAsDefaultNoAppNameCall`
!macro SetAsDefaultNoAppName
!macroend
!macro un.SetAsDefaultNoAppName
!macroend
!macro SetAsDefaultNoAppName_
!verbose push
!verbose ${_AllAssociation_VERBOSE}
Pop $R0 ; TYPE
Pop $R1 ; EXTENSION
Pop $R2 ; PROG_ID
StrCmp $R2 "No ProgId Pushed" NoBackupedProgId 0
StrCmp $R2 "" NoBackupedProgId 0
StrCmp $R1 "" NoBackupedProgId 0
${RegistryOpen} "HKLM\SOFTWARE\RegisteredApplications" "/K=0 /V=1 /S=0 /B=1" $R8 ; R8 = first registery handle
StrCmp $R8 0 close 0
loop1:
${RegistryFind} "$R8" $1 $R3 $3 $4 ; $R3 = AppRegisteredName
StrCmp $1 "" close 0
${RegistryOpen} "HKLM\$3" "/K=0 /V=1 /S=0 /B=1 /N='$R1'" $R9 ; R9 = second registery handle
StrCmp $R9 0 loop1 0
loop2:
${RegistryFind} "$R9" $1 $2 $R4 $4 ; $R4 = ProgId registered for EXTENSION
StrCmp $1 "" loop1 0
StrCmp $R4 "$R2" 0 loop2
AppAssocReg::SetAppAsDefault "$R3" "$R1" "$R0"
close:
registry::_Close /NOUNLOAD "$R9"
registry::_Close /NOUNLOAD "$R8"
registry::_Unload
NoBackupedProgId:
!verbose pop
!macroend
!define CreateProgId `!insertmacro CreateProgIdCall`
!define un.CreateProgId `!insertmacro CreateProgIdCall`
!macro CreateProgId
!macroend
!macro un.CreateProgId
!macroend
!macro CreateProgId_
!verbose push
!verbose ${_AllAssociation_VERBOSE}
Pop $R0 ;ICON
Pop $R1 ;DESCRIPTION
Pop $R2 ;PROG_ID
Pop $R3 ;EXECUTABLE
ReadRegStr $0 HKCR $R2 ""
; StrCmp $0 "" 0 JustSkip ; if icon and description are present then just skip
WriteRegStr HKCR "$R2" "" "$R1"
WriteRegStr HKCR "$R2\shell" "" "open"
WriteRegStr HKCR "$R2\DefaultIcon" "" "$R0"
;JustSkip:
WriteRegStr HKCR "$R2\shell\open\command" "" '"$R3" "%1"'
WriteRegStr HKCR "$R2\shell\edit" "" "Edit $R1"
WriteRegStr HKCR "$R2\shell\edit\command" "" '"$R3" "%1"'
!verbose pop
!macroend
!define RegisterAssociation `!insertmacro RegisterAssociationCall`
!define un.RegisterAssociation `!insertmacro RegisterAssociationCall`
!macro RegisterAssociation
!macroend
!macro un.RegisterAssociation
!macroend
!macro RegisterAssociation_
!verbose push
!verbose ${_AllAssociation_VERBOSE}
Pop $R0 ;type = file or protocol
Pop $R1 ;association name = ext or protocol
Pop $R2 ;exe
Pop $R3 ;prog_id
StrCmp "$R0" "file" 0 NoFile
; file
ReadRegStr $1 HKCR $R1 "" ; read current file association
StrCmp "$1" "" NoFileExtBackup ; is it empty
StrCmp "$1" "$R3" NoFileExtBackup ; it is our own
WriteRegStr HKCR $R1 "backup_val" "$1" ; backup current value
NoFileExtBackup:
WriteRegStr HKCR $R1 "" "$R3" ; set our file association
Goto VistaPlus
NoFile:
; Protocol
StrCmp "$R0" "protocol" 0 NotSupported
; write protocol flag
WriteRegStr HKCR $R1 "URL Protocol" ""
;get prog_id of current default
AppAssocReg::QueryCurrentDefault $R1 "protocol" "user"
Pop $1
StrCmp "$1" "method failed" NoProgID 0
StrCmp "$1" "method not available" NoProgID 0
StrCmp "$1" "$R3" NoProgID 0 ; it is our own
WriteRegStr HKCR "$R1\shell\open\command" "backup_progid" "$1" ; backup current progid
NoProgID:
; ReadRegStr $1 HKCR "$R1\shell\open\command" "" ; read current protocol association
; some applications write this as REG_EXPAND_SZ and don't work with REG_SZ (e.g.: some version of Opera)
${RegistryRead} "HKCR\$R1\shell\open\command" "" '$1' '$0' ; read current protocol association and its registery type
StrCmp "$1" "" NoProtocolBackup ; is it empty
StrCmp "$1" '"$R2" "%1"' NoProtocolBackup ; it is our own
;WriteRegStr HKCR "$R1\shell\open\command" "backup_val" "$1" ; backup current value
${RegistryWrite} "HKCR\$R1\shell\open\command" "backup_val" '$1' '$0' '$2'; backup current value and its registery type
NoProtocolBackup:
WriteRegStr HKCR "$R1\shell\open\command" "" '"$R2" "%1"' ; set our file association
;Goto VistaPlus
; TODO: type = startMenu or type = mime
VistaPlus:
;Vista and newer need some more works
AppAssocReg::SetAppAsDefault "${PRODUCT_NAME}" "$R1" "$R0"
NotSupported:
registry::_Unload
!verbose pop
!macroend
!define UnRegisterAssociation `!insertmacro UnRegisterAssociationCall`
!define un.UnRegisterAssociation `!insertmacro UnRegisterAssociationCall`
!macro UnRegisterAssociation
!macroend
!macro un.UnRegisterAssociation
!macroend
!macro UnRegisterAssociation_
!verbose push
!verbose ${_AllAssociation_VERBOSE}
Pop $R3 ;type = file or protocol
Pop $R2 ;prog_id
Pop $R1 ;exe
Pop $R0 ;association name = ext or protocol
StrCmp "$R3" "file" 0 NoFile
; file
ReadRegStr $1 HKCR $R0 ""
StrCmp $1 $R2 0 NoOwn ; only do this if we own it
ReadRegStr $1 HKCR $R0 "backup_val"
StrCmp $1 "" 0 RestoreFile ; if backup="" then delete the whole key
Push `"No ProgId Pushed"`
DeleteRegKey HKCR $R0
Goto NoOwn
RestoreFile:
Push `$1`
WriteRegStr HKCR $R0 "" $1
DeleteRegValue HKCR $R0 "backup_val"
DeleteRegKey HKCR $R2 ;Delete key with association name settings
Goto NoOwn
NoFile:
; Protocol
StrCmp "$R3" "protocol" 0 NoOwn
ReadRegStr $1 HKCR "$R0\shell\open\command" ""
StrCmp $1 '"$R1" "%1"' 0 NoOwn ; only do this if we own it
; ReadRegStr $1 HKCR "$R0\shell\open\command" "backup_val"
${RegistryRead} "HKEY_CLASSES_ROOT\$R0\shell\open\command" "backup_val" '$1' '$0' ; read current protocol association and its registery type
StrCmp $1 "" 0 RestoreProtocol ; if backup="" then delete the whole key
Push `"No ProgId Pushed"`
DeleteRegKey HKCR "$R0\shell\open\command"
Goto NoOwn
RestoreProtocol:
ReadRegStr $2 HKCR "$R0\shell\open\command" "backup_progid"
StrCmp $2 "" 0 HasProgId
Push `"No ProgId Pushed"`
Goto NoProgID
HasProgId:
Push `$2`
NoProgID:
;WriteRegStr HKCR "$R0\shell\open\command" "" $1
${RegistryWrite} "HKEY_CLASSES_ROOT\$R0\shell\open\command" "" '$1' '$0' '$2'
DeleteRegValue HKCR "$R0\shell\open\command" "backup_val"
DeleteRegValue HKCR "$R0\shell\open\command" "backup_progid"
StrCmp $R2 "" NoOwn 0 ;Delete protocol association if it's present
DeleteRegKey HKCR $R2 ;Delete key with association name settings
;Goto NoOwn
; TODO: type = startMenu or type = mime
NoOwn:
registry::_Unload
!verbose pop
!macroend
!define UpdateSystemIcons `!insertmacro UpdateSystemIcons_`
!define un.UpdateSystemIcons `!insertmacro UpdateSystemIcons_`
!macro UpdateSystemIcons
!macroend
!macro un.UpdateSystemIcons
!macroend
; !defines for use with SHChangeNotify
!ifdef SHCNE_ASSOCCHANGED
!undef SHCNE_ASSOCCHANGED
!endif
!define SHCNE_ASSOCCHANGED 0x08000000
!ifdef SHCNF_FLUSHNOWAIT
!undef SHCNF_FLUSHNOWAIT
!endif
!define SHCNF_FLUSHNOWAIT 0x3000
!macro UpdateSystemIcons_
; 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_FLUSHNOWAIT}, 0, 0)"
!macroend
!endif # !AllAssociation_INCLUDED