I have a requirement to (force) change the file association for a particular file type (extenison ".theext" ) to open with "myapp.exe" when installing an app using NSIS.
I've read a few suggestions of how to achieve this, so currentky this is what I have in my NSIS script:
DeleteRegKey HKCR ".theext"
DeleteRegKey HKLM ".theext"
DeleteRegKey HKCU ".theext"
WriteRegStr HKCR ".theext" "" "theextfile"
WriteRegStr HKCR "theextfile" "" "My App Document"
WriteRegStr HKCR "theextfile\DefaultIcon" "" "$INSTDIR\${EXENAME}.exe,0"
WriteRegStr HKCR "theextfile\shell\open\command" "" '"$INSTDIR\${EXENAME}.exe" "%1"'
WriteRegStr HKCR "theextfile\shell\print\command" "" '"$INSTDIR\${EXENAME}.exe" /p "%1"'
WriteRegStr HKLM "Software\RegisteredApplications" "${EXENAME}" "$INSTDIR\${EXENAME}.exe"
WriteRegStr HKCU "Software\RegisteredApplications" "${EXENAME}" "$INSTDIR\${EXENAME}.exe"
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.theext\OpenWithList" "a" "$INSTDIR\${EXENAME}.exe"
To test this, I set the file assoc using WIndows 7 Explorer to GVIM.exe.
Since doing this, every time I run the installer, Windows 7 still opens the file on double click using GVim, and not "MyApp.exe".
But when I check the file associatin as follows, all seems fine:
ftype | findstr /i theext
Gives:
theextfile="C:\Program File (x86)\My App\myapp.exe" "%1"
You are doing everything you are supposed to do and if the extension is not already registered by somebody else you will become the default. You are not really supposed to delete the old keys first though (it can screw up the system but it will never help you become default). Forcing something is evil, the user is supposed to be in control.
Because people forced this in the past Microsoft starting making it harder to change the default. The undocumented FileExts
key stores the users chosen default in the UserChoice
sub-keys. In newer versions of Windows (8+?) the default is verified with some secret hash so you cannot override it.
The IApplicationAssociationRegistration
interface does not work in newer version of Windows but it might work in Windows 7:
!include Win\COM.nsh
!include WinCore.nsh
!insertmacro ComHlpr_CreateInProcInstance ${CLSID_ApplicationAssociationRegistration} ${IID_IApplicationAssociationRegistration} r0 ""
${If} $0 P<> 0
${IApplicationAssociationRegistration::SetAppAsDefault} $0 '("MyApp", ".myext", ${AT_FILEEXTENSION})'
${IUnknown::Release} $0 ""
${EndIf}
In Windows 8 all you can do is launch the generic UI:
!include Win\COM.nsh
!insertmacro ComHlpr_CreateInProcInstance ${CLSID_ApplicationAssociationRegistrationUI} ${IID_IApplicationAssociationRegistrationUI} r0 ""
${If} $0 P<> 0
${IApplicationAssociationRegistrationUI::LaunchAdvancedAssociationUI} $0 '("Wordpad")' ; Replace with your name from the RegisteredApplications key
${IUnknown::Release} $0 ""
${EndIf}
In Windows 10 even this is gone, it will just display a toast telling the user to change their settings if you call LaunchAdvancedAssociationUI.
ftype
does not know the true default, the default is only known when Windows actually runs the association code in the shell. IApplicationAssociationRegistration::QueryCurrentDefault
is better at guessing the default but even it can fail if the default is actually a COM shell extension that overrides the default.