【问题标题】:How to get Application name to be displayed in open-with list?如何让应用程序名称显示在打开方式列表中?
【发布时间】:2012-08-12 11:00:27
【问题描述】:

这是我的问题here 的延续。我正在为 *.bmp 类型创建一个打开列表。根据该问题的答案,我已经从注册表项中创建了一个打开列表中的应用程序列表。

   public void RecommendedPrograms(string ext)
    {


        string baseKey = @"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\." + ext;

        using (RegistryKey rk = Registry.CurrentUser.OpenSubKey(baseKey + @"\OpenWithList"))
        {
            if (rk != null)
            {
                string mruList = (string)rk.GetValue("MRUList");
                if (mruList != null)
                {
                    foreach (char c in mruList.ToString())
                    {
                        string str=rk.GetValue(c.ToString()).ToString();
                        if (!progs.Contains(str))
                        {
                            progs.Add(str);
                        }
                    }
                }
            }
        }

        using (RegistryKey rk = Registry.CurrentUser.OpenSubKey(baseKey + @"\OpenWithProgids"))
        {
            if (rk != null)
            {
                foreach (string item in rk.GetValueNames())
                    progs.Add(item);
            }
        }

        using (RegistryKey rk = Registry.ClassesRoot.OpenSubKey("." + ext + @"\OpenWithList"))
        {
            if (rk != null)
            {
                foreach (var item in rk.GetSubKeyNames())
                {
                    if (!progs.Contains(item))
                    {
                        progs.Add(item.ToString());
                    }
                }
            }
        }
        using (RegistryKey rk = Registry.ClassesRoot.OpenSubKey("." + ext + @"\OpenWithProgids"))
        {
            if (rk != null)
            {
                foreach (string item in rk.GetValueNames())
                {
                    if (!progs.Contains(item))
                    {
                        progs.Add(item);
                    }
                }
            }
        }

    }

此方法将返回一个应用程序名称列表,例如,

  • 画.画
  • ehshell.exe
  • MSPaint.exe
  • ois.exe
  • VisualStudio.bmp.10.0
  • QuickTime.bmp

这些是 PrgId,我可以从

获取打开特定应用程序需要执行的命令
      public string GetRegisteredApplication(string StrProgID)
    {
        // 
        //  Return registered application by file's extension
        // 
        RegistryKey oHKCR;
        RegistryKey oOpenCmd;
        string command;

        if (Environment.Is64BitOperatingSystem == true)
        {
            oHKCR = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.ClassesRoot, RegistryView.Registry64);
        }
        else
        {
            oHKCR = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.ClassesRoot, RegistryView.Registry32);
        }
        try
        {


            oOpenCmd = oHKCR.OpenSubKey(StrProgID + "\\shell\\open\\command");
            if (oOpenCmd == null)
            {
                oOpenCmd = oHKCR.OpenSubKey("\\Applications\\" + StrProgID + "\\shell\\open\\command");
            }
            if (oOpenCmd != null)
            {
                command = oOpenCmd.GetValue(null).ToString();
                oOpenCmd.Close();
            }
            else
            {
                return null;
            }
        }
        catch (Exception ex)
        {
            return null;
        }
        return command;
    }

现在如何获得必须在菜单中显示的应用程序名称? 每次您开始使用新的应用程序时,Windows 操作系统都会自动从 exe 文件的版本资源中提取应用程序名称,并将其存储在称为“MuiCache”的注册表项中以供以后使用。 MUICache 数据存储在 HKEY_CURRENT_USER\Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\MuiCache 下

但我们不能保证应用程序至少运行过一次。我们也可以直接从文件的版本资源中获取描述密钥,但是我在从命令中拆分应用程序路径时遇到了一些麻烦

%SystemRoot%\System32\rundll32.exe "%ProgramFiles%\Windows 照片 Viewer\PhotoViewer.dll", ImageView_Fullscreen %1

如何获取姓名信息?

在我的命令列表下方

  • "C:\Windows\System32\rundll32.exe \"C:\Program Files\Windows 照片查看器\PhotoViewer.dll\", ImageView_Fullscreen %1"
  • "\"C:\Windows\eHome\ehshell.exe\"\"%1\""
  • "C:\PROGRA~1\MIF5BA~1\Office14\OIS.EXE /shellOpen \"%1\""
  • "\"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe\" /dde"
  • "C:\Program Files (x86)\QuickTime\PictureViewer.exe \"%1\""

【问题讨论】:

    标签: c# wpf registry open-with


    【解决方案1】:

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

    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
            }
    
    
    
        }
    }
    

    【讨论】:

      【解决方案2】:

      更新:抱歉,我看错了你的帖子。

      这仅在您根据扩展名查找默认应用程序名称时才有帮助。不基于 progID。

      public static class FileAssoc
      {
          [DllImport("Shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
          static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra, [Out] StringBuilder sOut, [In][Out] ref uint nOut);
      
          [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
          }
      
          public static string GetApplicationName(string fileExtensionIncludingDot)
          {
              uint cOut = 0;
              if (AssocQueryString(AssocF.Verify, AssocStr.FriendlyAppName, fileExtensionIncludingDot, null, null, ref cOut) != 1)
                  return null;
              StringBuilder pOut = new StringBuilder((int)cOut);
              if (AssocQueryString(AssocF.Verify, AssocStr.FriendlyAppName, fileExtensionIncludingDot, null, pOut, ref cOut) != 0)
                  return null;
              return pOut.ToString();
          }
      }
      

      你可以这样使用它

      string applicationName = FileAssoc.GetApplicationName(".docx");
      // results in "Microsoft Office Word"
      

      【讨论】:

        【解决方案3】:

        基于 Amal 的解决方案,您只需要处理两个场景:

        1) 启动“C:\Windows\System32\rundll32.exe”的那些 2) 其他一切

        如果您想要一些粗略的东西,您可以将“C:\Windows\System32\rundll32.exe”替换为一个空字符串。将 "s 替换为空字符串,以第一个正斜杠 (/) 或 % 终止您的字符串,然后修剪结果。

        你会留下你想要的名称的 .dll 或 .exe 的名称(这可能会用 RegEx 更优雅地完成,如果你需要处理,这个解决方案最终会很快变得复杂更多场景)。

        然后你通过 Amal 的代码运行它,你应该得到你想要的。

        【讨论】:

          【解决方案4】:

          如果您知道命令列表,那么您可以使用下面给出的代码检索描述

           FileVersionInfo.GetVersionInfo(Path.Combine(Environment.SystemDirectory, "Notepad.exe"));
           FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(Environment.SystemDirectory + "\\Notepad.exe");
          
          
              // Print the file name and version number.
              Console.WriteLine("File: " + myFileVersionInfo.FileDescription + '\n' +
                 "Version number: " + myFileVersionInfo.FileVersion);
          

          【讨论】:

          • 是的,伙计...但是我无法找到一种方法来始终如一地从命令中拆分出 exe 或 dll 路径,例如:在“%SystemRoot%\System32\rundll32. exe "%ProgramFiles%\Windows Photo Viewer\PhotoViewer.dll", ImageView_Fullscreen %1",我需要拆分 PhotoViewer.dll 以便在其他情况下从 FileVersionInfo 获取描述,例如 "C:\\Windows\\system32 \\NOTEPAD.EXE %1" 这是直截了当的
          猜你喜欢
          • 1970-01-01
          • 2023-03-12
          • 2011-09-17
          • 1970-01-01
          • 2011-06-05
          • 1970-01-01
          • 2020-10-07
          • 1970-01-01
          • 2013-02-15
          相关资源
          最近更新 更多