Skip to content

Instantly share code, notes, and snippets.

@otuncelli
Created August 24, 2017 00:06
Show Gist options
  • Save otuncelli/18209f687879616b2a045f06b92df04e to your computer and use it in GitHub Desktop.
Save otuncelli/18209f687879616b2a045f06b92df04e to your computer and use it in GitHub Desktop.
Windows File Extension Association Helper Class
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace DiskCatalog.Classes
{
public sealed class FileAssociation
{
public string Extension { get; }
public string ProgId { get; }
public string Description { get; }
private readonly string _execPath = Assembly.GetExecutingAssembly().Location;
private readonly Scope _scope;
public FileAssociation(string extension, string progId, string description, Scope scope)
{
Extension = extension;
ProgId = progId;
Description = description;
_scope = scope;
}
public void EnsureSet(bool editContext, bool resetExplorerOverride)
{
var changeNotify = false;
RegistryKey classesKey = _scope == Scope.Root
? Registry.ClassesRoot
: Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Classes", true);
if (classesKey == null)
throw new NullReferenceException();
try
{
using (RegistryKey extensionKey = classesKey.CreateSubKey(Extension))
{
if (extensionKey == null)
throw new NullReferenceException();
extensionKey.SetValue(null, ProgId);
}
using (RegistryKey progIdKey = classesKey.CreateSubKey(ProgId,
RegistryKeyPermissionCheck.ReadWriteSubTree))
{
if (progIdKey == null)
throw new NullReferenceException();
progIdKey.SetValue(null, Description);
using (RegistryKey keyIcon = progIdKey.CreateSubKey("DefaultIcon"))
{
if (keyIcon == null)
throw new NullReferenceException();
keyIcon.SetValue(null, $"\"{_execPath}\",0");
}
using (RegistryKey shellKey = progIdKey.CreateSubKey("Shell"))
{
if (shellKey == null)
throw new NullReferenceException();
if (SetShellCommand(shellKey, "open"))
changeNotify = true;
if (editContext)
{
if (SetShellCommand(shellKey, "edit"))
changeNotify = true;
}
else
{
try
{
shellKey.DeleteSubKeyTree("edit", true);
changeNotify = true;
}
catch (ArgumentException)
{
}
}
}
}
}
finally
{
classesKey.Dispose();
}
if (resetExplorerOverride && ResetExplorerOverride())
changeNotify = true;
if (changeNotify)
NativeMethods.SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSH, IntPtr.Zero, IntPtr.Zero);
}
public void UnSet(bool resetExplorerOverride)
{
var changeNotify = false;
RegistryKey classesKey = _scope == Scope.Root
? Registry.ClassesRoot
: Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Classes", true);
if (classesKey == null)
throw new NullReferenceException();
try
{
try
{
classesKey.DeleteSubKey(Extension, true);
changeNotify = true;
}
catch (ArgumentException)
{
}
try
{
classesKey.DeleteSubKeyTree(ProgId, true);
changeNotify = true;
}
catch (ArgumentException)
{
}
}
finally
{
classesKey.Dispose();
}
if (resetExplorerOverride && ResetExplorerOverride())
changeNotify = true;
if (changeNotify)
NativeMethods.SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSH, IntPtr.Zero, IntPtr.Zero);
}
private bool SetShellCommand(RegistryKey shellKey, string cmdKeyName)
{
var changeNotify = false;
using (RegistryKey cmdKey = shellKey.CreateSubKey(cmdKeyName))
{
if (cmdKey == null)
throw new NullReferenceException();
using (RegistryKey commandKey = cmdKey.OpenSubKey("command"))
if (commandKey == null)
changeNotify = true;
using (RegistryKey commandKey = cmdKey.CreateSubKey("command"))
{
if (commandKey == null)
throw new NullReferenceException();
commandKey.SetValue(null, $"\"{_execPath}\" \"%1\"");
}
}
return changeNotify;
}
private bool ResetExplorerOverride()
{
string keyPath = $@"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\{Extension}";
using (RegistryKey currentUser = Registry.CurrentUser)
using (RegistryKey explorerOverride = currentUser.OpenSubKey(keyPath, true))
{
if (explorerOverride != null)
{
try
{
explorerOverride.DeleteSubKey("UserChoice", true);
return true;
}
catch (ArgumentException)
{
}
}
}
return false;
}
public enum Scope
{
CurrentUser,
Root
}
private const int SHCNE_ASSOCCHANGED = 0x8000000;
private const int SHCNF_FLUSH = 0x1000;
private static class NativeMethods
{
[DllImport("shell32", CharSet = CharSet.Auto, SetLastError = true)]
public static extern void SHChangeNotify(uint wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment