Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Play Windows sound events defined in system Control Panel

0.00/5 (No votes)
11 Aug 2002 1  
Play system sounds defined in Control Panel and other wave files.

Sample Image - windowssoundevents.jpg

Introduction

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.

[DllImport("winmm.dll", EntryPoint="PlaySound",CharSet=CharSet.Auto)]
private static extern int PlaySound(String pszSound, int hmod, int falgs);

First problem fixed...

Sound events

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

The 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# Enum.

public enum SND
{
    SND_SYNC         = 0x0000  ,/* play synchronously (default) */
    SND_ASYNC        = 0x0001 , /* play asynchronously */
    SND_NODEFAULT    = 0x0002 , /* silence (!default) if sound not found */
    SND_MEMORY       = 0x0004 , /* pszSound points to a memory file */
    SND_LOOP         = 0x0008 , /* loop the sound until next sndPlaySound */
    SND_NOSTOP       = 0x0010 , /* don't stop any currently playing sound */
    SND_NOWAIT       = 0x00002000, /* don't wait if the driver is busy */
    SND_ALIAS        = 0x00010000 ,/* name is a registry alias */
    SND_ALIAS_ID     = 0x00110000, /* alias is a pre d ID */
    SND_FILENAME     = 0x00020000, /* name is file name */
    SND_RESOURCE     = 0x00040004, /* name is resource name or atom */
    SND_PURGE        = 0x0040,  /* purge non-static events for task */
    SND_APPLICATION  = 0x0080 /* look for application specific association */
}

Playing a wave file located on the disk looks like this, pszSound is the file path.

public static void PlaySound(String pszSound)
{
    if(File.Exists(pszSound))
    {
        PlaySound(pszSound,0,
          (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)
{
    PlaySound(pszSound,0,
      (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 AppEvents\Schemes\Apps key located under HKEY_CURRENT_USER. After that, we could read all subkeys into a string array.

RegistryKey rkey = Registry.CurrentUser;
RegistryKey rkey1=rkey.OpenSubKey("AppEvents\Schemes\Apps");
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.

// open reg key

for(int i=0;i<sections.Length;i++)
{
    // read section name

    rkey1=rkey.OpenSubKey(
        @"AppEvents\Schemes\Apps\" + sections[i]);
    // read section name

    try 
    {
        string sectionName = rkey1.GetValue("").ToString();
    } 
    catch {}
}

Now we read the subkeys of the section key, these are the sound event verbs.

// read subkeys

string[] subsections = rkey1.GetSubKeyNames();
for(int j=0;j<subsections.Length;j++)
{
    rkey1=rkey.OpenSubKey(
        @"AppEvents\EventLabels\" + subsections[j]);
    try 
    {
        string eventName = rkey1.GetValue("").ToString();
    } 
    catch {}
}

Finish our work and close all resources allocated.

rkey1.Close();
rkey.Close();

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here