I'd like to to associate a file extension to the current executable in C#. This way when the user clicks on the file afterwards in explorer, it'll run my executable with the given file as the first argument. Ideally it'd also set the icon for the given file extensions to the icon for my executable. Thanks all.
-
This has been thoroughly answered in the following thread: http://stackoverflow.com/questions/2993118/how-to-perform-shell-icon-embedding-in-visual-studio-2010/10415947#10415947 – Blake Niemyjski May 02 '12 at 14:40
-
This has been thoroughly answered in the following [stack overflow thread](http://stackoverflow.com/questions/2993118/how-to-perform-shell-icon-embedding-in-visual-studio-2010/10415947#10415947). We've been using this implementation and it works great. It is also open source and integrates into MSBuild. – Blake Niemyjski May 02 '12 at 14:40
-
3@BlakeNiemyjski How are your links about embedding icons into .NET assemblies relevant to this question about file extension association? – Dean Kuga Aug 22 '12 at 18:28
-
I was linking to the stack overflow post that contains useful wix information on associating a file extension via Wix Installer. – Blake Niemyjski Aug 27 '12 at 18:09
-
http://www.codeproject.com/KB/dotnet/System_File_Association.aspx Then perhaps http://www.csharpfriends.com/Forums/ShowPost.aspx?PostID=32627 Might be of some help. If need be you could always do the registry editing yourself via API directly for the association... but up to you EDIT: Also read the comments there, some good points eg the use of quotes for paths with spaces: @"C:\SomePath\MyApp.exe ""%1""" Also permission issues for registry access esp with Vista... good luck :) – White Dragon Sep 16 '08 at 06:24
-
Big problem with the codeproject example is that it writes to HKEY_CLASSES_ROOT instead of giving you the choice between that and HKEY_CURRENT_USER, would have used it otherwise. – Kelly Elton Oct 29 '13 at 04:11
9 Answers
There doesn't appear to be a .Net API for directly managing file associations but you can use the Registry classes for reading and writing the keys you need to.
You'll need to create a key under HKEY_CLASSES_ROOT with the name set to your file extension (eg: ".txt"). Set the default value of this key to a unique name for your file type, such as "Acme.TextFile". Then create another key under HKEY_CLASSES_ROOT with the name set to "Acme.TextFile". Add a subkey called "DefaultIcon" and set the default value of the key to the file containing the icon you wish to use for this file type. Add another sibling called "shell". Under the "shell" key, add a key for each action you wish to have available via the Explorer context menu, setting the default value for each key to the path to your executable followed by a space and "%1" to represent the path to the file selected.
For instance, here's a sample registry file to create an association between .txt files and EmEditor:
Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\.txt] @="emeditor.txt" [HKEY_CLASSES_ROOT\emeditor.txt] @="Text Document" [HKEY_CLASSES_ROOT\emeditor.txt\DefaultIcon] @="%SystemRoot%\\SysWow64\\imageres.dll,-102" [HKEY_CLASSES_ROOT\emeditor.txt\shell] [HKEY_CLASSES_ROOT\emeditor.txt\shell\open] [HKEY_CLASSES_ROOT\emeditor.txt\shell\open\command] @="\"C:\\Program Files\\EmEditor\\EMEDITOR.EXE\" \"%1\"" [HKEY_CLASSES_ROOT\emeditor.txt\shell\print] [HKEY_CLASSES_ROOT\emeditor.txt\shell\print\command] @="\"C:\\Program Files\\EmEditor\\EMEDITOR.EXE\" /p \"%1\""

- 1,869
- 15
- 24
-
Is there any way of passing some arguments to the exe (in this case to C:\Program Files\EmEditor\EMEDITOR.EXE)? – Apparao Jan 20 '16 at 13:57
-
@Apparao yes, look at the Print command as an example. It passes a /p parameter before the file name. – X-Cubed Jan 18 '17 at 06:05
-
1I am aware this answer is more than a decade old, but still -- I don't think this is a good way to associate a public file format that is plaintext (`*.txt`) with a random program -- this basically "takes over" file association, if there was already at least a previous association of text files to some program(s), overriding it. Microsoft documentation, unfulfilling as it is, states at least that the way to associate a program with a public file type (using "Open With" context menu) is to use the `OpenWithProgIds` registry key under the file type key. – Armen Michaeli Mar 20 '20 at 12:43
Also, if you decide to go the registry way, keep in mind that current user associations are under HKEY_CURRENT_USER\Software\Classes. It might be better to add your application there instead of local machine classes.
If your program will be run by limited users, you won't be able to modify CLASSES_ROOT anyway.

- 14,138
- 9
- 71
- 83
If you use ClickOnce deployment, this is all handled for you (at least, in VS2008 SP1); simply:
- Project Properties
- Publish
- Options
- File Associatons
- (add whatever you need)
(note that it must be full-trust, target .NET 3.5, and be set for offline usage)
See also MSDN: How to: Create File Associations For a ClickOnce Application

- 1,026,079
- 266
- 2,566
- 2,900
-
1I have VS2008 Professional, SP1 and I do not see this option. I must be missing something. – Jerry Jan 27 '10 at 18:25
Here's a complete example:
public class FileAssociation
{
public string Extension { get; set; }
public string ProgId { get; set; }
public string FileTypeDescription { get; set; }
public string ExecutableFilePath { get; set; }
}
public class FileAssociations
{
// needed so that Explorer windows get refreshed after the registry is updated
[System.Runtime.InteropServices.DllImport("Shell32.dll")]
private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
private const int SHCNE_ASSOCCHANGED = 0x8000000;
private const int SHCNF_FLUSH = 0x1000;
public static void EnsureAssociationsSet()
{
var filePath = Process.GetCurrentProcess().MainModule.FileName;
EnsureAssociationsSet(
new FileAssociation
{
Extension = ".binlog",
ProgId = "MSBuildBinaryLog",
FileTypeDescription = "MSBuild Binary Log",
ExecutableFilePath = filePath
},
new FileAssociation
{
Extension = ".buildlog",
ProgId = "MSBuildStructuredLog",
FileTypeDescription = "MSBuild Structured Log",
ExecutableFilePath = filePath
});
}
public static void EnsureAssociationsSet(params FileAssociation[] associations)
{
bool madeChanges = false;
foreach (var association in associations)
{
madeChanges |= SetAssociation(
association.Extension,
association.ProgId,
association.FileTypeDescription,
association.ExecutableFilePath);
}
if (madeChanges)
{
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSH, IntPtr.Zero, IntPtr.Zero);
}
}
public static bool SetAssociation(string extension, string progId, string fileTypeDescription, string applicationFilePath)
{
bool madeChanges = false;
madeChanges |= SetKeyDefaultValue(@"Software\Classes\" + extension, progId);
madeChanges |= SetKeyDefaultValue(@"Software\Classes\" + progId, fileTypeDescription);
madeChanges |= SetKeyDefaultValue($@"Software\Classes\{progId}\shell\open\command", "\"" + applicationFilePath + "\" \"%1\"");
return madeChanges;
}
private static bool SetKeyDefaultValue(string keyPath, string value)
{
using (var key = Registry.CurrentUser.CreateSubKey(keyPath))
{
if (key.GetValue(null) as string != value)
{
key.SetValue(null, value);
return true;
}
}
return false;
}

- 8,786
- 2
- 33
- 37
There may be specific reasons why you choose not to use an install package for your project but an install package is a great place to easily perform application configuration tasks such registering file extensions, adding desktop shortcuts, etc.
Here's how to create file extension association using the built-in Visual Studio Install tools:
Within your existing C# solution, add a new project and select project type as
Other Project Types
->Setup and Deployment
->Setup Project
(or try the Setup Wizard)Configure your installer (plenty of existing docs for this if you need help)
Right-click the setup project in the Solution explorer, select
View
->File Types
, and then add the extension that you want to register along with the program to run it.
This method has the added benefit of cleaning up after itself if a user runs the uninstall for your application.
To be specific about the "Windows Registry" way:
I create keys under HKEY_CURRENT_USER\Software\Classes (like Ishmaeel said)
and follow the instruction answered by X-Cubed.
The sample code looks like:
private void Create_abc_FileAssociation()
{
/***********************************/
/**** Key1: Create ".abc" entry ****/
/***********************************/
Microsoft.Win32.RegistryKey key1 = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software", true);
key1.CreateSubKey("Classes");
key1 = key1.OpenSubKey("Classes", true);
key1.CreateSubKey(".abc");
key1 = key1.OpenSubKey(".abc", true);
key1.SetValue("", "DemoKeyValue"); // Set default key value
key1.Close();
/*******************************************************/
/**** Key2: Create "DemoKeyValue\DefaultIcon" entry ****/
/*******************************************************/
Microsoft.Win32.RegistryKey key2 = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software", true);
key2.CreateSubKey("Classes");
key2 = key2.OpenSubKey("Classes", true);
key2.CreateSubKey("DemoKeyValue");
key2 = key2.OpenSubKey("DemoKeyValue", true);
key2.CreateSubKey("DefaultIcon");
key2 = key2.OpenSubKey("DefaultIcon", true);
key2.SetValue("", "\"" + "(The icon path you desire)" + "\""); // Set default key value
key2.Close();
/**************************************************************/
/**** Key3: Create "DemoKeyValue\shell\open\command" entry ****/
/**************************************************************/
Microsoft.Win32.RegistryKey key3 = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software", true);
key3.CreateSubKey("Classes");
key3 = key3.OpenSubKey("Classes", true);
key3.CreateSubKey("DemoKeyValue");
key3 = key3.OpenSubKey("DemoKeyValue", true);
key3.CreateSubKey("shell");
key3 = key3.OpenSubKey("shell", true);
key3.CreateSubKey("open");
key3 = key3.OpenSubKey("open", true);
key3.CreateSubKey("command");
key3 = key3.OpenSubKey("command", true);
key3.SetValue("", "\"" + "(The application path you desire)" + "\"" + " \"%1\""); // Set default key value
key3.Close();
}
Just show you guys a quick demo, very easy to understand. You could modify those key values and everything is good to go.
-
1Don't forget to add the necessary code to notify the shell to use the icon. `SHChangeNotify(0x8000000, 0, 0, 0);` – randomsolutions Aug 19 '15 at 19:11
The code below is a function the should work, it adds the required values in the windows registry. Usually i run SelfCreateAssociation(".abc") in my executable. (form constructor or onload or onshown) It will update the registy entry for the current user, everytime the executable is executed. (good for debugging, if you have some changes). If you need detailed information about the registry keys involved check out this MSDN link.
https://msdn.microsoft.com/en-us/library/windows/desktop/dd758090(v=vs.85).aspx
To get more information about the general ClassesRoot registry key. See this MSDN article.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx
public enum KeyHiveSmall
{
ClassesRoot,
CurrentUser,
LocalMachine,
}
/// <summary>
/// Create an associaten for a file extension in the windows registry
/// CreateAssociation(@"vendor.application",".tmf","Tool file",@"C:\Windows\SYSWOW64\notepad.exe",@"%SystemRoot%\SYSWOW64\notepad.exe,0");
/// </summary>
/// <param name="ProgID">e.g. vendor.application</param>
/// <param name="extension">e.g. .tmf</param>
/// <param name="description">e.g. Tool file</param>
/// <param name="application">e.g. @"C:\Windows\SYSWOW64\notepad.exe"</param>
/// <param name="icon">@"%SystemRoot%\SYSWOW64\notepad.exe,0"</param>
/// <param name="hive">e.g. The user-specific settings have priority over the computer settings. KeyHive.LocalMachine need admin rights</param>
public static void CreateAssociation(string ProgID, string extension, string description, string application, string icon, KeyHiveSmall hive = KeyHiveSmall.CurrentUser)
{
RegistryKey selectedKey = null;
switch (hive)
{
case KeyHiveSmall.ClassesRoot:
Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(extension).SetValue("", ProgID);
selectedKey = Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(ProgID);
break;
case KeyHiveSmall.CurrentUser:
Microsoft.Win32.Registry.CurrentUser.CreateSubKey(@"Software\Classes\" + extension).SetValue("", ProgID);
selectedKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(@"Software\Classes\" + ProgID);
break;
case KeyHiveSmall.LocalMachine:
Microsoft.Win32.Registry.LocalMachine.CreateSubKey(@"Software\Classes\" + extension).SetValue("", ProgID);
selectedKey = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(@"Software\Classes\" + ProgID);
break;
}
if (selectedKey != null)
{
if (description != null)
{
selectedKey.SetValue("", description);
}
if (icon != null)
{
selectedKey.CreateSubKey("DefaultIcon").SetValue("", icon, RegistryValueKind.ExpandString);
selectedKey.CreateSubKey(@"Shell\Open").SetValue("icon", icon, RegistryValueKind.ExpandString);
}
if (application != null)
{
selectedKey.CreateSubKey(@"Shell\Open\command").SetValue("", "\"" + application + "\"" + " \"%1\"", RegistryValueKind.ExpandString);
}
}
selectedKey.Flush();
selectedKey.Close();
}
/// <summary>
/// Creates a association for current running executable
/// </summary>
/// <param name="extension">e.g. .tmf</param>
/// <param name="hive">e.g. KeyHive.LocalMachine need admin rights</param>
/// <param name="description">e.g. Tool file. Displayed in explorer</param>
public static void SelfCreateAssociation(string extension, KeyHiveSmall hive = KeyHiveSmall.CurrentUser, string description = "")
{
string ProgID = System.Reflection.Assembly.GetExecutingAssembly().EntryPoint.DeclaringType.FullName;
string FileLocation = System.Reflection.Assembly.GetExecutingAssembly().Location;
CreateAssociation(ProgID, extension, description, FileLocation, FileLocation + ",0", hive);
}
-
Leaving a large block of code with no explanation is hardly helpful to future readers. Please try and add some explanation about what this code does. – Nisarg Shah Oct 24 '17 at 05:25
-
Code is working. Explanation in source code is fine and is working perfect for me. – Nasenbaer Jan 10 '19 at 13:10
The file associations are defined in the registry under HKEY_CLASSES_ROOT.
There's a VB.NET example here that I'm you can port easily to C#.

- 12,978
- 2
- 40
- 49
There are two cmd tools that have been around since Windows 7 which make it very easy to create simple file associations. They are assoc and ftype. Here's a basic explanation of each command.
- Assoc - associates a file extension (like '.txt') with a "file type."
- FType - defines an executable to run when the user opens a given "file type."
Note that these are cmd tools and not executable files (exe). This means that they can only be run in a cmd window, or by using ShellExecute with "cmd /c assoc." You can learn more about them at the links or by typing "assoc /?" and "ftype /?" at a cmd prompt.
So to associate an application with a .bob extension, you could open a cmd window (WindowKey+R, type cmd, press enter) and run the following:
assoc .bob=BobFile
ftype BobFile=c:\temp\BobView.exe "%1"
This is much simpler than messing with the registry and it is more likely to work in future windows version.
Wrapping it up, here is a C# function to create a file association:
public static int setFileAssociation(string[] extensions, string fileType, string openCommandString) {
int v = execute("cmd", "/c ftype " + fileType + "=" + openCommandString);
foreach (string ext in extensions) {
v = execute("cmd", "/c assoc " + ext + "=" + fileType);
if (v != 0) return v;
}
return v;
}
public static int execute(string exeFilename, string arguments) {
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = true;
startInfo.FileName = exeFilename;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = arguments;
try {
using (Process exeProcess = Process.Start(startInfo)) {
exeProcess.WaitForExit();
return exeProcess.ExitCode;
}
} catch {
return 1;
}
}

- 5,482
- 2
- 21
- 25