Click here to Skip to main content
Click here to Skip to main content

System File Association

By , 16 Mar 2007
 

Introduction

Ever wanted to programmatically associate a file type on the system with your application, but didn't like the idea of digging through the registry yourself? If so, then this article and code are right for you.

Background

File associations in Windows have two parts, the extension itself and the ProgID (programmatic identifier). While an extension does not have to be associated with any ProgID, if it is, it can only be associated with a single one. On the other hand, a ProgID can have multiple extensions associated with it.

The attached code includes classes such as:

  • FileAssociationInfo: provides properties to determine (or set) what ProgID the extension is associated with (ProgID), what sort of file the system considers it to be (PerceivedType), the MIME type of the file (ContentType), and what programs will appear in the extensions (OpenWithList).
  • ProgramAssociationInfo: functions similarly to FileAssociationInfo and provides properties to set how the shell should handle the file type (EditFlags), the command verbs and programs the ProgID supports (Verbs), and the file types icon (DefaultIcon).
  • AssociationManager: provides a simplistic method to determine if certain extensions are associated with a given ProgID. It also provides the ability to associate those types or to create a brand new association between already specified extensions and a ProgID.

Examples

Our first step is to create an instance of the FileAssociationInfo class and specify the extension we wish to deal with into the constructor. Next we see if the extension already exists and if it doesn't, we create it with the specified ProgID (MyProgramName), and then set up the optional ContentType and OpenWithList properties.

FileAssociationInfo fai = new FileAssociationInfo(".bob");
    if (!fai.Exists)
      {
         fai.Create("MyProgramName");

         //Specify MIME type (optional)
         fai.ContentType = "application/myfile";

         //Programs automatically displayed in open with list
         fai.OpenWithList = new string[]
        { "notepad.exe", "wordpad.exe", "someotherapp.exe" };
       }

Finally, we create an instance of the ProgramAssociationInfo class and specify the ProgID we wish to deal with in its constructor. Should this ProgID not exist, we create it and specify both a description for the program type (shared between all files using this ProgID) and the command verb that is used in selecting different ways to load the file.

ProgramAssociationInfo pai = new ProgramAssociationInfo(fai.ProgID);
    if (!pai.Exists)
      {
         pai.Create
         (
         //Description of program/file type
         "My Program's File Type",

         new ProgramVerb
              (
              //Verb name
              "Open",
              //Path and arguments to use
              @"C:\SomePath\MyApp.exe %1"
              )
            );

         //optional
         pai.DefaultIcon = new ProgramIcon(@"C:\SomePath\SomeIcon.ico");
       }

Full sample

The link at the top of this article includes a simplistic GUI that demonstrates all the capabilities of the FileAssociationInfo and ProgramAssociationInfo classes.

Word of warning

This code requires administrative access (especially under Vista) when used to create or modify extensions, and on some systems, it also requires elevated permission to read.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Brendan Grant
Web Developer
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe: ProgramIcon bug fix!memberikkentim31 Jan '12 - 10:35 
Thanks!
GeneralSome notes about file extensions on windowsmemberTheToid12 May '10 - 13:47 
It should be noted that the HKEY_CLASSES_ROOT key is actually a conglomerate view of the HKEY_LOCAL_MACHINE\Software\Classes AND the HKEY_CURRENT_USER\Software\Class, so please be careful, as sometimes one will override the other.
 
Also, when windows first launches a file association it creates a key under:
 
HKEY_CLASSES_ROOT\Software\Classes\Applications\{APPFILENAME}, where {APPFILENAME} is the filename including extension of the program associated, under this it will create a copy of the keys under the actual file association, this becomes the default when using the windows interface to create an association, which becomes a problem is the file pointed to under the Applications key no longer exists, as it stops the file from appearing in the open with list (even if you use the browse button), this key is not removed by the windows XP (maybe vista and 7 not sure) interface when going through the file types settings and restoring or deleting the association.
 
So if you have a problem where an association is not working be sure to check for this key and remove it.
 
One other place file assocations can be created is the Recommended Association list, this list can be found under:
 
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts
 
And lists the default recommended programs, as per usual microsoft makes everything more complication then it needs to be, I hope this message saves someone some time, i had to find this by trial and error in the registry because it dosnt appear to be mentioned anywhere else on the net.
GeneralGreat post, one commentmemberLimitedAtonement3 Feb '10 - 10:02 
Dear Mr. Grant,
 
I hope you get out of debt fast!
 
This is a great project. I was looking through it and found one little oopsie that you may want to know about, although I realize that you probably haven't touched this thing in a while. In AssociationGUIForm.cs, in the extensionsListBox_SelectedIndexChanged(object, EventArgs) around line 33 of that function, you have what seems like an identical if-then statement doing the same thing, but the second time around, also setting the tag for the textbox. It looks like you wanted to replace the first if-then, but instead, replicated it and added to it. If I see more, I'll let you know, but this is a great job. Nice Registry Wrapper!
 
In Christ,
Aaron Laws
 
http://ProCure.com

Generalthanks for the codememberwas830917 Sep '09 - 18:02 
Smile | :)
GeneralAssociations not Working for currently associated filesmemberPipSharp18 Aug '09 - 0:36 
Hi,
 
I was wondering if someone could give us a hand here. I've created my own classes which sets file assiciations in the registry, much similar to this project... it seems to work perfectly fine if I register my own custom file type, but if I want to change an existing extension (like .tif for instnace) to open in my app instead of the default or current app, it won't work until I go into the associated app's settings and (un)associate the file type.
 
I've scanned the registry to check what it's doing, even by making use of these classes, and it sets the verbs, paths and parameters as it should, but windows still opens it in the original program (unless I first go manually unassociate)
 
I've been stuck on this for 5 days... my project was supposed to have been live already... it's freaking my pip. Any ideas would be awesome.
 
Tks,
Pip
GeneralRe: Associations not Working for currently associated filesmemberLimitedAtonement3 Feb '10 - 10:03 
Dear Pip,
 
Wow, that sucks. How did you do? I have no idea what's going on, but am curious as to how you did.
 
In Christ,
Aaron Laws
 
http://ProCure.com

GeneralRe: Associations not Working for currently associated filesmemberTheToid12 May '10 - 13:51 
You most likely have the applications key left over, to reset a file association FULLY using the registry delete these keys (NOTE: the windows interface dosnt even reset some of these):
 
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.{EXT}
 
HKEY_LOCAL_MACHINE\Software\Classes\.{EXT}]
HKEY_LOCAL_MACHINE\Software\Classes\Applications\{YOURAPPNAME}
HKEY_LOCAL_MACHINE\Software\Classes\{EXT}_auto_file
 
HKEY_CURRENT_USER\Software\Classes\.{EXT}]
HKEY_CURRENT_USER\Software\Classes\Applications\{YOURAPPNAME}
HKEY_CURRENT_USER\Software\Classes\{EXT}_auto_file]
 
Replacing
 
{EXT} with your file extension
{YOURAPPNAME} with the FILENAME.EXT of your application
 
Doing this will not only ensure your newly created assocation will work, but it will also remove any crap that windows has added from the open with interface creating its associations ({EXT}_auto_file and the like).
QuestionI want to use your code in my app. Can I ?memberIQ719 Jun '09 - 3:27 
I am developing open - source free project under GNU public license. I want to use your code as is, without modifying, just add your project to my solution. Can I use your code ?
 
I see somewhere in a code, that it can't be used in a GNU projects.
QuestionHow to run this applicationmemberKapilDesai17 May '09 - 22:42 
I am not able to associate your files with my project kindly let me knw urgently.....
QuestionHow to use it for an applicationmemberMichael Egan9 Apr '09 - 22:46 
Nice works, but I don't know how to step by step use it in my application. All I want is that after install my application, user can open a file by double click into it, of course this file with my extension. Can you describe more details?
 
Michael Egan

Generaldoes not work under VISTAmemberviewon013 Apr '08 - 10:59 
Hi,
 
It does not work under VISTA, I don t know why !
 
Do you have an idea ?
GeneralFilenames with spacesmemberpucis8324 Feb '08 - 13:15 
A little tweak for proper file handling if filename is with spaces like "C:\Documents and settings\...", shoud be:
 
//Path and arguments to use
 
@"C:\SomePath\MyApp.exe ""%1"""
QuestionHow to get icon from ProgramAssociationInfo.DefaultIconmemberhoanhtuan8 Jan '08 - 21:34 
Brendan,
 
How to get the icon from path string of ProgramAssociationInfo.DefaultIcon ?
 
I'm writing a explorer type program, and will need to display icon for each file type.
 
You done a great job, Rose | [Rose] , thanks much.
 
Anh Tuan
AnswerRe: How to get icon from ProgramAssociationInfo.DefaultIconmemberAschratt31 Jan '08 - 7:51 
mmhh... You can get the path to the icon and load it into your ListView (Or any other control) using standart C# Commands!
 
FileAssociationInfo hFAInfo = new FileAssociationInfo(".test");
if (hFAInfo.Exists)
{
ProgramAssociationInfo hPAInfo = new ProgramAssociationInfo(hFAInfo.ProgID);
string sIconPath = hPAInfo.DefaultIcon.Path.ToString();
}

 
Greetings!
 
Bier

GeneralDefaultIcon Bug [modified]memberAschratt1 Dec '07 - 23:16 
Hey!
 
Nice Code... pretty easy to use! But I found an Bug... If I set an DefaultIcon for a ProgrammAssociation the libary creates an DefaultIcon string value to my icon. At least Windows (XP... dunno how it is in other Win Versions) uses a key with an string (Standart) including the Icon. Your GUI even doesn't show my icon!
 
To make this a little bit more understood I try to show this on an "example":
 
Your's libary creates something like this:
 
-[KEY]Prog.ID
--(Standard)
--DefaultIcon
--[KEY]shell
...
 
But Windows wants something like this:
 
-[KEY]Prog.ID
--(Standard)
--[KEY]DefaultIcon
---(Standard) //Path to the Icon
--[KEY]shell
...
 
I try to fix this, but it would be cool if you could try this too!
 
Greetings and thanks for the nice code! =)
 
//EDIT:
 
protected void SetDefaultIcon(ProgramIcon icon)
{
if (!this.Exists)
throw new Exception("Extension does not exist");
 
if (icon != ProgramIcon.None)
{
RegistryKey root = Registry.ClassesRoot;
RegistryKey key = root.OpenSubKey(this.progId, true);
RegistryKey tmpkey = key.OpenSubKey("DefaultIcon", true);
 
if (tmpkey != null)
{
key.DeleteSubKeyTree("shell");
}
 
tmpkey = key.CreateSubKey("DefaultIcon");
registryWrapper.Write(this.progId + "\\DefaultIcon", "", icon.ToString());
 
ShellNotification.NotifyOfChange();
}
}

 
Works for me Wink | ;)
 
Greetz!
 

-- modified at 5:43 Sunday 2nd December, 2007
 
Bier

GeneralRe: DefaultIcon Bugmemberzackflame15 Jun '10 - 4:48 
This code is incorrect. Correct version:
protected void SetDefaultIcon(ProgramIcon icon)
{
  if (!this.Exists)
      throw new Exception("Extension does not exist");
 
  if (icon != ProgramIcon.None)
  {
      RegistryKey root = Registry.ClassesRoot;
      RegistryKey key = root.OpenSubKey(this.progId, true);
      RegistryKey tmpkey = key.OpenSubKey("DefaultIcon", true);
 
      if (tmpkey == null)
      {
          tmpkey = key.CreateSubKey("DefaultIcon");
      }
      
      registryWrapper.Write(this.progId + "\\DefaultIcon", "", icon.ToString());
 
      ShellNotification.NotifyOfChange();
  }
}

GeneralAccess to registry key deniedmemberkamal2003us1 Jul '07 - 23:49 
I tried compiling your code but I'm facing an exception "Access to registry key HKEY_...ROOT\.ewf is denied"
 
I'm running Vista Busines.
 
"Do u think that my being stronger or faster has anything to do with my muscles in a place like this".

GeneralRe: Access to registry key deniedmemberBrendan Grant2 Jul '07 - 5:24 
Are you receiving that exception during compilation or execution?
 
Chances are you are running into that exception because your user account doesn't have permission to write to or create that registry key.
 
Currently my code only writes to HKEY_CLASSES_ROOT, perhaps in future it will support writing to HKEY_CURRENT_USER\Software\Classes as well so that an app can register user specific file associations.
 
Ordinarily when writing to an admin only portion of the registry, Vista's Registry Virtualization would kick in... however it doesn't apply in this case as we are writing to HKEY_CLASSES_ROOT and not HKEY_LOCAL_MACHINE\Software.
 
For now, try running the application as Administrator when setting/editing system wide associations (which is truly an admin operation).
GeneralRe: Access to registry key deniedmemberyf0129 Dec '07 - 20:39 
In vista, the file associations information is written in HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts instead of HKEY_CLASSES_ROOT.
It will read HKEY_CLASSES_ROOT unless there is no infomation existed in HKEY_CURRENT_USER.
And the key in HKEY_CURRENT_USER will be created when user opens file associations in the contro panel.
GeneralMay not need admin access under VistamemberThe_Mega_ZZTer16 Mar '07 - 14:42 
Vista (and it seems, also XP) support per-user file associations, at least as far as assigning extensions to existing file types. HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\ is where it's at... I don't see actual file types under there, just associations for specific extensions.
 
It's also possible that HKCR is one of the keys where any writes by limited users is mirrored into a per-user key, and read back when requested by that user.
 
At the very least, the stuff in the key I mentioned has the possibility of overriding what changes your code tries to make if it doesn't look there.
QuestionGreat stuff! Can I use it?memberRichard Brightwell8 Mar '07 - 8:27 
Hi!
 
These classes you wrote are exactly what we need. I was wondering if we can use it in our program?
 
Thanks so much!
 
Richard
AnswerRe: Great stuff! Can I use it?memberBrendan Grant12 Mar '07 - 6:18 
Absolutely!
 
When you get around to release I’d love to hear what you are using it for/in.
GeneralBrief version [modified]memberMatthiasBiel21 Feb '07 - 20:41 
Hi,
 
this code is not as flexible as the version provided by Brendan but covers the common case of registering an application for opening a file with a specific extension.
 
Matthias
 
/// <summary>
/// Registers a file type via it's extension. If the file type is already registered, nothing is changed.
/// </summary>
/// <param name="extension">The extension to register</param>
/// <param name="progId">A unique identifier for the program to work with the file type</param>
/// <param name="description">A brief description of the file type</param>
/// <param name="executeable">Where to find the executeable.</param>
/// <param name="iconFile">Location of the icon.</param>
/// <param name="iconIdx">Selects the icon within <paramref name="iconFile"/></param>
public static void Register(string extension, string progId, string description, string executeable, string iconFile, int iconIdx)
{
     try
     {                   
          if (extension.Length != 0)
          {
               if (extension[0] != '.')
               {
                    extension = "."+extension;
               }
 
               // register the extension, if necessary
               using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(extension))
               {
                    if (key == null)
                    {
                         using (RegistryKey extKey = Registry.ClassesRoot.CreateSubKey(extension))
                         {
                              extKey.SetValue(string.Empty, progId);
                         }
                    }
               }
 
               // register the progId, if necessary
               using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(progId))
               {
                    if (key == null)
                    {
                         using (RegistryKey progIdKey = Registry.ClassesRoot.CreateSubKey(progId))
                         {
                              progIdKey.SetValue(string.Empty, description);
                              using (RegistryKey defaultIcon = progIdKey.CreateSubKey("DefaultIcon"))
                              {
                                   defaultIcon.SetValue(string.Empty, String.Format("\"{0}\",{1}", iconFile, iconIdx));
                              }
 
                              using (RegistryKey command = progIdKey.CreateSubKey("shell\\open\\command"))
                              {
                                   command.SetValue(string.Empty, String.Format("\"{0}\" \"%1\"", executeable));
                              }
                         }
                    }
               }
          }
     }
     catch(Exception ex)
     {
          // TODO: implement proper exception handling.
     }
}
 

 

-- modified at 2:08 Wednesday 30th May, 2007
GeneralRe: Brief versionmemberTesto28ß519 Jun '08 - 10:45 
Nice, but don't work unter Vista.
GeneralRe: Brief versionmemberkasparovthe218 Feb '09 - 6:33 
Sure it works on vista !
You're german , aren't you ? Because you used the german "unter" instead of "under" Wink | ;)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 16 Mar 2007
Article Copyright 2007 by Brendan Grant
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid