A peek behind the beep

Or rather, a peek behind system sounds.

Windows 3.1 (I think - it might have been Win95) introduced the concept of "application events" to Windows (I prefer to call them system sounds).

But how do these events actually work? It turns out that documentation of how the schema for windows sounds work is relatively hard to find, but it's not very complicated.  This topic in MSDN covers defining application events (I call them system sounds), but it really doesn't describe the schema used to extend them.  This topic also talks about how to register events for your application.  But I'm not aware of any comprehensive description of what it takes to add a sound alias to Windows.

There are 5 steps needed to define a new system sound.  You need to:

  1. Tell Windows about your application.
  2. Tell Windows about the application event (alias) for the sound.
  3. Author the .WAV file for your sound.
  4. Associate your WAV file with your application event
  5. Write your app to call PlaySound

 

I'm not going to go into the authoring thingy, I have no idea how one would go about doing that :).  But I do know how to tell Windows about steps 1, 2, and 4.

To let Windows know about the sound, you need to do two things.  The first is that you need to be sure that PlaySound can figure out what file is associated with the sound, the second is that you need to be able to tell the control panel the "name" of your sound. 

In order to tell PlaySound and the control panel applet about your event, you need to define an "alias" for that event.  Once you've done that, simply insert a call to PlaySound specifying the SND_ALIAS flag, and you're done programming the event (that's #4).  But you still have to plumb in the support to map between the alias and the .WAV file that holds the sound, and that means going to the registry.

 

System sounds live under the "AppEvents\Apps" registry key under HKEY_CURRENT_USER.  From there, you can define the names of your sound aliases, set their display name, and otherwise control how the system manages your sounds.

The Apps key has a pretty straightforward layout:  There are a number of keys under the Apps key, one for each application that's registered to play sounds.

        HKEY_CURRENT_USER\
            AppEvents\
                Schemes\
                    Apps\
                        .Default\
                        MSNMSGR\

The ".Default" key is reserved for use by Windows, nobody should ever add an alias to that section.  Instead, you should create a new key under "Apps" with the filename (no extension) of your executable.  So if Outlook wants to add its own sounds, it should create a key named "Outlook".  The default value for the applications key is the name that the sounds control panel applet will use for the applications section. 

        HKEY_CURRENT_USER\
            AppEvents\
                Schemes\
                    Apps\
                        .Default\
                        MSNMSGR\
                        <APPNAME>\ <default Value "Your app name">

There's a significant drawback to doing this though - you can't support MUI builds (multiple languages on the same machine).  To enable MUI support, you should also create a value with the name DispFileName.  DispFileName should be a REG_SZ formatted as a shell indirect string.  mmsys.cpl will use SHLoadIndirectString to retrieve the actual value in a MUI safe form.  For Vista and beyond, there's a new registry API RegLoadMUIString that lets you do this directly from the registry.  You will also want to specify the SND_APPLICATION flag to PlaySound to tell it to look somewhere other than .Default.  When you specify SND_APPLICATION, PlaySound looks up the currently running executable name and uses that (minus path and extension) for the <appname>

        HKEY_CURRENT_USER\
            AppEvents\
                Schemes\
                    Apps\
                        .Default\
                        MSNMSGR\
                        <APPNAME>\ <default Value "Your app name">
                            VALUE: DispFileName, REG_SZ <value <shell path for your app name>>

Phew, we're almost done.  All we need to do now is to add a the actual sounds.  Under the app specific key, add a new key for each of your sounds - the name of the key matches the name of your alias.  Under the key with the alias, create yet another key named ".Current", the value of that should be either a REG_SZ or a REG_EXPAND_SZ that contains the path of your sound.

        HKEY_CURRENT_USER\
            AppEvents\
                Schemes\
                    Apps\
                        .Default\
                        MSNMSGR\
                        <APPNAME>\ <default Value "Your app name">
                            <Alias Name>\ <default Value: The display name for your alias>
                                .Current <default Value "Path to your .WAV file">

The sounds control panel applet will use the display name specified for your alias.

That's about it - it's a smidge more complicated than the MSDN documentation makes it out to be, but...  Enjoy!

 

 

Btw, if you look at a current XP or Vista machine, you'll find two registry keys under AppEvents, "EventLabels" and "Schemes".  The "EventLabels" key is an alternate mechanism to defines the mapping between the event alias and the display name used for your sound in the control panel.

        HKEY_CURRENT_USER\
            AppEvents\
                EventLabels\
                Schemes

Event Labels define the display name of the event.  It provides a flat list that maps between event aliases and their display names (similar to using the default value for the event listed above).  To add a new display name for a given alias, simply create a key with the name of your alias, and set the default value to the display name for the event.  Once again, for MUI builds, you can use the DispFileName trick to specify a resource that will be used for the name.

        HKEY_CURRENT_USER\
            AppEvents\
                EventLabels\
                    CriticalBatteryAlarm <default value "Critical Battery Alarm">
                        VALUE: DispFileName, REG_SZ <value "@mmsys.cpl,-5827">
                Schemes

Comments

  • Anonymous
    January 24, 2006
    Should that MSNMSGR key be in there? That would just be sounds for messenger wouldn't it?
  • Anonymous
    January 24, 2006
    Actually that was intentional to show an example of an app registration (MSN Messenger).
  • Anonymous
    January 24, 2006
    So is the only difference between the EventLabels mapping and assigning a default value to the alias key the fact that EventLabels handles the DispFileName stuff?

    Why make a whole new key to handle that when you could have just as easily added the value to the alias key? Not to mention making it a flat list, meaning you've got to make sure your alias names are unique... just seems like an odd design to me.
  • Anonymous
    January 24, 2006
    Larry,
    It would be good if you guys (i.e. MS) could prepare a reg file that would automatically insert comments into various registry keys, where the comments provide URLs to MSDN/KB articles, for that developers/power users who trawl through the registry (like me!).

    Raymond Chen also blogs a lot about users digging into the registry to read/change settings (instead of using the appropriate APIs): in these cases the comment could be on the lines of "Touch me not", and a URL to the appropriate API to use.

    ~Phylyp
  • Anonymous
    January 24, 2006
    Larry,
    It would be good if you guys (i.e. MSFT) could provide one (or more) .REG files that will insert comments into various registry keys. The comments will have URLs to the appropriate MSDN/KB articles for the keys/values.

    IMHO, this would be of use to developers/power users (like me!) who trawl through the registry (in express violation of Raymond Chen's advice). Cases when there exists an appropriate API to modify the values could be indicated, with the URL to that API's MSDN documentation.

    Do you think this encourage devs to use the registry in the right way, or will it merely provide a small safety-net against weird manipulations?

    ~Phylyp
  • Anonymous
    January 25, 2006
    Dean, yup. In Vista, we're planning on adding the DispFileName to the events and deprecating the event labels entirely (it's only needed for MUI).

    Phylyp, this is why I'm documenting this here (and will be talking to the MSDN people about documenting it better). Adding an API to manage this is installer-unfriendly, so we need to make the registry stuff clear.
  • Anonymous
    January 25, 2006
    It seems unfortunate that these are keyed by executable name. That makes collisions pretty likely.
  • Anonymous
    January 25, 2006
    Adrian,
    That's only a problem if it's a DLL trying to play the sound, it's not if it's an executable. And for the vast majority of cases for Windows, it's the executable that's playing the sound.

    I don't know about you, but I don't have that many collisions in executable names on my machine.
  • Anonymous
    January 25, 2006
    Ah, so that's why the apps are all exe names: to enable PlaySound to look up the events itself. I've always used GUIDs to identify my individual apps, and manually look up the file names to play myself.
  • Anonymous
    March 05, 2006
    I wanted to register a application event in my registry this weekend and I was wondered. The default value of the .current key has a REG_EXPAND_SZ type on all my systems. If I change a wav file association with the control panel applet the type of the default value was changed to REG_SZ. After that it was impossible for me to play this system sound via PlaySound. I tried this on my Windows XP SP2 32Bit and 64Bit Edition. It's very mystic.