I just ran into this fairly old post on Channel 9. mstefan reported that his applications played a “Ding” noise when selecting an item in a listview (or tree) control.
It turns out that I’d had the problem independently reported to me by one of the people here at Microsoft. Here were his reproduction steps:
- Clean Install Windows
- Open the sounds control panel
- Set the “Select” sound to a value
- Clear the “Select” sound (set it to “(None)”).
- Change the selection in a listview
Complicating matters is that this didn’t occur with many apps, just a couple of Windows Forms applications that the person at Microsoft had. So I dug into it a bit.
I quickly realized that the problem was that the application was calling PlaySound without the “SND_NODEFAULT” flag. I’ve written about this flag before (in fact I wrote that post shortly after investigating this issue, so that post contains part of the story).
Digging in deeper, I realized that the application was using version 5 of the common controls (there are two versions in Windows, v5 and v6). The problem didn’t occur in the version 6 common controls (this is why most applications didn’t reproduce the problem).
So why did the problem occur?
The common controls have a single routine which calls PlaySound and that code attempts to be somewhat clever. Instead of simply calling PlaySound, the code instead read the HKEY_CURRENT_USER\AppEvents\Schemes\.Default\CCSelect registry key. If the key didn’t exist, it skipped calling PlaySound. If the CCSelect registry key existed, it would call PlaySound specifying the CCSelect alias.
I’ve actually run into this pattern a bunch in WIndows – teams decided that calling PlaySound was “too slow”, or had “too much overhead” so they tried to avoid the call to PlaySound if the call to PlaySound wasn’t going to do anything (once upon a time it was important to avoid calling PlaySound because it could sometimes hang your application for several seconds – this isn’t the case any more if you specify SND_ASYNC).
The problem is that when you hit step 2 above (setting the “Select” sound), the control panel created the CCSelect registry key with a default value of the sound file you’re setting. When you set it to “None” the control panel cleared the value of the sound contained under the key. But the key itself wasn’t deleted. So the check above that checked for the registry key’s existence succeeded and it called PlaySound. But because the call didn’t specify SND_NODEFAULT, the PlaySound API decided to play the default sound when it realized that there wasn’t a sound associated with the CCSelect alias.
I wanted to understand how this bug was introduced so I looked back at the source history of the file containing the bug. It turns out that this was actually a bug fix made to Windows XP that wasn’t incorporated into Windows Server 2003. When Windows Vista was created, the team started with the Windows Server 2003 code base and incorporated all the bug fixes made since Windows XP forked into the Win2K3 code base. For whatever reason, this particular fix was missed when the team did the merge. Because the behavior was so subtle (to trigger the change you MUST go through steps 2 through 4 to get the registry key created and your app must use the v5 of the common controls).
Needless to say, it’s fixed in WIndows 7.