如何将文件扩展名关联到 C# 中的当前可执行文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/69761/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to associate a file extension to the current executable in C#
提问by
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.
我想将文件扩展名与 C# 中的当前可执行文件相关联。这样,当用户之后在资源管理器中单击文件时,它将以给定的文件作为第一个参数运行我的可执行文件。理想情况下,它还会将给定文件扩展名的图标设置为我的可执行文件的图标。谢谢大家。
回答by Steve Morgan
回答by X-Cubed
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.
似乎没有用于直接管理文件关联的 .Net API,但您可以使用 Registry 类来读取和写入您需要的键。
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.
您需要在 HKEY_CLASSES_ROOT 下创建一个密钥,并将名称设置为您的文件扩展名(例如:“.txt”)。将此键的默认值设置为文件类型的唯一名称,例如“Acme.TextFile”。然后在 HKEY_CLASSES_ROOT 下创建另一个键,名称设置为“Acme.TextFile”。添加一个名为“DefaultIcon”的子键,并将键的默认值设置为包含您希望用于此文件类型的图标的文件。添加另一个名为“shell”的兄弟。在“shell”键下,为您希望通过资源管理器上下文菜单提供的每个操作添加一个键,将每个键的默认值设置为可执行文件的路径,后跟一个空格和“%1”来表示路径到所选文件。
For instance, here's a sample registry file to create an association between .txt files and EmEditor:
例如,这里有一个示例注册表文件,用于在 .txt 文件和 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\""
回答by Ishmaeel
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.
此外,如果您决定采用注册表方式,请记住当前用户关联位于HKEY_CURRENT_USER\Software\Classes 下。最好在那里添加您的应用程序而不是本地机器类。
If your program will be run by limited users, you won't be able to modify CLASSES_ROOT anyway.
如果您的程序将由有限的用户运行,则无论如何您都无法修改 CLASSES_ROOT。
回答by Paul J
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:
以下是使用内置 Visual Studio 安装工具创建文件扩展名关联的方法:
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.
在现有的 C# 解决方案中,添加一个新项目并选择项目类型为
Other Project Types
->Setup and Deployment
->Setup Project
(或尝试安装向导)配置您的安装程序(如果您需要帮助,可以使用大量现有文档)
在解决方案资源管理器中右键单击安装项目,选择
View
->File Types
,然后添加要与程序一起注册的扩展以运行它。
This method has the added benefit of cleaning up after itself if a user runs the uninstall for your application.
如果用户为您的应用程序运行卸载程序,则此方法还有一个额外的好处,即自行清理。
回答by Marc Gravell
If you use ClickOnce deployment, this is all handled for you (at least, in VS2008 SP1); simply:
如果您使用 ClickOnce 部署,这一切都会为您处理(至少,在 VS2008 SP1 中);简单地:
- 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)
(注意必须是完全信任的,目标是.NET 3.5,并设置为离线使用)
See also MSDN: How to: Create File Associations For a ClickOnce Application
另请参见 MSDN:如何:为 ClickOnce 应用程序创建文件关联
回答by Strong
To be specific about the "Windows Registry" way:
具体到“Windows注册表”方式:
I create keys under HKEY_CURRENT_USER\Software\Classes(like Ishmaeel said)
我在HKEY_CURRENT_USER\Software\Classes下创建密钥(如 Ishmaeel 所说)
and follow the instruction answered by X-Cubed.
并按照 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.
给你们看一个快速演示,很容易理解。您可以修改这些键值,一切顺利。
回答by Kirill Osenkov
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;
}
回答by Mike
There are two cmd tools that have been around since Windows 7 which make it very easy to create simple file associations. They are assocand ftype. Here's a basic explanation of each command.
自 Windows 7 以来,有两个 cmd 工具一直存在,这使得创建简单的文件关联变得非常容易。它们是assoc和ftype。这是每个命令的基本解释。
- 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.
请注意,这些是 cmd 工具,而不是可执行文件 (exe)。这意味着它们只能在 cmd 窗口中运行,或者通过使用带有“cmd /c assoc”的 ShellExecute。您可以通过链接或输入“assoc /?”了解更多关于它们的信息。和“ftype /?” 在 cmd 提示符下。
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:
因此,要将应用程序与 .bob 扩展名关联,您可以打开一个 cmd 窗口(WindowKey+R,键入 cmd,按 Enter)并运行以下命令:
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.
这比弄乱注册表要简单得多,并且更有可能在未来的 Windows 版本中工作。
Wrapping it up, here is a C# function to create a file association:
总结一下,这里是一个创建文件关联的 C# 函数:
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;
}
}
回答by Carsten R.
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.
下面的代码是一个应该工作的函数,它在 Windows 注册表中添加了所需的值。通常我在我的可执行文件中运行 SelfCreateAssociation(".abc") 。(表单构造函数或 onload 或 onshown)每次执行可执行文件时,它将更新当前用户的注册表项。(适合调试,如果您有一些更改)。如果您需要有关所涉及的注册表项的详细信息,请查看此 MSDN 链接。
https://msdn.microsoft.com/en-us/library/windows/desktop/dd758090(v=vs.85).aspx
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.
获取有关常规 ClassesRoot 注册表项的更多信息。请参阅此 MSDN 文章。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx
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);
}