Where Did That Sound Come From?
- Posted: Oct 31, 2006 at 1:06 PM
- 1,115 Views
- 7 Comments
Loading User Information from Channel 9
Something went wrong getting user information from Channel 9
Loading User Information from MSDN
Something went wrong getting user information from MSDN
Loading Visual Studio Achievements
Something went wrong getting the Visual Studio Achievements
| This April Fools' Day article walks you through how you can programmatically change the Windows system sound events to mess with a co-worker or family member. Like many other pranks, this one requires you to have physical access to your victim's computer at a time when they're not around. | |
|
Difficulty: Easy
Time Required:
Less than 1 hour
Cost: Free
Hardware:
Download:
|
|
Video Demo
This April Fools' Day article walks you through how you can programmatically change the Windows system sound events to mess with a co-worker or family member. Like many other pranks, this one requires you to have physical access to your victim's computer at a time when they're not around. As a best practice, I recommend that you back up your registry before running any code to manipulate registry settings, especially if you've never programmed the registry before.
Microsoft Windows enables users to set sounds for system events, such as when Windows starts up, when a device is connected, when an error occurs, when a window is maximized, and more. What this article walks through is adding humorous or annoying system sounds for your victim for *every* Windows system sound. As with all pranks, you should find a way to personalize the sounds for your victim. Here are some ideas:
If you're not sure where to find wave audio clips, you can find a good set of sound clips on sites like http://www.reelwavs.com/and http://www.funwavs.com/ among others. Below I'll show you two different ways to change system sounds, from requiring no code at all, to building a utility created with Express, to automate changing the system sounds.
With your victim's machine unlocked, you can change their system sounds simply by opening the Control Panel and selecting "Sounds." This will display the image below, which you can scroll through. Click "Browse" to assign a sound file to each system event. Then watch as just about every possible event triggers that sound file.
Using Visual Basic or Visual C# Express, you can take this a step further and create a utility that can automatically change all of the system sound files, back up and restore sounds settings, and test sounds.
The first thing we want to do is find out where the system sound files are stored. Since most Windows settings are stored in the registry, that seems like a logical place to start looking. To look inside the registry, click Start > Run, then type "regedit" to open the Registry Editor. You can search the registry by clicking "Edit > Find," and since I know that the Windows Startup sound contains startup.wav, I simply search the registry for that sound. What you'll find is the registry hive that represents the system sounds, as shown below:
The way this works is that each folder under Schemes/Apps/.Default represents an event you can map sounds to. For example, if you've ever unplugged a USB device, you know that there is a system sound associated with that event, the DeviceDisconnect event. Underneath a specific event, like the DeviceDisconnect event, there will be a list of folders: .current, .Default, and one folder for any sound schemes they may have saved.
As you can see in the picture above, a specific system event has the following structure:
Now that I know where the registry keys are located and what I want to do, I'm going to create a DataSet that represents the Windows sound event and the path to the sound file to play when that event occurs. To do this, I'm going to start a new Windows Forms project and select "Add New Item..." from the Solution Explorer window, and then select the DataSet template. To represent a sound event as a DataSet, I'll add two text fields, "SoundName" and "SoundFile," as shown below:
Next, I'll add a class file, RegistryWrapper.cs, which will wrap all of my registry functions, including reading and writing data. We'll walk through the major tasks we want to achieve here including registry tasks like reading, writing, backing up, restoring, and even playing a sound event.
Reading Sound Events from the Registry
Since I know the exact location of the sound events in the registry, I'm going to declare two variables in the RegistryWrapper class to store the registry prefix and suffix, so I won't have to declare the full path *everywhere* in my application.
Visual Basic
'these represent the location in the registry with the user sounds
Private hivePrefix As String = "AppEvents\Schemes\Apps\.Default\"
Private hiveSuffix As String = "\.current"
Visual C#
//these represent the location in the registry with the user sounds
string hivePrefix = @"AppEvents\Schemes\Apps\.Default\";
string hiveSuffix = @"\.current";
Next, we'll add a method called GetSystemSound() that returns a RegSoundDataTable containing the SoundName and SoundFile values for the registry. The first thing we do is get the list of all the subkeys for the path we specified above by calling the GetSubKeyNames method. This will return a list of all of the sound events. Next, we loop through each sound event, creating a new row for the DataTable while setting the SoundName to the current sound event and the SoundFile to the registry key value that contains the location of the sound. Note that when we call the GetValue method to get the sound file, we need to pass in the name of the key, which in our case is blank so we pass in "". We'll also add a helper function that simply concatenates the two variables declared earlier.
Visual Basic
Public Function GetSystemSound() As RegSound.RegSoundDataTable
'Get the subkey key
Dim values() As String = Registry.CurrentUser.OpenSubKey(hivePrefix).GetSubKeyNames
Dim tb As RegSound.RegSoundDataTable = New RegSound.RegSoundDataTable
For Each s As String In values
'Loop through rows
Dim newRow As RegSound.RegSoundRow = tb.NewRegSoundRow
newRow.SoundName = s
newRow.SoundFile = _
CType(My.Computer.Registry.CurrentUser.OpenSubKey(getRegKeyPath(s)).GetValue(""), _
String)
tb.Rows.Add(newRow)
Next
Return tb
End Function
'adds the full registry key including prefix and suffix
Private Function getRegKeyPath(ByVal s As String) As String
Return (hivePrefix & s & hiveSuffix)
End Function
Visual C#
public RegSound.RegSoundDataTable GetSystemSound()
{
//Get the subkey key
string[] values = Registry.CurrentUser.OpenSubKey(hivePrefix).GetSubKeyNames();
RegSound.RegSoundDataTable tb = new RegSound.RegSoundDataTable();
foreach (string s in values)
{
//Loop through rows
RegSound.RegSoundRow newRow = tb.NewRegSoundRow();
newRow.SoundName = s;
newRow.SoundFile =
(string)Registry.CurrentUser.OpenSubKey(getRegKeyPath(s)).GetValue("") ;
tb.Rows.Add(newRow);
}
return tb;
}
//adds the full registry key including prefix and suffix
private string getRegKeyPath(string s)
{
return hivePrefix + s + hiveSuffix;
}
Writing Sound Events to the Registry
To set all of the sound events to a specific sound, we'll create another method that takes a RegSound DataTable and the sound file we'll use for the change. We loop through every row in the DataTable and set the registry key value for the sound by calling the SetValue method. To call the SetValue method, we need to know the key name (in our case its blank or ""), the value to set it to (in our case the sound file path), and the RegistryKind, which describes the type or kind of value being stored (in our case a string) in the registry.
Visual Basic
Public Sub SetSystemSound(ByVal sounds As RegSound.RegSoundDataTable,
ByVal soundPath As String)
'loop through all sounds
For Each row As RegSound.RegSoundRow In sounds
'Set key and value
Dim key As RegistryKey = _
My.Computer.Registry.CurrentUser.OpenSubKey(getRegKeyPath(row.SoundName), _
True)
key.SetValue("", soundPath, RegistryValueKind.String)
Next
End Sub
Visual C#
public void SetSystemSound(RegSound.RegSoundDataTable sounds,
string soundPath)
{
//loop through all sounds
foreach (RegSound.RegSoundRow row in sounds)
{
//Set key and value
RegistryKey key =
Registry.CurrentUser.OpenSubKey(getRegKeyPath(row.SoundName), true);
key.SetValue("", soundPath, RegistryValueKind.String);
}
}
Back Up Current Sound Settings
Since your victim may be upset you changed his or her sounds, we'll add a way to save their current sound settings to the local hard drive where you can restore them later. To do this, we'll add the SaveSystemSound method that takes the DataTable you want to save and the file location to save to. We can use the WriteXml method on the DataTable object to save the DataTable as an XML file.
Visual Basic
Public Sub SaveSystemSound(
ByVal sounds As RegSound.RegSoundDataTable,
ByVal savePath As String)
'Save Sound DataSet
sounds.WriteXml(savePath)
End Sub
Visual C#
public void SaveSystemSound(
RegSound.RegSoundDataTable sounds, string savePath)
{
//Save Sound DataSet
sounds.WriteXml(savePath);
}
Restoring Saved Sound Settings
Now let's add a method to restore the sound settings from the previous step. In this case, we just need to know where the location of the saved DataTable is and call the
ReadXml method to read the data we stored previously. Once we have the data we can loop through each sound event and call the
setValue method to replace the current sound.
Visual Basic
Public Sub RestoreSystemSound(ByVal savePath As String)
'Restore Sound DataSet
Dim sounds As RegSound.RegSoundDataTable = _
New RegSound.RegSoundDataTable
sounds.ReadXml(savePath)
For Each row As RegSound.RegSoundRow In sounds
'Set Key
Dim key As RegistryKey = _
My.Computer.Registry.CurrentUser.OpenSubKey( _
getRegKeyPath(row.SoundName), True)
key.SetValue("", row.SoundFile, RegistryValueKind.String)
Next
End Sub
Visual C#
public void RestoreSystemSound(string savePath)
{
//Restore Sound DataSet
RegSound.RegSoundDataTable sounds =
new RegSound.RegSoundDataTable();
sounds.ReadXml(savePath);
foreach (RegSound.RegSoundRow row in sounds)
{
//Set Key
RegistryKey key =
Registry.CurrentUser.OpenSubKey(
getRegKeyPath(row.SoundName), true);
key.SetValue("", row.SoundFile, RegistryValueKind.String);
}
}
Playing a Registry Sound Event
Finally, we'll add a way to play a registry sound. Since some sound files assume a path to the media folder under System root, we need to add a quick check to see if the file has any backslashes ("\"), which we'll use as a test to see if the sound file contains both a path and sound file. If it doesn't, we'll append the path to the sound file and play it.
Visual Basic
Public Sub PlayRegistrySound(ByVal soundFile As String)
'play sound if there is an associated file
If (soundFile <> "") Then
'add default path if there isn't one
Dim a As Integer = soundFile.IndexOf(Microsoft.VisualBasic.ChrW(92))
If (a <> 0) Then
Else
soundFile = "%SystemRoot%\\media\\" + soundFile
End If
My.Computer.Audio.Play(soundFile)
End If
End Sub
Visual C#
public void PlayRegistrySound(string soundFile)
{
//play sound if there is an associated file
if (soundFile != "")
{
SoundPlayer sp = new SoundPlayer();
//add default path if there isn't one
int a = soundFile.IndexOf('\\');
if (a != 0)
{
soundFile = "%SystemRoot%\\media\\" + soundFile;
}
sp.SoundLocation = soundFile;
sp.Play();
}
}
Creating the User Interface
To create the user interface, we'll begin by adding some controls to our form including:
After adding in some nice IconBuffet icons that you get for registering Express, your UI should look something like this:
Loading Data
Finally, we're going to put it all together by adding a couple of functions to the Windows Form. The first thing we'll want to do is add two form variables, one to represent the RegistryWrapper we wrote before and another to store the RegSoundDataTable data. To populate the DataTable, well call the GetRegistrySounds method, which in turn calls the GetSystemSound method we created earlier. We'll call the GetRegistrySounds method when the form loads, when we restore the sounds, or when we apply changes so that the DataGridView will display the current registry sounds.
Visual Basic
Private Sub frmMainForm_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
GetRegistrySounds()
End Sub
Private Sub GetRegistrySounds()
'Call the RegistryWrapper Class
sounds = myReg.GetSystemSound
RegSoundDataGridView.DataSource = sounds
End Sub
Visual C#
private void frmMainMenu_Load(object sender, EventArgs e)
{
GetRegistrySounds();
}
private void GetRegistrySounds()
{
//Call the RegistryWrapper Class
sounds = myReg.GetSystemSound();
regSoundDataGridView.DataSource = sounds;
}
Formatting the DataGridView
To add a nice UI, we'll format the DataGridView control by changing some of the properties, like setting the AlternatingRowsDefaultCellStyle property to a different color, changing the DefaultCellStyle font to Arial 10, and turning off adding, editing, and deleting.
We'll also add an image column with a "play" image so that we can here the currently associated sound. To do this, you can right-click on the DataGridView and select "Edit Columns" to bring up the Edit Column dialog box as shown below. Here we'll add a new column called "Play," set the column type to DataGridViewImageColumn, set the Image property to our sound image, and set the ImageLayout property to "Zoom" so that the image will fit the cell contents.
Finally, we'll want to add code to play a sound when someone clicks the sound image, and we can do this by adding the following code to the DataGridView CellContentClick event. As you can see below, we only play a sound if they clicked the third column (index start at 0 so the third is #2). To play a sound, we'll need the sound path, that we get by creating a DataGridViewTextBoxCell for the SoundFile column and reading its value.
Visual Basic
Private Sub RegSoundDataGridView_CellContentClick( _
ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _
Handles RegSoundDataGridView.CellContentClick
'Represents col #3 the "Play" column
If (e.ColumnIndex = 2) Then
Dim cell As DataGridViewTextBoxCell = _
CType(RegSoundDataGridView.Rows(e.RowIndex).Cells((e.ColumnIndex - 1)), _
DataGridViewTextBoxCell)
'Play Sound
myReg.PlayRegistrySound(cell.Value.ToString)
End If
End Sub
Visual C#
private void regSoundDataGridView_CellContentClick(
object sender, DataGridViewCellEventArgs e)
{
//Represents col #3 the "Play" column
if (e.ColumnIndex == 2)
{
DataGridViewTextBoxCell cell = (DataGridViewTextBoxCell)
regSoundDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex - 1];
//Play Sound
myReg.PlayRegistrySound(cell.Value.ToString());
}
}
Reading and writing data out of the registry is pretty easy, as is saving structured data like a DataSet. It's almost too easy to find the right sound file on the Internet and of course make hilarity ensue when your poor unsuspecting victim tries to figure out what's wrong with their PC. If you want to extend this application, a couple of additions would be to add the ability to change sounds beyond the system sound, like logon sounds for MSN Messenger, blocked pop-ups by Internet Explorer, and a host of other sound files you can map your PC.
Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation,
please create a new thread in our Forums,
or
Contact Us and let us know.
Follow the Discussion
Oops, something didn't work.
What does this mean?
Following an item on Channel 9 allows you to watch for new content and comments that you are interested in. You need to be signed in to Channel 9 to use this feature.What does this mean?
Following an item on Channel 9 allows you to watch for new content and comments that you are interested in and view them all on your notifications page.sign up for email notifications?
Hello i am nikhil,i liked the tutorial abt chaning sound scheme in windows by u.
I want to ask if i can add a new event for example..when i click on my computer -- a sound comes up like -- my computer opening ....i want sounds to be applicatio specific...can u help me in doing tat please thank u ...my email id ::
nikhil_20036@yahoo.com
Helo,
thanx for the tip...
can i know if i can add my own customized sounds..like when windows start copying file frm net or frm one location to other ...i wanna play some sound..
can i do that ???
Do you know if there is any way to add an event? I have a friend who would like Word to say, "That's brilliant," whenever she saves a document. (She's very modest.) But Save does not seem to be a recognized event.
Just wondering if there is any way to configure Windows to play event sounds using a URL instead of a filename and path. I run a sound clip database, and would like to be able to extend this functionality to my users, so that they can assign clips from my site to event sounds automatically, without having to first download the files to their local system. Is there any way that something like this could be done?
-Bill Auclair
bauclair@auclaironline.com
@Bill Auclair you could do something like this
System.Media.SoundPlayer sp = new SoundPlayer();
sp.Stream(// stream to the website ...
Hey,
I would also like to know how to Add custom events like the above people. Adding sounds while files are being copied and other things. I would also like to know how to add sound gor Dialogue Boxes that pop up like Confirm Delete File, or for Confirm Replace files Etc. Thanks and hope to hear from you soon.
goodraju@gmail.com
@goodraju hooking into more global events will allow you to do just that. And most of that is configurable via the control panel built into Windows.
Remove this comment
Remove this thread
close