Hey, Scripting Guy! Question

Hey, Scripting Guy! Is there an easy way to randomize the selection of .wav files at the startup and shutdown of windows?

-- DW

SpacerHey, Scripting Guy! AnswerScript Center

Hey, DW. Last night as the Scripting Guy who writes this column was on his way home he stopped at a red light. (Which is yet another thing that separates him from most Seattle-area suburbanites: very few of them bother to stop at red lights these days.) As he sat there waiting for the light to turn green, he glanced around and noticed a reader board posted in front of a local restaurant:

CHICKEN FRIED STEAK
HERB CRUSTED TROUT
PARMESAN CARMEL LATTE

Admittedly, the CHICKEN FRIED STEAK sounded awfully tempting. The HERB CRUSTED TROUT? Well, the Scripting Guy who writes this column doesn’t like seafood; in fact, he refuses to eat anything that swims. Still, he could see how seafood lovers might be attracted to HERB CRUSTED TROUT.

That just left one of the day’s specials: PARMESAN CARMEL LATTE. Notice anything weird about that? That’s absolutely right; carmel should actually be spelled “caramel!”

Oh. And then there’s that whole Parmesan cheese thing.

Admittedly, the Scripting Guy who writes this column has never tried a PARMESAN CARMEL LATTE; for that matter, he’s pretty sure he’s never tried any kind of cheese-flavored latte. And he’s well aware that people have no problem drinking odd-flavored lattes; root beer and grape are two of the more unusual ones that the Scripting Guy who writes this column is personally aware of.

Note. This has nothing to do with anything, but did you know that they now make coffee-flavored vodka? It’s true: Double Espresso Double Caffeine Vodka. One shot of this stuff supposedly has as much caffeine as three shots of espresso, and is designed to give people that “extra kick they need to keep going in the evening.” (It’s no fun when people conk out before they’ve had a chance to order a few more vodkas.) And have we mentioned Dr. Brown’s Cel-Ray Soda, which (we assume) is the world’s only soda pop made from (and tasting of) celery? Well, now we have.

And people think the Scripting Guys have too much time on their hands.

Anyway, where were we? Oh, right: the PARMESAN CARMEL LATTE. Like we said, we haven’t actually tried this, and until you try something you have no right to pass judgment on it.

Except, of course, in this case. A Parmesan-flavored latte? Thanks, but no thanks.

What’s that? OK, sure, it’s possible that the restaurant simply made a mistake. For example, maybe the reader board was supposed to look like this instead:

CHICKEN FRIED STEAK
PARMESAN HERB CRUSTED TROUT
CARMEL LATTE

But that wouldn’t have made for a very entertaining column, would it? And caramel would still be spelled wrong.

Speaking of columns, we should probably take a minute or two to address DW’s question, shouldn’t we? As it turns out, system sound information is stored in the registry; to be a little more precise, system sound information is stored in the HKEY_CURRENT_USER\AppEvents\Schemes\Apps\.Default\Maximize\.Current portion of the registry. Each of the system sound events found in the Windows Control Pane (Default Beep; Device Connect; Device Disconnect; etc.) have their own little place in this registry key:

Spacer


So how can we randomly-assign a sound to one of these events? Let’s start by showing you a script that assigns a specific sound to a specific event. After we explain how that code works then we’ll see what we can do about adding in the random-assignment stuff.

Here’s a simple little script that assigns the sound file C:\Windows\Media\Ding.wav to the Maximize sound event (in other words, Ding.wav will be played each time you maximize a window):

Const HKEY_CURRENT_USER = &H80000001strComputer = "." Set objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv") strKeyPath = "AppEvents\Schemes\Apps\.Default\Maximize\.Current"strValueName = ""strValue = "C:\Windows\Media\Ding.wav" objRegistry.SetExpandedStringValue _    HKEY_CURRENT_USER,strKeyPath,strValueName,strValue

As you can see, we start off by defining a constant named HKEY_CURRENT_USER and setting the value to &H80000001; we’ll use this constant to tell the script which registry key we want to work with. After we define the constant, we connect to the WMI service on the local computer.

Note. Could we use this script to change the system sounds on a remote machine? Sure; just assign the name of that remote machine to the variable strComputer.

Next we assign values to three variables:

  • strKeyPath is the path to the registry key we want to work with. In this case, that’s AppEvents\Schemes\Apps\.Default\Maximize\.Current. If we wanted to change the sound used when Windows shuts down we’d use this path: AppEvents\Schemes\Apps\.Default\SystemExit\.Current. To change the sound used when Windows first starts up we’d use this path: AppEvents\Schemes\Apps\.Default\SystemStart\.Current. Etc.
  • strValueName. This is the name of the registry value we need to change. Notice that we didn’t specify a name here. Why? Because the sound events all use the (Default) value to store sound information. When working with a (Default) you don’t specify a value name.
  • strValue. This is the local path to the sound we want played each time we maximize a window. Incidentally, sound information is stored using the REG_EXPAND_SZ data type; that means we could also use environment variables such as %WINDIR% and %SYSTEMROOT% in our file paths. In other words, we could have assigned this value to strValue: %WINDIR%\Media\Ding.wav.

At that point all we have to do is call the SetExpandedStringValue method to update the registry:

objRegistry.SetExpandedStringValue _    HKEY_CURRENT_USER,strKeyPath,strValueName,strValue

Best of all, this change takes place immediately; there’s no need to logoff or shutdown. Instead, run the script and then immediately try maximizing a window. If you don’t hear a ding, the Scripting Guy who writes this column will eat his hat.

And maybe even drink a PAREMSAN CARMEL LATTE.

Cool, huh? Now, what about randomly assigning a sound to a sound event? Well, this next script retrieves a collection of all the files in the folder C:\Windows\Media:

Set colFileList = objWMIService.ExecQuery _    ("ASSOCIATORS OF {Win32_Directory.Name='C:\Windows\Media'} Where " _        & "ResultClass = CIM_DataFile")

The script then retrieves the value of the Count property, which tells it how many files were found in the Media folder:

intCount = colFileList.Count

From there the script uses this block of code to generate a random number between 1 and the number of files in the folder:

intHighNumber = intCountintLowNumber = 1RandomizeintNumber = Int((intHighNumber - intLowNumber + 1) * Rnd + intLowNumber)

Got all that? OK, after assigning the value 1 to a counter variable named i we next set up a For Each loop to loop through all the files in the collection. Inside that loop we use this line of code to determine if our counter variable is equal to the random number we generated:

If i = intNumber Then

If it is, we grab the value of the file’s Name (path) property, assign it to the variable strValue, then use the Exit For statement to exit the For Each loop:

If i = intNumber Then    strValue = objFile.Name    Exit ForEnd If

If it isn’t, we increment i by 1 and try again. Sooner or later, i will be equal to intNumber and we will have assigned a file path to strValue. Once that’s happened we can then use our original script to assign that value to the Maximize sound event.

Here’s what the entire script looks like:

Const HKEY_CURRENT_USER = &H80000001strComputer = "."Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")Set colFileList = objWMIService.ExecQuery _    ("ASSOCIATORS OF {Win32_Directory.Name='C:\Windows\Media'} Where " _        & "ResultClass = CIM_DataFile")intCount = colFileList.CountintHighNumber = intCountintLowNumber = 1RandomizeintNumber = Int((intHighNumber - intLowNumber + 1) * Rnd + intLowNumber)i = 1For Each objFile in colFileList    If i = intNumber Then        strValue = objFile.Name        Exit For    End If           i = i + 1NextSet objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv") strKeyPath = "AppEvents\Schemes\Apps\.Default\Maximize\.Current"strValueName = "" objRegistry.SetExpandedStringValue _    HKEY_CURRENT_USER,strKeyPath,strValueName,strValue

That should get you going, DW.

Before we go, we’d be remiss if we signed off without noting another reader board sign that the Scripting Guy who writes this column saw a year or so ago. While driving past a “Used Equipment and Army Surplus Store,” he saw a reader board that read like this:

SLEEPING BAGS AND OUTDOOR GEAR
HIKING BOOTS
HALIBUT

The Scripting Guy who writes this column wasn’t sure whether this was used HALIBUT or Army Surplus HALIBUT. Nor did he bother to try and find out.