特定のファイルタイプを編集するプログラムを作成し、起動時にアプリケーションをこのファイルタイプのデフォルトのエディターとして設定するオプションをユーザーに提供したい(インストーラーが必要ないため)。
HKEY_CLASSES_ROOTにキーを追加することで、ファイルを関連付けて(Vistaを実行しているOSであることが望ましい)再利用可能なメソッドを記述しようとしましたが、アプリケーションで使用していますが、動作するようです。
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」を使用するメソッドの一部は、regeditを使用して同じことを行うと機能するようですが、アプリケーションを使用すると機能しません。
答えは思ったよりもずっと簡単でした。 Windowsエクスプローラーには、アプリケーションで開くための独自のオーバーライドがあり、コードの最後の行でそれを変更しようとしました。 Explorerのオーバーライドを削除するだけで、ファイルの関連付けが機能します。
また、アンマネージ関数SHChangeNotify()
を呼び出してファイルの関連付けを変更したことをExplorerに伝えました。
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);
完全な例を次に示します。
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;
}
それはmanagedの方法で行うことができます ClickOnce経由 。自分でレジストリをいじる必要はありません。これは、プロジェクトプロパティ=>発行=>オプション=>ファイルの関連付けで、VS2008以降のツール(つまり、xmlなし)(Expressを含む)から利用できます。
上記のソリューションは、Windows 10では機能しませんでした。現在のユーザーに対して、%localappdata%\ MyApp\MyApp.exeの拡張子が.myExtのファイルを開くためのソリューションを次に示します。コメントを読んだ後に最適化されます。
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);
キーをHKEY_CURRENT_USER\Software\Classes
ではなくHKEY_CLASSES_ROOT
に書き込む場合、Vista以降では管理者権限がなくても機能します。
古いバージョンのVisual Studioを使用している場合、Vistaはプログラムを「レガシー」Windowsアプリとして扱います。そして、あなたが行うレジストリ書き込みをリダイレクトします。プログラムに マニフェスト を含めると、Vistaに見えるようになります。このマニフェストは、VS2008以降によって自動的に含まれます。
これでもユーザーの問題が解決しないことに注意してください。UACをオフにしてアプリを実行することはほとんどありません。リンクされたマニフェストを持ち、管理者権限を要求する別のアプリを作成する必要があります。 requestedExecutionLevelがrequireAdministratorに設定されたマニフェストが必要です。
Visual Studio 2015を使用している場合は、セットアップと展開の拡張機能をインストールします。セットアップウィザードを作成し、そこに.exeファイルを添付します。ソリューションエクスプローラーでメインプログラムを右クリックして、-view、-file typesに移動し、ファイルタイプを右クリックして、[新しいファイルタイプの追加]を選択します。すべてのプロパティを必要に応じて変更し、MSIインストーラーをビルドします。
[〜#〜] note [〜#〜]:私はあなたの質問を読み直し、インストーラが欲しくないことに気付きました。それについては申し訳ありませんが、プログラムをよりカスタマイズできるため、使用を検討する必要があります。