如何正确检索与 Windows 上的扩展关联的打开命令

How do I correctly retrieve the open command associated with an extension on Windows?

本文关键字:扩展 关联 命令 何正确 检索 Windows      更新时间:2023-10-16

我正在尝试找出用于打开给定扩展名文件的可执行文件,因此如果扩展名没有,我可以显示该可执行文件的图标。

我知道文件类型的HKEY_CLASSES_ROOT注册表项中的开放谓词,但我发现它的值并不总是正确的。

例如,我目前正在OS X上运行Windows。PDF文件的默认关联是Safari。我通过资源管理器将默认关联更改为Adobe Reader。注册表中的打开谓词仍然是 Safari,但是当我双击 PDF 文件时,它会使用 Adobe Reader 打开。32 位和 64 位注册表具有相同的值。

是否有更好的方法来检索文件类型与 .NET 或 winapi 的关联?

最好的

办法可能是使用Assoc*组函数,例如通过 PInvoke AssocQueryKey()AssocQueryString()。但是,我不知道 .NET 框架的许多化身附带的众多类之一是否已经为您包装了它。但命令行管理程序 API 为你提供了一个检索此信息的选项。

另请注意备注部分,其中指出上述函数是 IQueryAssociations 接口的包装器,这使得你更有可能从 .NET 中获得所需的另一条更直接的路由。

旧式函数是这个:FindExecutable()。不过,不要使用它。它使用与ShellExecute()相同的有缺陷的错误代码魔法。

另请参阅 Windows 的解答:列出和启动与扩展关联的应用程序

我的代码包括检查以防止一些常见错误...希望有帮助:-)

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace HQ.Util.Unmanaged
{
    /// <summary>
    /// Usage: string executablePath = FileAssociation.GetExecFileAssociatedToExtension(pathExtension, "open");
    /// Usage: string command FileAssociation.GetExecCommandAssociatedToExtension(pathExtension, "open");
    /// </summary>
    public static class FileAssociation
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ext"></param>
        /// <param name="verb"></param>
        /// <returns>Return null if not found</returns>
        public static string GetExecCommandAssociatedToExtension(string ext, string verb = null)
        {
            if (ext[0] != '.')
            {
                ext = "." + ext;
            }
            string  executablePath = FileExtentionInfo(AssocStr.Command, ext, verb);
            // Ensure to not return the default OpenWith.exe associated executable in Windows 8 or higher
            if (!string.IsNullOrEmpty(executablePath) && File.Exists(executablePath) &&
                !executablePath.ToLower().EndsWith(".dll"))
            {
                if (executablePath.ToLower().EndsWith("openwith.exe"))
                {
                    return null; // 'OpenWith.exe' is th windows 8 or higher default for unknown extensions. I don't want to have it as associted file
                }
                return executablePath;
            }
            return executablePath;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ext"></param>
        /// <param name="verb"></param>
        /// <returns>Return null if not found</returns>
        public static string GetExecFileAssociatedToExtension(string ext, string verb = null)
        {
            if (ext[0] != '.')
            {
                ext = "." + ext;
            }
            string executablePath = FileExtentionInfo(AssocStr.Executable, ext, verb); // Will only work for 'open' verb
            if (string.IsNullOrEmpty(executablePath))
            {
                executablePath = FileExtentionInfo(AssocStr.Command, ext, verb); // required to find command of any other verb than 'open'
                // Extract only the path
                if (!string.IsNullOrEmpty(executablePath) && executablePath.Length > 1) 
                {
                    if (executablePath[0] == '"')
                    {
                        executablePath = executablePath.Split('"')[1];
                    }
                    else if (executablePath[0] == ''')
                    {
                        executablePath = executablePath.Split(''')[1];
                    }
                }
            }
            // Ensure to not return the default OpenWith.exe associated executable in Windows 8 or higher
            if (!string.IsNullOrEmpty(executablePath) && File.Exists(executablePath) &&
                !executablePath.ToLower().EndsWith(".dll"))
            {
                if (executablePath.ToLower().EndsWith("openwith.exe"))
                {
                    return null; // 'OpenWith.exe' is th windows 8 or higher default for unknown extensions. I don't want to have it as associted file
                }
                return executablePath;
            }
            return executablePath;
        }
        [DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra, [Out] StringBuilder pszOut, [In][Out] ref uint pcchOut);
        private static string FileExtentionInfo(AssocStr assocStr, string doctype, string verb)
        {
            uint pcchOut = 0;
            AssocQueryString(AssocF.Verify, assocStr, doctype, verb, null, ref pcchOut);
            Debug.Assert(pcchOut != 0);
            if (pcchOut == 0)
            {
                return "";
            }
            StringBuilder pszOut = new StringBuilder((int)pcchOut);
            AssocQueryString(AssocF.Verify, assocStr, doctype, verb, pszOut, ref pcchOut);
            return pszOut.ToString();
        }
        [Flags]
        public enum AssocF
        {
            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
        }
        public enum AssocStr
        {
            Command = 1,
            Executable,
            FriendlyDocName,
            FriendlyAppName,
            NoOpen,
            ShellNewValue,
            DDECommand,
            DDEIfExec,
            DDEApplication,
            DDETopic
        }

    }
}

您还需要检查HKEY_USERS\{User}\Software\Classes。 用户可以覆盖自己的默认应用程序。