Windows plays sounds if you click somewhere, or if an error occurs. If you logoff, Windows plays a logoff sound. Did you ever want to use something similar in your application, e.g. if you'd like to play a certain sound if your application does something special?
The .NET framework support no sounds at this time, so we have to use the API method
PlaySound located in the winmm.dll. We have to include this method into our C# Project like this.
private static extern int PlaySound(String pszSound, int hmod, int falgs);
First problem fixed...
The sound events are stored in the registry, this is done by user. So the settings can be found under
HKEY_CURRENT_USER. Windows supports Sections, this means every application can create/use it's own section. We're able to add a new Section for our application. But Windows knows also the Sound Schemes, which can be chosen and altered by the user. Because of this it's not very easy to read the sound events in registry, but it's possible.
Every sound event is based on :
- .default Wave file defined by the vendor of the application.
- .current Wave file currently used for this sound event.
HKEY_CURRENT_USER\AppEvents\EventLabels\<EVENTNAME> Description used to display sound event.
With this knowledge, we can rebuild the control panel view of the system sounds. We're also able to add our own sound events to registry. All we have to do is create some registry keys at the right position.
How to play sound events
PlaySound method supports the playing of normal wave files stored on the disk. But it also supports playing sound events from registry. The registry key, which defines the sound event, is the verb we need to send to
PlaySound method. Otherwise we have to send the file path to the method. There are different parameter flags used, defined in a C#
public enum SND
SND_SYNC = 0x0000 ,
SND_ASYNC = 0x0001 ,
SND_NODEFAULT = 0x0002 ,
SND_MEMORY = 0x0004 ,
SND_LOOP = 0x0008 ,
SND_NOSTOP = 0x0010 ,
SND_NOWAIT = 0x00002000,
SND_ALIAS = 0x00010000 ,
SND_ALIAS_ID = 0x00110000,
SND_FILENAME = 0x00020000,
SND_RESOURCE = 0x00040004,
SND_PURGE = 0x0040,
SND_APPLICATION = 0x0080
Playing a wave file located on the disk looks like this,
pszSound is the file path.
public static void PlaySound(String pszSound)
(int) (SND.SND_ASYNC | SND.SND_FILENAME | SND.SND_NOWAIT));
Otherwise, if we play a sound event, it looks like this,
pszSound is the event verb.
public static void PlaySoundEvent(String pszSound)
(int) (SND.SND_ASYNC | SND.SND_ALIAS | SND.SND_NOWAIT));
How to display sound events
The next step is to fill a
TreeView control like the one filled in the control panel. We have to read all the application sections, in the default scheme. After that, we could load sound events for each section. If you click a
TreeNode, we play the sound defined by this sound event, sounds nice?
First we need to open the
\Apps key located under
HKEY_CURRENT_USER. After that, we could read all subkeys into a string array.
RegistryKey rkey = Registry.CurrentUser;
string sections = rkey1.GetSubKeyNames();
Now we've got the names of the application sections, next we read the display string for each section stored in the default value of the key.
@"AppEvents\Schemes\Apps\" + sections[i]);
string sectionName = rkey1.GetValue("").ToString();
Now we read the subkeys of the section key, these are the sound event verbs.
string subsections = rkey1.GetSubKeyNames();
@"AppEvents\EventLabels\" + subsections[j]);
string eventName = rkey1.GetValue("").ToString();
Finish our work and close all resources allocated.
If you like, you could fill this information into a
TreeView, like I did it in my demo application. If you click on a
TreeNode, you can play the sound event.
Have phun with it.