60

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

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

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

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

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

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

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

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

4

6 回答 6

80

目前所有的答案都是不可靠的。注册表是一个实现细节,确实这样的代码在我的 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
}

相关文件:

示例用法:

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();
}
于 2013-07-21T14:31:26.730 回答
18

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

于 2008-10-02T13:47:17.383 回答
8

嗬!当然。

HKEY_CLASSES_ROOT\.txt

包括对

HKEY_CLASSES_ROOT\txtfile

其中包含一个子项

HKEY_CLASSES_ROOT\txtfile\shell\open\command

其中引用记事本。

已排序,非常感谢!

巴特

于 2008-10-02T13:52:05.657 回答
5

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

于 2008-10-02T13:48:23.073 回答
3

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

这会给你类名。例如 .txt 有一个默认的 txtfile

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

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

于 2008-10-02T13:50:48.827 回答
3

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

链接 NUGET 文件关联

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

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());
    }
}
于 2015-10-16T09:35:14.633 回答