Windows Vista, Default Programs API, file format associations, and (un)installers - explosive mix!
My application is a rather well behaved Windows citizen, so when I ported it to Windows Vista/7 I replaced my custom file format association code with support for the Default Programs API. However I ran into a problem when trying to make uninstaller for my application - there seems to be no way to remove file format associations via Default Programs API.
I tried to call IApplicationAssociationRegistration::ClearUserAssociations but it actually removes all associations, including the ones for other applications - completely restoring default state of the OS (which is of course unacceptable).
I tried to call IApplicationAssociationRegistration::SetAppAsDefault to return file format associations to the previous "owner" - but it does not开发者_运维技巧 help, because my application handles many unique file formats which the OS does not support and there is no previous "owners". And Windows does not allow to pass empty strings to SetAppAsDefault...
So what do I do? Any good solutions?
I think that you are using the Default Programs API in the wrong way. If I understand correctly the default programs functionality was added by Microsoft due to legal requirements to replace Internet Explorer as the default browser. It offers another set of functionality than the normal file associations used by aplications. If you just have a simple file association to register, I'd suggest you stick to the old behaviour.
From MSDN:Default Programs (Windows):
Default Programs is primarily designed for applications that use standard file types such as .mp3 or .jpg files or standard protocols, such as HTTP or mailto. Applications that use their own proprietary protocols and file associations do not typically use the Default Programs functionality.
Side note: All the considerations below apply even if you modify directly the file associations in the registry instead of using the Default Programs API.
On first run, your application should collect the previous owners of all the file types for which one exists, through IApplicationAssociationRegistration::QueryCurrentDefault
and store them in storage your app owns.
On uninstall, your application should use IApplicationAssociationRegistration::SetAppAsDefault
to attempt to restore any file association it still owns to the previous owner it has. For associations your app still owns, but don't know previous owners, go to the HKCR
registry and delete the corresponding extension, protocol or MIME type entry. Don't touch any associations your app is not the current owner - you'll be overwriting the user's choice.
I certainly wish that the batched backup on first run and cleanup on uninstall were provided as a single API call by the Default Programs API, but until they decide to generalize that behavior for all apps, you're on your own.
Note that the cleanup your application executes on uninstall will be specific for the uninstalling user. Any other users that might have used the application and changed their defaults will not be cleaned up.
You can automate the cleanup for each user by adding a simple per-user task that executes the steps above in the Task Scheduler. The task will be scheduled to execute once and then removes itself from the user task scheduler. The only potential problem with that approach is that since you don't know how many users there will be, it's impossible for you to know when to remove the dll for that task from the machine. Then again, if you leave that dll in the ProgramData folder, it's not a big deal.
The correct code for associating your file extension with an application, is using the Windows Registry settings. Typically this is done to the entire machine (regardless of user) using the HKEY_LOCAL_MACHINE\SOFTWARE\Classes
registry hive, which is also accessible more conveniently through the HKEY_CLASSES_ROOT
alias (registry shortcut).
Your process involves three steps:
Saving the "old" settings, before installing your application (BTW, it's nice that you are doing that. Many applications simply remove the mapping altogether!)
Creating your own associations. A good example on how to perform this is at Modifying File Associations With Registry Editor. A thorough explanation is on MSDN:
When uninstalling, recover the saved "old" settings from step (1), and rewrite the installed values with these original ones. In case there were no "old" settings, a good citizenship would mean simply deleting the class key altogether from the registry.
One tool to assist in debugging and seeing how class (extension) mappings change is at FileAsoc Windows File Association Editor. It lets you recover file extensions while debugging your application. The webpage also gives a short explanation of how exactly the values are stored.
Hope this helps!
Instead of making the file associations in your app, make them in the installer. Using WiX you can create an installer that sets file associations on install and will remove them on uninstall
精彩评论