Post by Darhl ThomasonI read the help on the sndPlaySound API, and also on the Resource File. I
believe I have things set up properly because I can pull bitmaps out of my
resource file. The help files also referenced the ATM sample project which
I have looked at as well.
You'd be better off using PlaySound rather than sndPlaySound...for a number
of reasons. First, PlaySound supports playing *directly* from the resource.
IOW, you don't need to create a temp file or "buffer" the resource into a
string variable. Also, my experience has been that certain sounds just
won't play (or worse, cause the app to crash) if the sound is from a
resource and you're using sndPlaySound. That might just be the problem
you're having. I've NEVER had a problem using PlaySound to play sounds from
a resource. The only caveat is that it won't work in the IDE. This is
because you need to provide an instance handle, and when in the IDE the
instance handle is that of the IDE and the resource isn't an IDE resource.
Here's a complete class module that I use. Some of it you won't care about
(such as the Enum type for certain resource IDs that I use). This is also
capable of playing sounds from a resource DLL. This is a separate DLL that
can be shared among your apps. However, this DLL need to be created with
VC++. The documentation for using this class module is pretty much all in
the BeginPlaySound method. It pretty much describes everything you need to
know. One thing that I'm not sure is mentioned in any comments is that the
sound resources MUST have a type of "WAVE".
There will probably be quite a bit of line-wrapping that you'll need to
correct when you copy and paste this. Sorry 'bout that.
-----BEGIN
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
Persistable = 0 'NotPersistable
DataBindingBehavior = 0 'vbNone
DataSourceBehavior = 0 'vbNone
MTSTransactionMode = 0 'NotAnMTSObject
END
Attribute VB_Name = "Sound"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Private Declare Function PlaySound Lib "WINMM.DLL" Alias "PlaySoundA" (ByVal
lpszName As Any, ByVal hModule As Long, ByVal dwFlags As Long) As Long
'Private Declare Function sndPlaySound Lib "WINMM.DLL" Alias "sndPlaySoundA"
(ByVal lpszSoundName As Any, ByVal uFlags As Long) As Long
Private m_sSoundBuffer As String
Enum SoundFlagConstants
'Constants for the dwFlags argument
SND_SYNC = &H0 ' Control does not return until sound
completes
SND_ASYNC = &H1 ' Control returns immediately after being
playback
SND_NODEFAULT = &H2 ' Don't play default sound if lpszSoundName
is invalid
SND_LOOP = &H8 ' Continously loops the sound. SND_ASYNC
MUST ALSO BE SPECIFIED, otherwise control will never return
SND_NOSTOP = &H10 ' Do not stop playback of a sound already
playing
SND_ALIAS = &H10000 ' Name is a sound event in either WIN.INI or
Registry
SND_FILENAME = &H20000 ' Name is a file name
End Enum
'Private Const SND_ALIAS = &H10000 ' name is a WIN.INI [sounds]
entry
'Private Const SND_ALIAS_ID = &H110000 ' name is a WIN.INI [sounds]
entry identifier
'Private Const SND_ALIAS_START = 0 ' must be > 4096 to keep
strings in same section of resource file
'Private Const SND_APPLICATION = &H80 ' look for application
specific association
'Private Const SND_ASYNC = &H1 ' play asynchronously
'Private Const SND_FILENAME = &H20000 ' name is a file name
'Private Const SND_LOOP = &H8 ' loop the sound until next
sndPlaySound
'Private Const SND_MEMORY = &H4 ' lpszSoundName points to a
memory file
'Private Const SND_NODEFAULT = &H2 ' silence not default, if
sound not found
'Private Const SND_NOSTOP = &H10 ' don't stop any currently
playing sound
'Private Const SND_NOWAIT = &H2000 ' don't wait if the driver is
busy
'Private Const SND_PURGE = &H40 ' purge non-static events for
task
'Private Const SND_RESERVED = &HFF000000 ' In particular these flags
are reserved
'Private Const SND_RESOURCE = &H40004 ' name is a resource name or
atom
'Private Const SND_SYNC = &H0 ' play synchronously (default)
'Private Const SND_TYPE_MASK = &H170007
'Private Const SND_VALID = &H1F ' valid flags /
;Internal /
'Private Const SND_VALIDFLAGS = &H17201F ' Set of valid flag bits.
Anything outside
'This flag determines if sounds are on or off. This is set to True or False
'by the class's Enabled property. This is useful so you can provide the
user with
'an option to play sounds or to not play sounds. This flag can be
overridden when
'invoking the Sounds.BeginPlaySound method. See comments in that procedure
for details.
Private m_bSoundsEnabled As Boolean
'These are constants for Resource IDs in the shared sound DLL file.
'Resource IDs for sounds in an application-specific sounds DLL file
'MUST start at 201. This allows the BeginPlaySound method to automatically
'determine which DLL file to use. The path to each DLL file must be
assigned
'to the corresponding properties of this class. Any sound resource compiled
'into the same component as this class can use any Resource ID, as the
'BeginPlaySound method has an optional parameter to specify whether the
'the resource is compiled in the component or exists externally, although
'it is highly recommended the same ID numbering convention be used
regardless.
Enum SoundIDConstants
ssUhOh = 101
ssQuestion = 102
ssMenuClick = 103
ssOptionClick = 103
ssThankYou = 104
ssButtonClick = 105
ssBummer = 106
ssHelpMe = 107
End Enum
'These functions are used for loading sound resources from other
'modules (i.e. a resource-only DLL file)
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA"
(ByVal lpLibFileName As String) As Long
Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As
Long) As Long
Private Declare Function LoadResource Lib "kernel32" (ByVal hInstance As
Long, ByVal hResInfo As Long) As Long
Private Declare Function FreeResource Lib "kernel32" (ByVal hResData As
Long) As Long
Private Declare Function FindResource Lib "kernel32" Alias "FindResourceA"
(ByVal hInstance As Long, ByVal lpName As String, ByVal lpType As String) As
Long
Private Declare Function LockResource Lib "kernel32" (ByVal hResData As
Long) As Long
'Private Declare Function SizeofResource Lib "kernel32" (ByVal hInstance As
Long, ByVal hResInfo As Long) As Long
Private m_sSharedResourceFileName As String
Private m_sAppResourceFileName As String
Public Property Let AppResourceFileName(NewFileName As String)
m_sAppResourceFileName = NewFileName
End Property
Property Let Enabled(OnOrOff As Boolean)
'Assigns whether sounds are on or off
m_bSoundsEnabled = OnOrOff
End Property
Property Get Enabled() As Boolean
'Returns whether sounds are on or off
Enabled = m_bSoundsEnabled
End Property
Public Function BeginPlaySound(ByVal ResourceId As SoundIDConstants,
Optional ByVal Flags As SoundFlagConstants = SND_ASYNC Or SND_NODEFAULT,
Optional ByVal WaveName As String = "", Optional ByVal ExternalDLL As
Boolean = False, Optional ByVal Override As Boolean = False) As Boolean
'ResourceId is the index number assigned to the sound in the resource
file.
'To make things easier, create constants for each index number. See the
'General Declarations section of this class module for more information.
'This is the only required argument.
'Flags is an optional argument to pass the SND_ constants.
'If not specified, the default is to play the sound asynchronously
(control
'returns immediately) and no default sound (if iResourceId is invalid or
file
'is not found) if the specified sound cannot be played.
'WaveName is an optional argument that specifies either a .wav file or a
sound
'event (events are listed in Control Panel's Sounds applet). If this
'argument is specified, it overrides both the ResourceID and the
ExternalDLL
'arguments. Windows will look first for a sound event matching
WaveName. If it
'can't find a match, it assumes the name is a .wav file. A couple of
notes regarding
'this. Potentially, a file (if no path or extension is specified) and
an event could
'have the same name. Also throw into this mix the fact that Windows
will look for a
'.wav file in a number of different folders if no path is specified.
Let's say there
'is a sound event named Quit and there is also a file named QUIT.WAV in
the Windows
'folder and another file named QUIT.WAV in your application's folder (as
returned by
'App.Path). You pass "QUIT" for WaveName and want QUIT.WAV in the
Windows folder to play.
'Not gonna happen. Windows is going to play the QUIT sound event (upper
and lower case
'is not relevant). So, you pass "QUIT.WAV" for WaveName thinking then
that Windows
'will play the file in the Windows folder. Not gonna happen. Windows
looks first in
'the application folder. Moral? Pass a fully qualified path and file
name which
'includes the extension and DON'T hard code this path (the Windows
folder might not
'be C:\Windows on all computers). Alternatively, you can specify either
the SND_ALIAS
'or SND_FILENAME flags (but never both). SND_ALIAS means Windows will
only look for
'a matching sound event. SND_FILENAME means Windows will only look for
a .wav file;
'however, you still have the potential problem of the order of folders
in which
'Windows looks for this file.
'ExternalDLL indicates whether to play the sound from a resource-only
DLL file,
'which is the default. If this parameter is False, the sound is played
from a
'resource which is compiled into the same component as this class. To
play a
'sound in a DLL, the path and file name of the DLL must be specified for
the
'appropriate ResourceFileName property. Resource IDs less than 201 use
the
'SharedResourceFileName property; IDs greater than 201 use the
AppResourceFileName
'property.
'Override is another optional argument to ignore the Enabled property.
If not
'specifed, the default is False (do not override Enabled property). By
specifying
'True for Override, the sound will ALWAYS play, even if Enabled is
False. This
'could be useful when you need a sound to play even if the user has
sounds disabled
'(assuming that such an option was provided to the user).
'There are no checks to ensure that files exists and that IDs are valid.
This is
'because this won't cause an error. By default, there simply won't be
any sound
'played at all. If you want the system default sound to play in this
case, specify
'a Flag argument that does NOT include the ssSndNoDefault flag.
'The method returns either True or False. True means playback was begun
successfully.
'False means a sound couldn't be played due to a problem (file couldn't
be found,
'no sound resource having the specified ID, DLL module couldn't be
loaded, etc.) AND
'ssSndNoDefault was NOT specified (because then the system default sound
is played).
Dim lRet As Long
Dim hInstance As Long
Const SND_RESOURCE = &H40004 ' Name is a resource name or atom
Const SND_MEMORY = &H4 ' lpszSoundName points to a memory file
'If both these are False, we will not play a sound. We need to return
True
'however, because the sound was not played due to some problem.
If Not Override And Not Enabled Then
BeginPlaySound = True
Exit Function
End If
On Error GoTo NoPlay
'If we're looping the sound, we have to make SURE that the sound is
being
'played asynchronously; otherwise, neither the PlaySound or sndPlaySound
API
'functions will ever return. This means the program would lock up.
If (Flags And SND_LOOP) = SND_LOOP Then
Flags = Flags Or SND_ASYNC
End If
If Len(WaveName) Then
'No problem using PlaySound here within the IDE because we're not
playing a
'resource. See NOTE below.
lRet = PlaySound(WaveName, 0&, Flags)
Else
'Make sure SND_ALIAS or SND_FILENAME was not specified or else the
sound
'may not play.
If (Flags And SND_ALIAS) = SND_ALIAS Then
Flags = Flags And Not SND_ALIAS
End If
If (Flags And SND_FILENAME) = SND_FILENAME Then
Flags = Flags And Not SND_FILENAME
End If
If ExternalDLL Then
'Get an instance handle to the appropriate module
If ResourceId <= 200 Then
hInstance = LoadLibrary(SharedResourceFileName)
Else
hInstance = LoadLibrary(AppResourceFileName)
End If
'If the module couldn't be loaded, the system's default sound
will play
'unless the ssSndNoDefault flag was specified. This flag is
specified by
'by default, so if you want to hear the system default sound in
case the
'specified sound can't be played, you'll need to pass a value
for the
'Flag argument.
'Also, the sound cannot be play asynchronously as this causes a
GPF since
'the library is immediately freed.
Flags = Flags And Not SND_ASYNC
lRet = PlaySound("#" & CStr(ResourceId), hInstance, Flags Or
SND_RESOURCE)
FreeLibrary hInstance
Else
'NOTE:
'The hInstance property of the App object will return the
instance handle
'of VB when the project is run within the IDE. This means the
PlaySound
'function won't work within the IDE. Instead, we'll load the
resource
'into a buffer and use sndPlaySound (at least until MS drops all
support
'for sndPlaySound, which isn't likely because it is still widely
used).
'PlaySound works fine if the compiled component is run because
then hInstance
'returns the proper instance handle. If you don't care about
hearing the sound
'when the program is run within the IDE, you can comment out the
first 2 lines
'and uncomment the line which follows.
'************************************************************
'NOTE: This may cause a fatal exception under NT/2000 so it's
'best to use the PlaySound function.
'm_sSoundBuffer = StrConv(LoadResData(ResourceId, "WAVE"),
vbUnicode)
'lRet = sndPlaySound(m_sSoundBuffer, Flags Or SND_MEMORY)
'************************************************************
lRet = PlaySound(ResourceId, App.hInstance, Flags Or
SND_RESOURCE)
End If
End If
BeginPlaySound = CBool(lRet)
Exit Function
NoPlay:
End Function
Public Sub EndPlaySound()
'Invoke this method if you wish to stop playback
'of a sound playing asynchronously (for example,
'a sound that is being looped).
Dim lRet As Long
lRet = PlaySound(0&, App.hInstance, 0&)
End Sub
Public Property Get AppResourceFileName() As String
AppResourceFileName = m_sAppResourceFileName
End Property
Public Property Let SharedResourceFileName(FileName As String)
m_sSharedResourceFileName = FileName
End Property
Public Property Get SharedResourceFileName() As String
SharedResourceFileName = m_sSharedResourceFileName
End Property
-----END
--
Mike
Microsoft MVP Visual Basic