关联文件扩展名和应用程序

我编写了一个编辑特定文件types的程序,我想让用户select将我的应用程序设置为此文件types的默认编辑器(因为我不需要安装程序)。

我试着编写一个可重用的方法,通过向HKEY_CLASSES_ROOT添加一个密钥,并将其与我的应用程序一起使用,为我(最好在任何操作系统上,尽pipe我正在运行Vista)关联一个文件,但它不似乎工作。

public static void SetAssociation(string Extension, string KeyName, string OpenWith, string FileDescription) { RegistryKey BaseKey; RegistryKey OpenMethod; RegistryKey Shell; RegistryKey CurrentUser; BaseKey = Registry.ClassesRoot.CreateSubKey(Extension); BaseKey.SetValue("", KeyName); OpenMethod = Registry.ClassesRoot.CreateSubKey(KeyName); OpenMethod.SetValue("", FileDescription); OpenMethod.CreateSubKey("DefaultIcon").SetValue("", "\"" + OpenWith + "\",0"); Shell = OpenMethod.CreateSubKey("Shell"); Shell.CreateSubKey("edit").CreateSubKey("command").SetValue("", "\"" + OpenWith + "\"" + " \"%1\""); Shell.CreateSubKey("open").CreateSubKey("command").SetValue("", "\"" + OpenWith + "\"" + " \"%1\""); BaseKey.Close(); OpenMethod.Close(); Shell.Close(); CurrentUser = Registry.CurrentUser.CreateSubKey(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\" + Extension); CurrentUser = CurrentUser.OpenSubKey("UserChoice", RegistryKeyPermissionCheck.ReadWriteSubTree, System.Security.AccessControl.RegistryRights.FullControl); CurrentUser.SetValue("Progid", KeyName, RegistryValueKind.String); CurrentUser.Close(); } 

任何想法,为什么它不工作? 一个示例使用可能是

 SetAssociation(".ucs", "UCS_Editor_File", Application.ExecutablePath, "UCS File"); 

使用“CurrentUser”的方法的一部分似乎工作,如果我使用registry编辑器相同,但使用我的应用程序它不。

答案比我想象的要简单得多。 Windows资源pipe理器有自己的应用程序打开覆盖,我试图修改它的最后一行代码。 如果你只是删除资源pipe理器覆盖,那么文件关联将起作用。

我也告诉资源pipe理器,我通过调用非托pipe函数SHChangeNotify()更改了文件关联

 public static void SetAssociation(string Extension, string KeyName, string OpenWith, string FileDescription) { // The stuff that was above here is basically the same // Delete the key instead of trying to change it CurrentUser = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\" + Extension, true); CurrentUser.DeleteSubKey("UserChoice", false); CurrentUser.Close(); // Tell explorer the file association has been changed SHChangeNotify(0x08000000, 0x0000, IntPtr.Zero, IntPtr.Zero); } [DllImport("shell32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern void SHChangeNotify(uint wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2); 

您可以通过ClickOnce以可pipe理的方式执行此操作。 不要在registry中烦恼。 这可以通过工具(即无xml)在VS2008和以上(包括快递)项目属性=>发布=>选项=>文件关联

如果您将密钥写入HKEY_CURRENT_USER\Software\Classes而不是HKEY_CLASSES_ROOT ,则在Vista及更高版本下,这应该无需pipe理员权限即可运行。

这是一个完整的例子:

 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 = ".ucs", ProgId = "UCS_Editor_File", FileTypeDescription = "UCS File", 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; } 

您正在使用Visual Studio的旧版本,Vista会将您的程序视为“传统”Windows应用程序。 并redirectregistry你写。 在你的程序中包含一个清单 ,所以你会看到Vista的意识。 这个清单自动包含在VS2008中。

注意,这仍然不能解决您的用户的问题,她不太可能运行与UACclosures的应用程序。 您需要编写一个单独的应用程序,该应用程序具有链接的清单,并要求提供pipe理员权限。 它需要清单与requestedExecutionLevel设置为requireAdministrator。

如果您使用Visual Studio 2015,则安装设置和部署扩展。 创build安装向导,然后将其附加到您的.exe文件。 右键单击解决scheme资源pipe理器中的主程序,进入-view,-file types,然后右键单击文件types并select添加新文件types。 将所有属性更改为您的需要,然后构buildMSI安装程序。

:我重新读你的问题,并意识到你不想要一个安装程序。 对不起,虽然你应该考虑使用一个,因为它给你更多的定制你的程序(S)。

上面的解决scheme不适合我的Windows 10.这里是我的解决scheme打开.myExt文件与当前用户%localappdata%\ MyApp \ MyApp.exe。 读完评论后优化。

  String App_Exe = "MyApp.exe"; String App_Path = "%localappdata%; SetAssociation_User("myExt", App_Path + App_Exe, App_Exe); public static void SetAssociation_User(string Extension, string OpenWith, string ExecutableName) { try { using (RegistryKey User_Classes = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Classes\\", true)) using (RegistryKey User_Ext = User_Classes.CreateSubKey("." + Extension)) using (RegistryKey User_AutoFile = User_Classes.CreateSubKey(Extension + "_auto_file")) using (RegistryKey User_AutoFile_Command = User_AutoFile.CreateSubKey("shell").CreateSubKey("open").CreateSubKey("command")) using (RegistryKey ApplicationAssociationToasts = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\ApplicationAssociationToasts\\", true)) using (RegistryKey User_Classes_Applications = User_Classes.CreateSubKey("Applications")) using (RegistryKey User_Classes_Applications_Exe = User_Classes_Applications.CreateSubKey(ExecutableName)) using (RegistryKey User_Application_Command = User_Classes_Applications_Exe.CreateSubKey("shell").CreateSubKey("open").CreateSubKey("command")) using (RegistryKey User_Explorer = Registry.CurrentUser.CreateSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\." + Extension)) using (RegistryKey User_Choice = User_Explorer.OpenSubKey("UserChoice")) { User_Ext.SetValue("", Extension + "_auto_file", RegistryValueKind.String); User_Classes.SetValue("", Extension + "_auto_file", RegistryValueKind.String); User_Classes.CreateSubKey(Extension + "_auto_file"); User_AutoFile_Command.SetValue("", "\"" + OpenWith + "\"" + " \"%1\""); ApplicationAssociationToasts.SetValue(Extension + "_auto_file_." + Extension, 0); ApplicationAssociationToasts.SetValue(@"Applications\" + ExecutableName + "_." + Extension, 0); User_Application_Command.SetValue("", "\"" + OpenWith + "\"" + " \"%1\""); User_Explorer.CreateSubKey("OpenWithList").SetValue("a", ExecutableName); User_Explorer.CreateSubKey("OpenWithProgids").SetValue(Extension + "_auto_file", "0"); if (User_Choice != null) User_Explorer.DeleteSubKey("UserChoice"); User_Explorer.CreateSubKey("UserChoice").SetValue("ProgId", @"Applications\" + ExecutableName); } SHChangeNotify(0x08000000, 0x0000, IntPtr.Zero, IntPtr.Zero); } catch (Exception excpt) { //Your code here } } [DllImport("shell32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern void SHChangeNotify(uint wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);