1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-18 11:02:57 +08:00

Merge pull request #31450 from peppy/association-manager-cleanup

This commit is contained in:
Dean Herbert 2025-01-08 23:38:52 +09:00 committed by GitHub
commit 2e10f83b5c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -56,14 +56,13 @@ namespace osu.Desktop.Windows
/// Installs file and URI associations. /// Installs file and URI associations.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Call <see cref="UpdateDescriptions"/> in a timely fashion to keep descriptions up-to-date and localised. /// Call <see cref="LocaliseDescriptions"/> in a timely fashion to keep descriptions up-to-date and localised.
/// </remarks> /// </remarks>
public static void InstallAssociations() public static void InstallAssociations()
{ {
try try
{ {
updateAssociations(); updateAssociations();
updateDescriptions(null); // write default descriptions in case `UpdateDescriptions()` is not called.
NotifyShellUpdate(); NotifyShellUpdate();
} }
catch (Exception e) catch (Exception e)
@ -76,17 +75,13 @@ namespace osu.Desktop.Windows
/// Updates associations with latest definitions. /// Updates associations with latest definitions.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Call <see cref="UpdateDescriptions"/> in a timely fashion to keep descriptions up-to-date and localised. /// Call <see cref="LocaliseDescriptions"/> in a timely fashion to keep descriptions up-to-date and localised.
/// </remarks> /// </remarks>
public static void UpdateAssociations() public static void UpdateAssociations()
{ {
try try
{ {
updateAssociations(); updateAssociations();
// TODO: Remove once UpdateDescriptions() is called as specified in the xmldoc.
updateDescriptions(null); // always write default descriptions, in case of updating from an older version in which file associations were not implemented/installed
NotifyShellUpdate(); NotifyShellUpdate();
} }
catch (Exception e) catch (Exception e)
@ -95,11 +90,17 @@ namespace osu.Desktop.Windows
} }
} }
public static void UpdateDescriptions(LocalisationManager localisationManager) // TODO: call this sometime.
public static void LocaliseDescriptions(LocalisationManager localisationManager)
{ {
try try
{ {
updateDescriptions(localisationManager); foreach (var association in file_associations)
association.LocaliseDescription(localisationManager);
foreach (var association in uri_associations)
association.LocaliseDescription(localisationManager);
NotifyShellUpdate(); NotifyShellUpdate();
} }
catch (Exception e) catch (Exception e)
@ -140,17 +141,6 @@ namespace osu.Desktop.Windows
association.Install(); association.Install();
} }
private static void updateDescriptions(LocalisationManager? localisation)
{
foreach (var association in file_associations)
association.UpdateDescription(getLocalisedString(association.Description));
foreach (var association in uri_associations)
association.UpdateDescription(getLocalisedString(association.Description));
string getLocalisedString(LocalisableString s) => localisation?.GetLocalisedString(s) ?? s.ToString();
}
#region Native interop #region Native interop
[DllImport("Shell32.dll")] [DllImport("Shell32.dll")]
@ -174,9 +164,20 @@ namespace osu.Desktop.Windows
#endregion #endregion
private record FileAssociation(string Extension, LocalisableString Description, string IconPath) private class FileAssociation
{ {
private string programId => $@"{program_id_prefix}{Extension}"; private string programId => $@"{program_id_prefix}{extension}";
private string extension { get; }
private LocalisableString description { get; }
private string iconPath { get; }
public FileAssociation(string extension, LocalisableString description, string iconPath)
{
this.extension = extension;
this.description = description;
this.iconPath = iconPath;
}
/// <summary> /// <summary>
/// Installs a file extension association in accordance with https://learn.microsoft.com/en-us/windows/win32/com/-progid--key /// Installs a file extension association in accordance with https://learn.microsoft.com/en-us/windows/win32/com/-progid--key
@ -189,14 +190,16 @@ namespace osu.Desktop.Windows
// register a program id for the given extension // register a program id for the given extension
using (var programKey = classes.CreateSubKey(programId)) using (var programKey = classes.CreateSubKey(programId))
{ {
programKey.SetValue(null, description.ToString());
using (var defaultIconKey = programKey.CreateSubKey(default_icon)) using (var defaultIconKey = programKey.CreateSubKey(default_icon))
defaultIconKey.SetValue(null, IconPath); defaultIconKey.SetValue(null, iconPath);
using (var openCommandKey = programKey.CreateSubKey(SHELL_OPEN_COMMAND)) using (var openCommandKey = programKey.CreateSubKey(SHELL_OPEN_COMMAND))
openCommandKey.SetValue(null, $@"""{exe_path}"" ""%1"""); openCommandKey.SetValue(null, $@"""{exe_path}"" ""%1""");
} }
using (var extensionKey = classes.CreateSubKey(Extension)) using (var extensionKey = classes.CreateSubKey(extension))
{ {
// set ourselves as the default program // set ourselves as the default program
extensionKey.SetValue(null, programId); extensionKey.SetValue(null, programId);
@ -208,13 +211,13 @@ namespace osu.Desktop.Windows
} }
} }
public void UpdateDescription(string description) public void LocaliseDescription(LocalisationManager localisationManager)
{ {
using var classes = Registry.CurrentUser.OpenSubKey(software_classes, true); using var classes = Registry.CurrentUser.OpenSubKey(software_classes, true);
if (classes == null) return; if (classes == null) return;
using (var programKey = classes.OpenSubKey(programId, true)) using (var programKey = classes.OpenSubKey(programId, true))
programKey?.SetValue(null, description); programKey?.SetValue(null, localisationManager.GetLocalisedString(description));
} }
/// <summary> /// <summary>
@ -225,7 +228,7 @@ namespace osu.Desktop.Windows
using var classes = Registry.CurrentUser.OpenSubKey(software_classes, true); using var classes = Registry.CurrentUser.OpenSubKey(software_classes, true);
if (classes == null) return; if (classes == null) return;
using (var extensionKey = classes.OpenSubKey(Extension, true)) using (var extensionKey = classes.OpenSubKey(extension, true))
{ {
// clear our default association so that Explorer doesn't show the raw programId to users // clear our default association so that Explorer doesn't show the raw programId to users
// the null/(Default) entry is used for both ProdID association and as a fallback friendly name, for legacy reasons // the null/(Default) entry is used for both ProdID association and as a fallback friendly name, for legacy reasons
@ -240,13 +243,24 @@ namespace osu.Desktop.Windows
} }
} }
private record UriAssociation(string Protocol, LocalisableString Description, string IconPath) private class UriAssociation
{ {
/// <summary> /// <summary>
/// "The <c>URL Protocol</c> string value indicates that this key declares a custom pluggable protocol handler." /// "The <c>URL Protocol</c> string value indicates that this key declares a custom pluggable protocol handler."
/// See https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa767914(v=vs.85). /// See https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa767914(v=vs.85).
/// </summary> /// </summary>
public const string URL_PROTOCOL = @"URL Protocol"; private const string url_protocol = @"URL Protocol";
private string protocol { get; }
private LocalisableString description { get; }
private string iconPath { get; }
public UriAssociation(string protocol, LocalisableString description, string iconPath)
{
this.protocol = protocol;
this.description = description;
this.iconPath = iconPath;
}
/// <summary> /// <summary>
/// Registers an URI protocol handler in accordance with https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa767914(v=vs.85). /// Registers an URI protocol handler in accordance with https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa767914(v=vs.85).
@ -256,31 +270,32 @@ namespace osu.Desktop.Windows
using var classes = Registry.CurrentUser.OpenSubKey(software_classes, true); using var classes = Registry.CurrentUser.OpenSubKey(software_classes, true);
if (classes == null) return; if (classes == null) return;
using (var protocolKey = classes.CreateSubKey(Protocol)) using (var protocolKey = classes.CreateSubKey(protocol))
{ {
protocolKey.SetValue(URL_PROTOCOL, string.Empty); protocolKey.SetValue(null, $@"URL:{description}");
protocolKey.SetValue(url_protocol, string.Empty);
using (var defaultIconKey = protocolKey.CreateSubKey(default_icon)) using (var defaultIconKey = protocolKey.CreateSubKey(default_icon))
defaultIconKey.SetValue(null, IconPath); defaultIconKey.SetValue(null, iconPath);
using (var openCommandKey = protocolKey.CreateSubKey(SHELL_OPEN_COMMAND)) using (var openCommandKey = protocolKey.CreateSubKey(SHELL_OPEN_COMMAND))
openCommandKey.SetValue(null, $@"""{exe_path}"" ""%1"""); openCommandKey.SetValue(null, $@"""{exe_path}"" ""%1""");
} }
} }
public void UpdateDescription(string description) public void LocaliseDescription(LocalisationManager localisationManager)
{ {
using var classes = Registry.CurrentUser.OpenSubKey(software_classes, true); using var classes = Registry.CurrentUser.OpenSubKey(software_classes, true);
if (classes == null) return; if (classes == null) return;
using (var protocolKey = classes.OpenSubKey(Protocol, true)) using (var protocolKey = classes.OpenSubKey(protocol, true))
protocolKey?.SetValue(null, $@"URL:{description}"); protocolKey?.SetValue(null, $@"URL:{localisationManager.GetLocalisedString(description)}");
} }
public void Uninstall() public void Uninstall()
{ {
using var classes = Registry.CurrentUser.OpenSubKey(software_classes, true); using var classes = Registry.CurrentUser.OpenSubKey(software_classes, true);
classes?.DeleteSubKeyTree(Protocol, throwOnMissingSubKey: false); classes?.DeleteSubKeyTree(protocol, throwOnMissingSubKey: false);
} }
} }
} }