Today, I just might ruffle a few feathers by doing so, but I figured I’d go through and demonstrate the process of reversing some incompletely documented stuff in Windows in order to fix a problem that was causing me some personal pain.

Specifically, I’m going to talk about sound schemes in Windows 7. With Windows Vista, we had only 1 sound scheme (unless you bought Ultimate, in which case the additional sound schemes were provided as Ultimate Extras). With Windows 7, you get multiple sound schemes.

And for a while, I was terrified of using any of them other than the one I had originally selected.

You see, every time I would change the sound scheme, I would lose sounds in a number of my other programs. Pretty much anything that wasn’t Windows. I like my computer making little beeps and boops all the time (seriously – I still add in the Office 97 sounds, because I like the audio feedback I get when deleting, moving copying – it feels bizarre not to have it after more than a decade of always hearing it).

When we released a whole bunch of new themes for Windows 7 on the day we reached General Availability, I had reached the last straw. The themes all changed my sound scheme, and I don’t want to lose the sound from my other programs thank you very much. So, I set out to figure out how to fix that.

Here’s a blog post that described how to set up the sounds:

A Peek Behind the Beep

Put sounds in .current, eh? Well, time to go spelunking. For the sounds that do switch around, I notice more in the registry than just .Current. I notice that each event not only has a .current subkey, it also has a subkey with the name of each of the sound schemes. So, it seems likely that everyone who adds a new set of application sounds would only affect the current sound scheme, and as soon as you changed it, those settings would go away!

A quick check with process monitor would confirm that:

8:08:59.2736148 PM    rundll32.exe    4796    RegOpenKey    HKCU\AppEvents\Schemes\Apps\Communicator\COMMUNICATOR_appinvite\Delta    SUCCESS    Desired Access: Maximum Allowed, Granted Access: All Access
8:08:59.2736558 PM    rundll32.exe    4796    RegQueryValue    HKCU\AppEvents\Schemes\Apps\Communicator\COMMUNICATOR_appinvite\Delta\(Default)    BUFFER OVERFLOW    Length: 144
8:08:59.2737043 PM    rundll32.exe    4796    RegQueryValue    HKCU\AppEvents\Schemes\Apps\Communicator\COMMUNICATOR_appinvite\Delta\(Default)    SUCCESS    Type: REG_SZ, Length: 172, Data: C:\Program Files (x86)\Microsoft Office Communicator\Media\COMMUNICATOR_appinvite.wav
8:08:59.2741839 PM    rundll32.exe    4796    RegCloseKey    HKCU\AppEvents\Schemes\Apps\Communicator\COMMUNICATOR_appinvite\Delta    SUCCESS   
8:09:00.4227580 PM    rundll32.exe    4796    RegOpenKey    HKCU\AppEvents\Schemes\Apps\Communicator\COMMUNICATOR_appinvite    SUCCESS    Desired Access: Maximum Allowed, Granted Access: All Access
8:09:00.4227946 PM    rundll32.exe    4796    RegQueryKey    HKCU\AppEvents\Schemes\Apps\Communicator\COMMUNICATOR_appinvite    SUCCESS    Query: HandleTags, HandleTags: 0x0
8:09:00.4228254 PM    rundll32.exe    4796    RegCreateKey    HKCU\AppEvents\Schemes\Apps\Communicator\COMMUNICATOR_appinvite\Delta    SUCCESS    Desired Access: Set Value
8:09:00.4228632 PM    rundll32.exe    4796    RegSetValue    HKCU\AppEvents\Schemes\Apps\Communicator\COMMUNICATOR_appinvite\Delta\(Default)    SUCCESS    Type: REG_SZ, Length: 172, Data: C:\Program Files (x86)\Microsoft Office Communicator\Media\COMMUNICATOR_appinvite.wav
8:09:00.4229075 PM    rundll32.exe    4796    RegCloseKey    HKCU\AppEvents\Schemes\Apps\Communicator\COMMUNICATOR_appinvite\Delta    SUCCESS   
8:09:00.4229383 PM    rundll32.exe    4796    RegQueryKey    HKCU\AppEvents\Schemes\Apps\Communicator\COMMUNICATOR_appinvite    SUCCESS    Query: HandleTags, HandleTags: 0x0
8:09:00.4229707 PM    rundll32.exe    4796    RegCreateKey    HKCU\AppEvents\Schemes\Apps\Communicator\COMMUNICATOR_appinvite\.current    SUCCESS    Desired Access: Set Value
8:09:00.4230081 PM    rundll32.exe    4796    RegSetValue    HKCU\AppEvents\Schemes\Apps\Communicator\COMMUNICATOR_appinvite\.Current\(Default)    SUCCESS    Type: REG_SZ, Length: 172, Data: C:\Program Files (x86)\Microsoft Office Communicator\Media\COMMUNICATOR_appinvite.wav
8:09:00.4230401 PM    rundll32.exe    4796    RegCloseKey    HKCU\AppEvents\Schemes\Apps\Communicator\COMMUNICATOR_appinvite\.Current    SUCCESS   

Yes, indeed – when you change the sound scheme, you copy the values over from the subkey with the new scheme name into the .current key. And none of the program sounds from external programs contained subkeys for each (or any) of the schemes!

So, I’m thinking I’ve reversed the secret to carrying my program sounds over from scheme to scheme – could it be that simple? Only one way to find out – populate them! But, if there were so few that I could do so easily by hand, then I wouldn’t be reversing this stuff in the first place. So, it looks like it’s time for a PowerShell Script! Here’s what I wrote:

foreach ($app in Get-ChildItem -Path "HKCU:\AppEvents\Schemes\Apps")
{
    if (($app.PSChildName -ne ".Default") -and ($app.PSChildName -ne "Explorer") -and ($app.PSChildName -ne "sapisvr"))
    {
        foreach ($events in Get-ChildItem -Path $app.PSPath)
        {
            $event = $events.PSPath
            foreach ($soundSchemes in Get-ChildItem -Path "HKCU:\AppEvents\Schemes\Names")
            {
                $soundScheme = $soundSchemes.PSChildName
                if (($soundScheme -ne ".Default") -and ($soundScheme -ne ".None"))
                {
                    $defaultPath = $event + "\.current"
                    $newPath = $event + "\" + $soundScheme
                    if (Test-Path $newPath)
                    {
                        Remove-Item -Path $newPath
                    }
                    Copy-Item -Path $defaultPath -Destination $newPath  
                }
            }
        }
    }
}

I ran this script, and tried changing my sound scheme. Sure enough, it worked! I was able to swap out my sound schemes, and the other applications which extend the sound scheme mechanism in Windows still generate the sounds which makes their use so much more satisfying! (Or, in the case of Communicator, it’s downright critical to the way I use the application.) Hooray!

Now, this is kind of a klugy workaround, which depends on my reversing and guessing correctly on a couple of things. What could we do differently? Well, ideally the application developer would have enumerated the schemes, which is something they wouldn’t have had to do with Windows Vista (except in the case of Ultimate Extras), and added their sound events to each of the schemes. But, it’s a little bit late for that now – these apps already exist. The sound schemes already exit, and there is no API we can intercept – the apps are just writing to the registry. So, if we wanted to do something about this within Windows, we’d have to do something proactive to mitigate the issue with other programs in response to a sound scheme change event. That’s getting a little bit harder to argue for in a service pack, but you never know. It’s worth a try at least.

For now, you can use my workaround, and carry your sounds around with you from scheme to scheme. Happy dinging!