Как получить имя приложения для отображения в открытом списке?
Это продолжение моего вопроса здесь. Я создаю список open with для типа *.bmp. Согласно ответам на этот вопрос, я создал список приложений в списке open with из разделов реестра.
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);
}
}
}
}
}
Этот метод вернет список имен приложений, например,
- Paint.Picture
- ehshell.exe
- mspaint.exe
- ois.exe
- VisualStudio.bmp.10.0
- QuickTime.bmp
Это PrgIds, и я могу получить команду, которую нужно выполнить, чтобы открыть конкретное приложение из
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\ Программное обеспечение \ Классы \ Локальные настройки \ Программное обеспечение \Microsoft\Windows\Shell\MuiCache
но мы не можем гарантировать, что приложение было запущено хотя бы один раз. Также мы можем напрямую получить ключ описания из ресурсов версии файла, но у меня есть некоторые проблемы с выделением пути приложения из таких команд, как
%SystemRoot%\System32\rundll32.exe "%ProgramFiles%\Windows Photo Viewer\PhotoViewer.dll", ImageView_Fullscreen %1
Как я могу получить информацию об имени?
Ниже список моих команд
- "C: \ Windows \ System32 \ rundll32.exe \" C: \ Program Files \ Windows Photo Viewer \ 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 \ ""
4 ответа
Опираясь на решение Amal, у вас есть только два сценария, которые вам нужно решить:
1) те, которые запускают "C:\Windows\System32\rundll32.exe" 2) все остальное
Если вы хотите что-то грубое, вы можете заменить "C: \ Windows \ System32 \ rundll32.exe" пустой строкой. Замените "s" на пустые строки, завершите вашу строку первой косой чертой (/) или%, а затем обрежьте результат.
У вас останется имя.dll или.exe, имя которого вы хотите (возможно, это будет сделано более изящно с помощью RegEx, и это решение быстро усложнится, если вам потребуется обработать больше сценариев),
Затем вы запускаете это через бит кода из Amal, и у вас должно быть то, что вы хотите.
Если вы знаете список команд, то вы можете получить описание, используя приведенный ниже код
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);
Обновление: извините, я неправильно прочитал ваш пост.
Это помогает, только если вы ищете имя приложения по умолчанию на основе расширения. Не основано на 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"
Мой код, который включает проверку, чтобы предотвратить некоторые распространенные ошибки... Надеюсь, это поможет:-)
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
}
}
}