Using Sounds


WinWatch is just a demo, and showing a hex dump of unknown data formats is good enough. But you’ll have to do better than that in real life. WinWatch does know about one nonstandard resource: sounds in the WAVE format.


Nonstandard formats can be a problem unless everyone who uses the format agrees on the type name. Someone might put a wave file in a program as an RCDATA resource type. If that someone was you, you’d know what to do. But to WinWatch, it’s just data. You could turn the data into a string and search the string for some identifying data instead of producing a hex dump. A hex dump of wave data, for example, looks like this:

52 49 46 46 B2 87 00 00  RIFF....
57 41 56 45 66 6D 74 20 WAVEfmt

WinWatch could test data blocks to see whether they contain such recognizable formats, but that’s up to you. My version recognizes only wave data that has the type name WAVE. This works for TRES. If you see a resource with type WAVE in another program, there’s a good chance you’ll be able to play it, although you have no guarantee that a particular wave resource won’t contain waves for a surfing program.


Assuming that you do have a wave sound resource, here’s the code to play it:

Sub PlayWave(ByVal hMod As Long, sWave As String)
‘ Convert wave resource to memory
Dim hWave As Long, hmemWave As Long, pWave As Long
hWave = FindResourceStrStr(hMod, sWave, “WAVE”)
hmemWave = LoadResource(hMod, hWave)
pWave = LockResource(hmemWave)
Call FreeResource(hmemWave)
‘ Play it
If sndPlaySoundAsLp(pWave, SND_MEMORY Or SND_NODEFAULT) Then
pbResource.Print “Sound played”
Else
pbResource.Print “Can’t play sound: “ & sCrLf & sCrLf & _
WordWrap(ApiError(Err.LastDllError), 25)
End If
End Sub

If this isn’t clear, you might refer to “The Zen of Windows Memory Management” on pages 454–455. The sndPlaySoundAsLp function is a type-safe alias to the multimedia sndPlaySound function. The Windows API type library provides two other aliases. You can use the raw version to play sound files or system alerts. For example, use this statement to play a wave file:

f = sndPlaySound(“c:\windows\wave\helpme.wav”, SND_SYNC)

Use this statement to play the sound associated with SystemExclamation in
the registry:

f = sndPlaySound(“SystemExclamation”, SND_SYNC)

When you load a sound with LoadResData, you get back an array of bytes. The Test Resources program uses the sndPlaySoundAsBytes alias to play a wave string. It’s wrapped in the following function in UTILITY.BAS.

Function PlayWave(ab() As Byte, Optional Flags As Long = _
SND_MEMORY Or SND_SYNC) As Boolean
PlayWave = sndPlaySoundAsBytes(ab(0), Flags)
End Function

You can play sounds with the Multimedia MCI control, which is appropriate in the context of other multimedia features, but it’s overkill if you’re simply playing sounds. Adding a control takes up a good chunk of memory resources, whereas using the sndPlaySound function takes up very little.


A bit of advice: if you’re tempted to start putting sound resources in your programs left and right, think again. Ask the guy across the hall from me how much he enjoyed those amusing sounds in the Test Resources program the 500th time he heard them during my debugging phase. He’ll suggest that you use the sounds associated with existing events in the registry. You can find the standard events in the \HKEY_CURRENT_USER\AppEvents\EventLabels key. The sounds associated with the events are in \HKEY_CURRENT_USER\AppEvents\Schemes­\Apps. By using the registry, you give users the opportunity to override your choice of sounds (or perhaps remove them) with the Sounds applet in the Control Panel. I’ll examine the registry in more detail in Chapter 10, but this should give you some idea of how to let users have the final say about potentially annoying noises.