// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using autoShell.Logging;
using Microsoft.WindowsAPICodePack.Shell;
namespace autoShell;
///
/// Windows implementation of .
/// Builds lookups from a hardcoded list of well-known apps and
/// dynamically discovered AppUserModelIDs from the shell AppsFolder.
///
internal sealed class WindowsAppRegistry : IAppRegistry
{
private readonly ILogger _logger;
private readonly Dictionary _friendlyNameToPath = new(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary _friendlyNameToId = new(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary _appMetadata;
public WindowsAppRegistry(ILogger logger)
{
_logger = logger;
string userName = Environment.UserName;
_appMetadata = new Dictionary(StringComparer.OrdinalIgnoreCase)
{
{ "chrome", ["chrome.exe"] },
{ "power point", ["C:\\Program Files\\Microsoft Office\\root\\Office16\\POWERPNT.EXE"] },
{ "powerpoint", ["C:\\Program Files\\Microsoft Office\\root\\Office16\\POWERPNT.EXE"] },
{ "word", ["C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE"] },
{ "winword", ["C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE"] },
{ "excel", ["C:\\Program Files\\Microsoft Office\\root\\Office16\\EXCEL.EXE"] },
{ "outlook", ["C:\\Program Files\\Microsoft Office\\root\\Office16\\OUTLOOK.EXE"] },
{ "visual studio", ["devenv.exe"] },
{ "visual studio code", [$"C:\\Users\\{userName}\\AppData\\Local\\Programs\\Microsoft VS Code\\Code.exe"] },
{ "edge", ["C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"] },
{ "microsoft edge", ["C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"] },
{ "notepad", ["C:\\Windows\\System32\\notepad.exe"] },
{ "paint", ["mspaint.exe"] },
{ "calculator", ["calc.exe"] },
{ "file explorer", ["C:\\Windows\\explorer.exe"] },
{ "control panel", ["C:\\Windows\\System32\\control.exe"] },
{ "task manager", ["C:\\Windows\\System32\\Taskmgr.exe"] },
{ "cmd", ["C:\\Windows\\System32\\cmd.exe"] },
{ "powershell", ["C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"] },
{ "snipping tool", ["C:\\Windows\\System32\\SnippingTool.exe"] },
{ "magnifier", ["C:\\Windows\\System32\\Magnify.exe"] },
{ "paint 3d", ["C:\\Program Files\\WindowsApps\\Microsoft.MSPaint_10.1807.18022.0_x64__8wekyb3d8bbwe\\"] },
{ "m365 copilot", ["C:\\Program Files\\WindowsApps\\Microsoft.MicrosoftOfficeHub_19.2512.45041.0_x64__8wekyb3d8bbwe\\M365Copilot.exe"] },
{ "copilot", ["C:\\Program Files\\WindowsApps\\Microsoft.MicrosoftOfficeHub_19.2512.45041.0_x64__8wekyb3d8bbwe\\M365Copilot.exe"] },
{ "spotify", ["C:\\Program Files\\WindowsApps\\SpotifyAB.SpotifyMusic_1.278.418.0_x64__zpdnekdrzrea0\\spotify.exe"] },
{ "github copilot", [$"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}\\AppData\\Local\\Microsoft\\WinGet\\Packages\\GitHub.Copilot_Microsoft.Winget.Source_8wekyb3d8bbwe\\copilot.exe", "GITHUB_COPILOT_ROOT_DIR", "--allow-all-tools"] },
};
foreach (var kvp in _appMetadata)
{
_friendlyNameToPath.Add(kvp.Key, kvp.Value[0]);
}
PopulateInstalledAppIds();
}
///
public string GetExecutablePath(string friendlyName)
=> _friendlyNameToPath.GetValueOrDefault(friendlyName);
///
public string GetAppUserModelId(string friendlyName)
=> _friendlyNameToId.GetValueOrDefault(friendlyName);
///
public string ResolveProcessName(string friendlyName)
{
string path = GetExecutablePath(friendlyName);
return path != null ? Path.GetFileNameWithoutExtension(path) : friendlyName;
}
///
public string GetWorkingDirectoryEnvVar(string friendlyName)
{
return _appMetadata.TryGetValue(friendlyName, out string[] value) && value.Length > 1
? value[1]
: null;
}
///
public string GetArguments(string friendlyName)
{
return _appMetadata.TryGetValue(friendlyName, out string[] value) && value.Length > 2
? string.Join(" ", value.Skip(2))
: null;
}
///
public IEnumerable GetAllAppNames()
=> _friendlyNameToId.Keys;
private void PopulateInstalledAppIds()
{
// GUID taken from https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
var appsFolderId = new Guid("{1e87508d-89c2-42f0-8a7e-645a0f50ca58}");
try
{
ShellObject appsFolder = (ShellObject)KnownFolderHelper.FromKnownFolderId(appsFolderId);
foreach (var app in (IKnownFolder)appsFolder)
{
string appName = app.Name;
if (_friendlyNameToId.ContainsKey(appName))
{
_logger.Debug("Key has multiple values: " + appName);
}
else
{
// The ParsingName property is the AppUserModelID
_friendlyNameToId.Add(appName, app.ParsingName);
}
}
}
catch (Exception ex)
{
_logger.Debug($"Failed to enumerate installed apps: {ex.Message}");
}
}
}