diff --git a/src/ManagedShell.Common/Helpers/SoundHelper.cs b/src/ManagedShell.Common/Helpers/SoundHelper.cs index 34a4c67e..382a7c34 100644 --- a/src/ManagedShell.Common/Helpers/SoundHelper.cs +++ b/src/ManagedShell.Common/Helpers/SoundHelper.cs @@ -8,12 +8,95 @@ namespace ManagedShell.Common.Helpers public class SoundHelper { private const string SYSTEM_SOUND_ROOT_KEY = @"AppEvents\Schemes\Apps"; - private const int SND_FILENAME = 0x00020000; - private const int SND_ASYNC = 0x0001; - private const long SND_SYSTEM = 0x00200000L; + + /// + /// Flag values for playing the sound. + /// + [Flags] + public enum SND : uint + { + /// + /// The sound is played synchronously; PlaySound returns after the sound event completes (default behavior). + /// + SYNC = 0x0000, + + /// + /// The sound is played asynchronously; PlaySound returns immediately after initiating the sound. + /// To stop an asynchronously played sound, call PlaySound with pszSound set to NULL. + /// + ASYNC = 0x00000001, + + /// + /// No default sound event is used. If the sound is not found, PlaySound returns without playing a sound. + /// + NODEFAULT = 0x00000002, + + /// + /// The pszSound parameter points to a sound loaded in memory. + /// + MEMORY = 0x00000004, + + /// + /// The sound plays repeatedly until PlaySound is called with pszSound set to NULL. + /// Use the ASYNC flag with LOOP. + /// + LOOP = 0x00000008, + + /// + /// The specified sound event will yield to another sound event already playing in the same process. + /// If the required resource is busy, the function returns immediately without playing the sound. + /// + NOSTOP = 0x00000010, + + /// + /// The pszSound parameter is a system-event alias from the registry or WIN.INI file. + /// Do not use with FILENAME or RESOURCE. + /// + ALIAS = 0x00010000, + + /// + /// The pszSound parameter is a predefined identifier for a system-event alias. + /// + ALIAS_ID = 0x00110000, + + /// + /// The pszSound parameter is a file name. If the file is not found, the default sound is played unless NODEFAULT is set. + /// + FILENAME = 0x00020000, + + /// + /// The pszSound parameter is a resource identifier; hmod must identify the instance that contains the resource. + /// + RESOURCE = 0x00040004, + + /// + /// The pszSound parameter is an application-specific alias in the registry. + /// Can be combined with ALIAS or ALIAS_ID to specify an application-defined sound alias. + /// + APPLICATION = 0x00000080, + + /// + /// Requires Windows Vista or later. If set, triggers a SoundSentry event when the sound is played, + /// providing a visual cue for accessibility. + /// + SENTRY = 0x00080000, + + /// + /// Treats the sound as a ring from a communications app. + /// + RING = 0x00100000, + + /// + /// Requires Windows Vista or later. If set, the sound is assigned to the audio session for system notification sounds, + /// allowing control via the system volume slider. Otherwise, it is assigned to the application's default audio session. + /// + SYSTEM = 0x00200000, + } + + private const SND DEFAULT_SYSTEM_SOUND_FLAGS = SND.ASYNC | SND.NODEFAULT | SND.SYSTEM; [DllImport("winmm.dll", SetLastError = true, CharSet = CharSet.Auto)] - private static extern bool PlaySound(string pszSound, IntPtr hmod, uint fdwSound); + public static extern bool PlaySound(string pszSound, IntPtr hmod, SND soundFlags); /// /// Plays the specified system sound using the audio session for system notification sounds. @@ -24,34 +107,42 @@ public static bool PlaySystemSound(string app, string name) { try { - using (RegistryKey key = Registry.CurrentUser.OpenSubKey($"{SYSTEM_SOUND_ROOT_KEY}\\{app}\\{name}\\.Current")) + using var key = Registry.CurrentUser.OpenSubKey($@"{SYSTEM_SOUND_ROOT_KEY}\{app}\{name}\.Current"); + if (key == null) + { + ShellLogger.Debug($"SoundHelper: Unable to find sound {name} for app {app}"); + return false; + } + + var soundFileName = key.GetValue(null) as string; + if (string.IsNullOrEmpty(soundFileName)) { - if (key == null) - { - ShellLogger.Error($"SoundHelper: Unable to find sound {name} for app {app}"); - return false; - } - - if (key.GetValue(null) is string soundFileName) - { - if (string.IsNullOrEmpty(soundFileName)) - { - ShellLogger.Error($"SoundHelper: Missing file for sound {name} for app {app}"); - return false; - } - - return PlaySound(soundFileName, IntPtr.Zero, (uint)(SND_ASYNC | SND_FILENAME | SND_SYSTEM)); - } - else - { - ShellLogger.Error($"SoundHelper: Missing file for sound {name} for app {app}"); - return false; - } + ShellLogger.Debug($"SoundHelper: Missing file for sound {name} for app {app}"); + return false; } + + return PlaySound(soundFileName, IntPtr.Zero, DEFAULT_SYSTEM_SOUND_FLAGS | SND.FILENAME); } catch (Exception e) { - ShellLogger.Error($"SoundHelper: Unable to play sound {name} for app {app}: {e.Message}"); + ShellLogger.Debug($"SoundHelper: Unable to play sound {name} for app {app}: {e.Message}"); + return false; + } + } + + /// + /// Plays the specified system sound using the audio session for system notification sounds. + /// + /// The name of the system sound for ".Default" to play. + public static bool PlaySystemSound(string alias) + { + try + { + return PlaySound(alias, IntPtr.Zero, DEFAULT_SYSTEM_SOUND_FLAGS | SND.ALIAS); + } + catch (Exception e) + { + ShellLogger.Debug($"SoundHelper: Unable to play sound {alias}: {e.Message}"); return false; } } @@ -62,24 +153,22 @@ public static bool PlaySystemSound(string app, string name) public static void PlayNotificationSound() { // System default sound for the classic notification balloon. - if (!PlaySystemSound("Explorer", "SystemNotification")) + if (PlaySystemSound("Explorer", "SystemNotification")) return; + if (EnvironmentHelper.IsWindows8OrBetter) { - if (EnvironmentHelper.IsWindows8OrBetter) - { - // Toast notification sound. - if (!PlaySystemSound(".Default", "Notification.Default")) - PlayXPNotificationSound(); - } - else - { + // Toast notification sound. + if (!PlaySystemSound("Notification.Default")) PlayXPNotificationSound(); - } + } + else + { + PlayXPNotificationSound(); } } - public static bool PlayXPNotificationSound() + public static void PlayXPNotificationSound() { - return PlaySystemSound(".Default", "SystemNotification"); + PlaySystemSound("SystemNotification"); } } } \ No newline at end of file diff --git a/src/ManagedShell.Common/ManagedShell.Common.csproj b/src/ManagedShell.Common/ManagedShell.Common.csproj index 0409ff73..7998fdff 100644 --- a/src/ManagedShell.Common/ManagedShell.Common.csproj +++ b/src/ManagedShell.Common/ManagedShell.Common.csproj @@ -4,6 +4,7 @@ netcoreapp3.1;net471;net6.0-windows true true + 12