【问题标题】:How can I get the description of a file extension in .NET如何在 .NET 中获取文件扩展名的描述
【发布时间】:2011-04-16 08:29:11
【问题描述】:

嗨,

Windows 提供文件扩展名的描述,例如 .cpl 文件的“控制面板项”和 .daa 文件的“PowerISO 文件”。有什么方法可以在 .NET 中获取这些数据?我使用 C#,但可以阅读所有其他 .NET 语言。还有一种方法可以获得扩展的默认图标吗?任何帮助将不胜感激。

提前致谢

【问题讨论】:

标签: .net windows


【解决方案1】:

您可以使用SHGetFileInfo API 来获取该信息。这是一个包装器方法:

    public static string GetFileTypeDescription(string fileNameOrExtension)
    {
        SHFILEINFO shfi;
        if (IntPtr.Zero != SHGetFileInfo(
                            fileNameOrExtension,
                            FILE_ATTRIBUTE_NORMAL,
                            out shfi,
                            (uint)Marshal.SizeOf(typeof(SHFILEINFO)),
                            SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME))
        {
            return shfi.szTypeName;
        }
        return null;
    }

    [DllImport("shell32")]
    private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, out SHFILEINFO psfi, uint cbFileInfo, uint flags);

    [StructLayout(LayoutKind.Sequential)]
    private struct SHFILEINFO
    {
        public IntPtr hIcon;
        public int iIcon;
        public uint dwAttributes;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string szDisplayName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
        public string szTypeName;
    }

    private const uint FILE_ATTRIBUTE_READONLY = 0x00000001;
    private const uint FILE_ATTRIBUTE_HIDDEN = 0x00000002;
    private const uint FILE_ATTRIBUTE_SYSTEM = 0x00000004;
    private const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
    private const uint FILE_ATTRIBUTE_ARCHIVE = 0x00000020;
    private const uint FILE_ATTRIBUTE_DEVICE = 0x00000040;
    private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
    private const uint FILE_ATTRIBUTE_TEMPORARY = 0x00000100;
    private const uint FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200;
    private const uint FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400;
    private const uint FILE_ATTRIBUTE_COMPRESSED = 0x00000800;
    private const uint FILE_ATTRIBUTE_OFFLINE = 0x00001000;
    private const uint FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000;
    private const uint FILE_ATTRIBUTE_ENCRYPTED = 0x00004000;
    private const uint FILE_ATTRIBUTE_VIRTUAL = 0x00010000;

    private const uint SHGFI_ICON = 0x000000100;     // get icon
    private const uint SHGFI_DISPLAYNAME = 0x000000200;     // get display name
    private const uint SHGFI_TYPENAME = 0x000000400;     // get type name
    private const uint SHGFI_ATTRIBUTES = 0x000000800;     // get attributes
    private const uint SHGFI_ICONLOCATION = 0x000001000;     // get icon location
    private const uint SHGFI_EXETYPE = 0x000002000;     // return exe type
    private const uint SHGFI_SYSICONINDEX = 0x000004000;     // get system icon index
    private const uint SHGFI_LINKOVERLAY = 0x000008000;     // put a link overlay on icon
    private const uint SHGFI_SELECTED = 0x000010000;     // show icon in selected state
    private const uint SHGFI_ATTR_SPECIFIED = 0x000020000;     // get only specified attributes
    private const uint SHGFI_LARGEICON = 0x000000000;     // get large icon
    private const uint SHGFI_SMALLICON = 0x000000001;     // get small icon
    private const uint SHGFI_OPENICON = 0x000000002;     // get open icon
    private const uint SHGFI_SHELLICONSIZE = 0x000000004;     // get shell size icon
    private const uint SHGFI_PIDL = 0x000000008;     // pszPath is a pidl
    private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010;     // use passed dwFileAttribute

(大多数常量实际上并没有在该代码中使用,但我还是把它们放在了以防你想让代码适应你的特定需求)

【讨论】:

  • 这与在 c# 中使用 FileInfo 类有何不同或更好? (只是好奇)
  • @Tony Abrams,FileInfo 类没有给你类型描述。否则,我认为它主要是 SHFILEINFO 的包装器......
  • using System.Runtime.InteropServices; 需要
【解决方案2】:

为了使用SHGetFileInfo,该文件必须存在于磁盘上。如果您只有文件的名称,甚至只有扩展名,则需要直接从注册表中获取信息:

public static string GetFileTypeDisplayName(string extension) =>
    Registry.ClassesRoot.OpenSubKey(extension)?.GetValue(null) is string keyName ?
        Registry.ClassesRoot.OpenSubKey(keyName)?.GetValue(null) as string :
        null;

如果注册表中没有适合给定文件扩展名的条目,此方法将简单地返回 null

【讨论】:

    【解决方案3】:

    您可以像这样搜索注册表:

    • HKEY_CLASSES_ROOT 中搜索扩展名的默认值。例如HKEY_CLASSES_ROOT\.txt的默认值为txtfile
    • 然后搜索上一个结果的默认值:例如HKEY_CLASSES_ROOT\txtfile的默认值是Text Document

    经过两次搜索,答案是文本文档

    您可以通过RegEdit 测试任何其他扩展。

    访问此链接:http://www.codeproject.com/KB/cs/GetFileTypeAndIcon.aspx?display=Print

    这是这两个搜索的实现:

    public static class Helper
    {
        public static string GetFileDescription(string fileName)
        {
            if (fileName == null)
            {
                throw new ArgumentNullException("fileName");
            }
    
            RegistryKey registryKey1 = null;
            RegistryKey registryKey2 = null;
            try
            {
                FileInfo fileInfo = new FileInfo(fileName);
    
                if (string.IsNullOrEmpty(fileInfo.Extension))
                {
                    return string.Empty;
                }
    
                string extension = fileInfo.Extension.ToLowerInvariant();
    
                registryKey1 = Registry.ClassesRoot.OpenSubKey(extension);
                if (registryKey1 == null)
                {
                    return string.Empty;
                }
    
                object extensionDefaultObject = registryKey1.GetValue(null);
                if (!(extensionDefaultObject is string))
                {
                    return string.Empty;
                }
    
                string extensionDefaultValue = (string)extensionDefaultObject;
    
                registryKey2 = Registry.ClassesRoot.OpenSubKey(extensionDefaultValue);
                if (registryKey2 == null)
                {
                    return string.Empty;
                }
    
                object fileDescriptionObject = registryKey2.GetValue(null);
                if (!(fileDescriptionObject is string))
                {
                    return string.Empty;
                }
    
                string fileDescription = (string)fileDescriptionObject;
                return fileDescription;
            }
            catch (Exception)
            {
                return null;
            }
            finally
            {
                if (registryKey2 != null)
                {
                    registryKey2.Close();
                }
    
                if (registryKey1 != null)
                {
                    registryKey1.Close();
                }
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      扩展在 HKEY_CLASSES_ROOT 键中关联。所以你需要打开注册表,找到你感兴趣的值。你应该也可以在那里找到默认的图标。

      Here 是一个示例项目(我没有尝试过)。

      【讨论】:

      • 你不会在那里找到像“控制面板项目”这样好的字符串
      • 这里要注意的是扩展关联会因机器而异。
      • 谢谢大家。 SHGetFileInfo 似乎没有注册表操作那么粗糙。 Andrey 还写了一些扩展名,就像 PowerISO 文件一样,但 .cpl 文件只是称为 cplfiles,而不是 Windows 内默认程序控制面板中显示的“控制面板项目”。谢谢Thomas 非常有帮助,对于将来需要更多参考的其他人support.microsoft.com/kb/319350 也展示了如何在 C# 中使用 SHGetFileInfo。
      【解决方案5】:

      假设您的扩展名是 .xyz 要显示大多数用户友好的文本,例如“控制面板项”,您应该做两件事:

      1. 转到 HKEY_CLASSES_ROOT 并搜索节点 xyzfile。检查“cplfile”
      2. 如果不存在,您可以在同一个地方获得关联,但节点是 .xyz 。它会告诉您打开它的应用程序,以便您获取名称。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-14
        • 1970-01-01
        • 2019-11-17
        • 2016-10-23
        • 2015-12-31
        相关资源
        最近更新 更多