Как я могу получить значок приложения для любого запущенного приложения?C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Как я могу получить значок приложения для любого запущенного приложения?

Сообщение Anonymous »

Я хочу создать собственную панель задач в приложении WinUI3. У меня есть код для получения всех открытых окон (на основе этого ответа), но теперь я пытаюсь получить значки, связанные с процессом, для каждого окна. После долгих исследований, проб и ошибок и чтения многих других (в конечном итоге неудачных) ответов SO у меня есть несколько разных методов. Три из них функциональны, но недостаточно полны, а один вообще не работает:
ПРИМЕЧАНИЕ. Для всех этих методов я получаю исполняемый файл приложения (sourcePath) с помощью следующий метод:

Код: Выделить всё

private static string GetProcessExecutablePath(Process process) {
try {
StringBuilder buffer = new(1024);
uint size = (uint) buffer.Capacity;
IntPtr hProcess = process.Handle;

if (QueryFullProcessImageName(hProcess, 0, buffer, ref size) != 0) {
return buffer.ToString();
}
} catch (Win32Exception ex) {
Debug.WriteLine($"Error accessing process handle for {process.ProcessName}: {ex.Message}");
}

return null;
}
1. [Функционально] Извлеките значок из исполняемого файла:

Код: Выделить всё

public static string ExtractIconFromFile(string sourcePath) {
try {
// using ensures that the Icon is disposed of
using Icon icon = Icon.ExtractAssociatedIcon(sourcePath);

// using ensures that the Bitmap is disposed of
using Bitmap bitmap = icon.ToBitmap();

return bitmap.SaveToFile(Path.Combine(Path.GetTempPath(), ".TestTaskbar2", "AppIcons"), $"{desktopApp.AppName}_{Guid.NewGuid()}");
} catch (Exception ex) when (ex is ArgumentNullException or IOException) {
return null;
}
}
Этот метод не работает, если значок приложения хранится в другом месте, например в файле ярлыка меню «Пуск» или в отдельном файле изображения в случае приложения UWP. В этом случае эта функция возвращает изображение значка исполняемого файла по умолчанию. Этот метод также бесполезен, если процесс, из которого исходит sourcePath, был запущен от имени администратора, а код C# — нет, как тогда exe-файл (

Код: Выделить всё

sourcePath
) вообще не может быть найден.
2. [Функционально] Извлечение значка из ярлыка меню «Пуск» по пути к файлу:
Этот код ищет файл ярлыка в папке меню «Пуск» (я запускаю его как для конкретного пользователя, так и для операционной системы). -папка меню «Пуск»), которая указывает на тот же исполняемый файл, тот же каталог или подкаталог или родительский каталог исполняемого файла приложения, для которого мы получаем значок. Затем он получает значок, который использует файл ярлыка.

Код: Выделить всё

private static List FindShortcutIconsByPath(string directory, string sourceFile) {
string appDirectory = Path.GetDirectoryName(sourceFile);

List icons = [];

foreach (string file in Directory.GetFiles(directory, "*.lnk", SearchOption.AllDirectories)) {
WshShell shell = new();
IWshShortcut shortcut = null;
try {
shortcut = (IWshShortcut) shell.CreateShortcut(file);
string targetPath = shortcut.TargetPath;
string targetDirectory = Path.GetDirectoryName(targetPath);

// App location exists and target location exists and app does not reside in C:\Windows or C:\Windows\System32
// (Many windows apps are housed in Windows and System32, and all of their icons will be found for...
// ...each one of the apps, with no way to distinguish by path which is right)
if (appDirectory is not null && targetDirectory is not null && !appDirectory.ToLower().Equals(@"c:\windows") && !appDirectory.ToLower().Equals(@"c:\windows\system32")) {
// Target points to the exact folder the app is in,
// or target points to a subfolder of app's location,
// or app is in a subfolder of where target points
if (targetDirectory.Equals(appDirectory, StringComparison.OrdinalIgnoreCase)
|| targetPath.StartsWith(appDirectory, StringComparison.OrdinalIgnoreCase)
|| appPath.StartsWith(targetDirectory, StringComparison.OrdinalIgnoreCase)) {
icons.Add(ExtractIconFromFile(shortcut.IconLocation ?? targetPath));
}
}
} finally {
// COM objects must be released to prevent memory leaks
if (shortcut != null) {
Marshal.ReleaseComObject(shortcut);
}

Marshal.ReleaseComObject(shell);
}
}

return icons;
}
Иногда ярлык меню «Пуск» указывает на другой исполняемый файл одного и того же приложения (например, на средство обновления, установщик или средство запуска), поэтому этот код пытается учесть это путем сравнения папки и просмотр подпапок. Однако он не идеален и по-прежнему может пропускать приложения или находить слишком много значков из других исполняемых файлов (я пытался учесть это с помощью папок Windows и System32, но не могу этого сделать для все). В таких случаях не существует программного способа определить, какой значок правильный.
3. [Функционально] Извлечение значка из ярлыка меню «Пуск» по имени:
Этот код аналогичен приведенному выше, но находит ярлыки меню «Пуск», сопоставляя их имена с приложением.

Код: Выделить всё

private static List FindShortcutIconsByName(string directory, string appName) {
List icons = [];

foreach (string file in Directory.GetFiles(directory, "*.lnk", SearchOption.AllDirectories)) {
WshShell shell = new();
IWshShortcut shortcut = null;
try {
if (Path.GetFileNameWithoutExtension(file).ToLower().Replace("microsoft", "").Trim() == appName.ToLower().Replace("microsoft", "").Trim()) {
shortcut = (IWshShortcut) shell.CreateShortcut(file);
icons.Add(ExtractIconFromFile(shortcut.IconLocation ?? shortcut.TargetPath));
}
} finally {
// COM objects must be released to prevent memory leaks
if (shortcut != null) {
Marshal.ReleaseComObject(shortcut);
}

Marshal.ReleaseComObject(shell);
}
}

return icons;
}
Как вы можете себе представить, этот метод часто не может найти ярлык, но он предназначен для резервного копирования. Хорошей новостью является то, что когда он находит ярлык, это вполне вероятно правильный значок.
4. [Не удалось] — получить значки приложений UWP
Я пытался использовать код из этого ответа, чтобы получить значки для приложений UWP, но он просто возвращает значение null для каждого отдельного процесса, и я не знаю почему.
Вот моя слегка измененная реализация кода в этом ответе: https://pastebin.com/rAuFgXge. В основном это связано с очисткой VS множества настроек форматирования и стиля, и я изменил метод Show, чтобы он стал методом AppxPackage, а не отдельной функцией. Он также использует Debug.WriteLine, а не Console.Writeline, поскольку я хочу видеть выходные данные в отладчике VS.
EDIT: Вот как я вызвал код для тестирования:

Код: Выделить всё

foreach (Process p in Process.GetProcesses()) {
AppxPackage package = AppxPackage.FromProcess(p);
if (package != null) {
package.Show();
Debug.WriteLine("\n\n");
} else {
Debug.WriteLine($"Could not find package for {p.ProcessName}");
}
}
Проблема
Используя эти три метода вместе, я иногда могу найти три хороших значка (в этом случае я выбираю один с самым высоким разрешением), иногда получаю хороший значок из одного из них, иногда вообще не получаю хороших значков (я получаю значок исполняемого файла Windows по умолчанию или заполнитель по умолчанию), а иногда получаю дюжину значков, только один из которых правильный.
Для некоторых приложений лучше использовать исполняемый файл вместо значков ярлыков в меню «Пуск», для других лучше использовать значки ярлыков вместо исполняемых файлов, и я не знаю, как это сделать программно. решайте, что лучше. На данный момент мой план состоит в том, чтобы позволить пользователю выбирать между возможными значками приложений или загружать свои собственные, но это не идеально.
Самая большая проблема заключается в Приложения UWP. Из-за сложной и противоречивой структуры приложений ни один из этих методов на них не работает. Папки, в которых хранятся значки, часто имеют непоследовательные названия и расположение в лучшем случае, а обилие значков внутри не позволяет надежно выбрать одну.
Итак, в целом...< /p>
Как получить значок приложения для приложений UWP (и надежно получить значок приложения для других приложений)

Подробнее здесь: https://stackoverflow.com/questions/791 ... unning-app
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»