C# 查找用于在 Windows 上打开特定文件类型的默认应用程序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/162331/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 16:16:56  来源:igfitidea点击:

Finding the default application for opening a particular file type on Windows

c#.netwindowsfile-type

提问by Bart Read

I'm developing an application targeting .NET Framework 2.0 using C# for which I need to be able to find the default application that is used for opening a particular file type.

我正在使用 C# 开发面向 .NET Framework 2.0 的应用程序,为此我需要能够找到用于打开特定文件类型的默认应用程序。

I know that, for example, if you just want to open a file using that application you can use something like:

我知道,例如,如果您只想使用该应用程序打开一个文件,您可以使用以下内容:

System.Diagnostics.Process.Start( "C:\...\...\myfile.html" );

to open an HTML document in the default browser, or

在默认浏览器中打开 HTML 文档,或

System.Diagnostics.Process.Start( "C:\...\...\myfile.txt" );

to open a text file in the default text editor.

在默认文本编辑器中打开文本文件。

However, what I want to be able to do is to open files that don't necessarily have a .txtextension (for example), in the default text editor, so I need to be able to find out the default application for opening .txtfiles, which will allow me to invoke it directly.

但是,我希望能够做的是在默认文本编辑器中打开不一定具有.txt扩展名的文件(例如),因此我需要能够找到打开.txt的默认应用程序。 txt文件,这将允许我直接调用它。

I'm guessing there's some Win32 API that I'll need to P/Invoke in order to do this, however a quick look with both Google and MSDN didn't reveal anything of much interest; I did find a very large number of completely irrelevant pages, but nothing like I'm looking for.

我猜有一些 Win32 API 需要 P/Invoke 来执行此操作,但是快速浏览 Google 和 MSDN 并没有发现任何有趣的东西;我确实找到了大量完全不相关的页面,但没有像我正在寻找的那样。

采纳答案by curtisk

You can check under registry section HKEY_CLASSES_ROOTfor the extension and action details. Documentation for this is on MSDN. Alternatively, you can use the IQueryAssociationsinterface.

您可以在注册表部分HKEY_CLASSES_ROOT查看扩展和操作详细信息。这方面的文档位于 MSDN 上。或者,您可以使用IQueryAssociations接口。

回答by xsl

Here is a blog post with about this topic.The code samples are in VB.net, but it should be easy to port them to C#.

这是一篇关于这个主题的博客文章。代码示例在 VB.net 中,但将它们移植到 C# 应该很容易。

回答by Tom

You can just query the registry. First get the Default entry under HKEY_CLASSES_ROOT\.ext

您可以查询注册表。首先获取 HKEY_CLASSES_ROOT\.ext 下的 Default 条目

That will give you the classname. For example .txt has a default of txtfile

那会给你类名。例如 .txt 的默认值为 txtfile

Then open up HKEY_CLASSES_ROOT\txtfile\Shell\Open\Command

然后打开HKEY_CLASSES_ROOT\txtfile\Shell\Open\Command

That will give you the default command used.

这将为您提供使用的默认命令。

回答by Bart Read

Doh! Of course.

哦!当然。

HKEY_CLASSES_ROOT\.txt

includes a reference to

包括对

HKEY_CLASSES_ROOT\txtfile

which contains a subkey

其中包含一个子键

HKEY_CLASSES_ROOT\txtfile\shell\open\command

which references Notepad.

其中引用记事本。

Sorted, many thanks!

已整理,非常感谢!

Bart

巴特

回答by Ohad Schneider

All current answers are unreliable. The registry is an implementation detail and indeed such code is broken on my Windows 8.1 machine. The proper way to do this is using the Win32 API, specifically AssocQueryString:

目前所有的答案都不可靠。注册表是一个实现细节,确实这样的代码在我的 Windows 8.1 机器上被破坏了。正确的方法是使用 Win32 API,特别是AssocQueryString

using System.Runtime.InteropServices;

[DllImport("Shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern uint AssocQueryString(
    AssocF flags, 
    AssocStr str,  
    string pszAssoc, 
    string pszExtra, 
    [Out] StringBuilder pszOut, 
    ref uint pcchOut
); 

[Flags]
public enum AssocF
{
    None = 0,
    Init_NoRemapCLSID = 0x1,
    Init_ByExeName = 0x2,
    Open_ByExeName = 0x2,
    Init_DefaultToStar = 0x4,
    Init_DefaultToFolder = 0x8,
    NoUserSettings = 0x10,
    NoTruncate = 0x20,
    Verify = 0x40,
    RemapRunDll = 0x80,
    NoFixUps = 0x100,
    IgnoreBaseClass = 0x200,
    Init_IgnoreUnknown = 0x400,
    Init_Fixed_ProgId = 0x800,
    Is_Protocol = 0x1000,
    Init_For_File = 0x2000
}

public enum AssocStr
{
    Command = 1,
    Executable,
    FriendlyDocName,
    FriendlyAppName,
    NoOpen,
    ShellNewValue,
    DDECommand,
    DDEIfExec,
    DDEApplication,
    DDETopic,
    InfoTip,
    QuickTip,
    TileInfo,
    ContentType,
    DefaultIcon,
    ShellExtension,
    DropTarget,
    DelegateExecute,
    Supported_Uri_Protocols,
    ProgID,
    AppID,
    AppPublisher,
    AppIconReference,
    Max
}

Relevant documentation:

相关文档:

Sample usage:

示例用法:

static string AssocQueryString(AssocStr association, string extension)
{
    const int S_OK = 0;
    const int S_FALSE = 1;

    uint length = 0;
    uint ret = AssocQueryString(AssocF.None, association, extension, null, null, ref length);
    if (ret != S_FALSE)
    {
        throw new InvalidOperationException("Could not determine associated string");
    }

    var sb = new StringBuilder((int)length); // (length-1) will probably work too as the marshaller adds null termination
    ret = AssocQueryString(AssocF.None, association, extension, null, sb, ref length);
    if (ret != S_OK)
    {
        throw new InvalidOperationException("Could not determine associated string"); 
    }

    return sb.ToString();
}

回答by Harald Coppoolse

A late answer, but there is a good NUGET package that handles file associations: File Association

一个迟到的答案,但有一个很好的 NUGET 包可以处理文件关联:文件关联

Link NUGET File Association

链接 NUGET 文件关联

Usage is simple, for instance to add all allowed file extensions to a context menu:

用法很简单,例如将所有允许的文件扩展名添加到上下文菜单:

private void OnMenuSourceFileOpening(object sender, ...)
{   // open a context menu with the associated files + ".txt" files
    if (File.Exists(this.SelectedFileName))
    {
        string fileExt = Path.GetExtension(this.SelectedFileNames);
        string[] allowedExtensions = new string[] { fileExt, ".txt" };
        var fileAssociations = allowedExtensions
            .Select(ext => new FileAssociationInfo(ext));
        var progInfos = fileAssociations
            .Select(fileAssoc => new ProgramAssociationInfo (fileAssoc.ProgID));
        var toolstripItems = myProgInfos
            .Select(proginfo => new ToolStripLabel (proginfo.Description) { Tag = proginfo });
        // add also the prog info as Tag, for easy access
        //  when the toolstrip item is selected
        // of course this can also be done in one long linq statement

        // fill the context menu:
        this.contextMenu1.Items.Clear();
        this.contextMenuOpenSourceFile.Items.AddRange (toolstripItems.ToArray());
    }
}