Skip to content

Commit cf7405d

Browse files
authored
Merge pull request #139 from xoascf/sound-develop
Update SoundHelper
2 parents c754a25 + a8fef36 commit cf7405d

File tree

2 files changed

+129
-39
lines changed

2 files changed

+129
-39
lines changed

src/ManagedShell.Common/Helpers/SoundHelper.cs

Lines changed: 128 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,95 @@ namespace ManagedShell.Common.Helpers
88
public class SoundHelper
99
{
1010
private const string SYSTEM_SOUND_ROOT_KEY = @"AppEvents\Schemes\Apps";
11-
private const int SND_FILENAME = 0x00020000;
12-
private const int SND_ASYNC = 0x0001;
13-
private const long SND_SYSTEM = 0x00200000L;
11+
12+
/// <summary>
13+
/// Flag values for playing the sound.
14+
/// </summary>
15+
[Flags]
16+
public enum SND : uint
17+
{
18+
/// <summary>
19+
/// The sound is played synchronously; PlaySound returns after the sound event completes (default behavior).
20+
/// </summary>
21+
SYNC = 0x0000,
22+
23+
/// <summary>
24+
/// The sound is played asynchronously; PlaySound returns immediately after initiating the sound.
25+
/// To stop an asynchronously played sound, call PlaySound with pszSound set to NULL.
26+
/// </summary>
27+
ASYNC = 0x00000001,
28+
29+
/// <summary>
30+
/// No default sound event is used. If the sound is not found, PlaySound returns without playing a sound.
31+
/// </summary>
32+
NODEFAULT = 0x00000002,
33+
34+
/// <summary>
35+
/// The pszSound parameter points to a sound loaded in memory.
36+
/// </summary>
37+
MEMORY = 0x00000004,
38+
39+
/// <summary>
40+
/// The sound plays repeatedly until PlaySound is called with pszSound set to NULL.
41+
/// Use the ASYNC flag with LOOP.
42+
/// </summary>
43+
LOOP = 0x00000008,
44+
45+
/// <summary>
46+
/// The specified sound event will yield to another sound event already playing in the same process.
47+
/// If the required resource is busy, the function returns immediately without playing the sound.
48+
/// </summary>
49+
NOSTOP = 0x00000010,
50+
51+
/// <summary>
52+
/// The pszSound parameter is a system-event alias from the registry or WIN.INI file.
53+
/// Do not use with FILENAME or RESOURCE.
54+
/// </summary>
55+
ALIAS = 0x00010000,
56+
57+
/// <summary>
58+
/// The pszSound parameter is a predefined identifier for a system-event alias.
59+
/// </summary>
60+
ALIAS_ID = 0x00110000,
61+
62+
/// <summary>
63+
/// The pszSound parameter is a file name. If the file is not found, the default sound is played unless NODEFAULT is set.
64+
/// </summary>
65+
FILENAME = 0x00020000,
66+
67+
/// <summary>
68+
/// The pszSound parameter is a resource identifier; hmod must identify the instance that contains the resource.
69+
/// </summary>
70+
RESOURCE = 0x00040004,
71+
72+
/// <summary>
73+
/// The pszSound parameter is an application-specific alias in the registry.
74+
/// Can be combined with ALIAS or ALIAS_ID to specify an application-defined sound alias.
75+
/// </summary>
76+
APPLICATION = 0x00000080,
77+
78+
/// <summary>
79+
/// Requires Windows Vista or later. If set, triggers a SoundSentry event when the sound is played,
80+
/// providing a visual cue for accessibility.
81+
/// </summary>
82+
SENTRY = 0x00080000,
83+
84+
/// <summary>
85+
/// Treats the sound as a ring from a communications app.
86+
/// </summary>
87+
RING = 0x00100000,
88+
89+
/// <summary>
90+
/// Requires Windows Vista or later. If set, the sound is assigned to the audio session for system notification sounds,
91+
/// allowing control via the system volume slider. Otherwise, it is assigned to the application's default audio session.
92+
/// </summary>
93+
SYSTEM = 0x00200000,
94+
}
95+
96+
private const SND DEFAULT_SYSTEM_SOUND_FLAGS = SND.ASYNC | SND.NODEFAULT | SND.SYSTEM;
1497

1598
[DllImport("winmm.dll", SetLastError = true, CharSet = CharSet.Auto)]
16-
private static extern bool PlaySound(string pszSound, IntPtr hmod, uint fdwSound);
99+
public static extern bool PlaySound(string pszSound, IntPtr hmod, SND soundFlags);
17100

18101
/// <summary>
19102
/// 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)
24107
{
25108
try
26109
{
27-
using (RegistryKey key = Registry.CurrentUser.OpenSubKey($"{SYSTEM_SOUND_ROOT_KEY}\\{app}\\{name}\\.Current"))
110+
using var key = Registry.CurrentUser.OpenSubKey($@"{SYSTEM_SOUND_ROOT_KEY}\{app}\{name}\.Current");
111+
if (key == null)
112+
{
113+
ShellLogger.Debug($"SoundHelper: Unable to find sound {name} for app {app}");
114+
return false;
115+
}
116+
117+
var soundFileName = key.GetValue(null) as string;
118+
if (string.IsNullOrEmpty(soundFileName))
28119
{
29-
if (key == null)
30-
{
31-
ShellLogger.Error($"SoundHelper: Unable to find sound {name} for app {app}");
32-
return false;
33-
}
34-
35-
if (key.GetValue(null) is string soundFileName)
36-
{
37-
if (string.IsNullOrEmpty(soundFileName))
38-
{
39-
ShellLogger.Error($"SoundHelper: Missing file for sound {name} for app {app}");
40-
return false;
41-
}
42-
43-
return PlaySound(soundFileName, IntPtr.Zero, (uint)(SND_ASYNC | SND_FILENAME | SND_SYSTEM));
44-
}
45-
else
46-
{
47-
ShellLogger.Error($"SoundHelper: Missing file for sound {name} for app {app}");
48-
return false;
49-
}
120+
ShellLogger.Debug($"SoundHelper: Missing file for sound {name} for app {app}");
121+
return false;
50122
}
123+
124+
return PlaySound(soundFileName, IntPtr.Zero, DEFAULT_SYSTEM_SOUND_FLAGS | SND.FILENAME);
51125
}
52126
catch (Exception e)
53127
{
54-
ShellLogger.Error($"SoundHelper: Unable to play sound {name} for app {app}: {e.Message}");
128+
ShellLogger.Debug($"SoundHelper: Unable to play sound {name} for app {app}: {e.Message}");
129+
return false;
130+
}
131+
}
132+
133+
/// <summary>
134+
/// Plays the specified system sound using the audio session for system notification sounds.
135+
/// </summary>
136+
/// <param name="alias">The name of the system sound for ".Default" to play.</param>
137+
public static bool PlaySystemSound(string alias)
138+
{
139+
try
140+
{
141+
return PlaySound(alias, IntPtr.Zero, DEFAULT_SYSTEM_SOUND_FLAGS | SND.ALIAS);
142+
}
143+
catch (Exception e)
144+
{
145+
ShellLogger.Debug($"SoundHelper: Unable to play sound {alias}: {e.Message}");
55146
return false;
56147
}
57148
}
@@ -62,24 +153,22 @@ public static bool PlaySystemSound(string app, string name)
62153
public static void PlayNotificationSound()
63154
{
64155
// System default sound for the classic notification balloon.
65-
if (!PlaySystemSound("Explorer", "SystemNotification"))
156+
if (PlaySystemSound("Explorer", "SystemNotification")) return;
157+
if (EnvironmentHelper.IsWindows8OrBetter)
66158
{
67-
if (EnvironmentHelper.IsWindows8OrBetter)
68-
{
69-
// Toast notification sound.
70-
if (!PlaySystemSound(".Default", "Notification.Default"))
71-
PlayXPNotificationSound();
72-
}
73-
else
74-
{
159+
// Toast notification sound.
160+
if (!PlaySystemSound("Notification.Default"))
75161
PlayXPNotificationSound();
76-
}
162+
}
163+
else
164+
{
165+
PlayXPNotificationSound();
77166
}
78167
}
79168

80-
public static bool PlayXPNotificationSound()
169+
public static void PlayXPNotificationSound()
81170
{
82-
return PlaySystemSound(".Default", "SystemNotification");
171+
PlaySystemSound("SystemNotification");
83172
}
84173
}
85174
}

src/ManagedShell.Common/ManagedShell.Common.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<TargetFrameworks>netcoreapp3.1;net471;net6.0-windows</TargetFrameworks>
55
<UseWindowsForms>true</UseWindowsForms>
66
<UseWPF>true</UseWPF>
7+
<LangVersion>12</LangVersion>
78
</PropertyGroup>
89

910
<ItemGroup>

0 commit comments

Comments
 (0)