views:

184

answers:

4

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?

+1  A: 
Anders Abel
My software registers both standard file types (JPEG, GIF, PNG, TIFF) and non-standard (SVG, JPEG2000, 40+ others) - so I wanted to use Default Programs to manage all of those. Plus I see that a lot of software (for example Foobar2000 or Media Player Classic Home Cinema) lately started using Default Programs API for managing all of their associations, including non-standard ones. So I'm not sure what to do still...
Alex T.
A: 

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:

  1. Saving the "old" settings, before installing your application (BTW, it's nice that you are doing that. Many applications simply remove the mapping altogether!)

  2. 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:

  3. 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!

Etamar L.
That's the way my code for WindowsXP works (and that's not what I was asking about).
Alex T.
A: 

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.

Franci Penov
Thank you! I'm going to do it in this way (hopefully Microsoft will add missing bits in Windows 8 ).
Alex T.
A: 

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

Charles Gargent
This is not an option unfortunately, as I should give user option to change associations after installation (and with ability to add plug-ins the installer won't know all extensions anyway).
Alex T.