Discussion:
Playing sound from resource file via sndPlaySound API
(too old to reply)
Darhl Thomason
2007-06-06 21:53:53 UTC
Permalink
I 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.

Note: the constants are declared elsewhere, they are working when I step
through the code so I know it's not them.

If I call sndPlaySound like this:
sndPlaySound App.Path & "\sound.wav", SND_ASYNC
it plays fine.

If I call PlaySound like this:
sndPlaySound LoadResData(101, "SOUND"), SND_ASYNC
it does not play.

The ATM sample calls it like this (In a BAS module):
Global Const SoundBuffer() as Byte
Sub BeginPlaySound(ByVal ResourceId As Integer)
SoundBuffer = LoadResData(ResourceId, "ATM_SOUND")
sndPlaySound SoundBuffer(0), SND_ASYNC Or SND_NODEFAULT Or SND_MEMORY
End Sub

And calls it by:
BeginPlaySound I

So I built this (in a BAS module):
Global Const SoundBuffer() as Byte
Sub MakeNoise(ByVal ResourceID As Integer)
SoundBuffer = LoadResData(ResourceID, "SOUND")
PlaySound SoundBuffer(0), SND_ASYNC Or SND_NODEFAULT Or SND_MEMORY
End Sub

And call it by:
MakeNoise WaveFile

And it doesn't play...Any help???

d
Darhl Thomason
2007-06-06 21:58:46 UTC
Permalink
Whoops, found typo, I fixed it but no help.
Post by Darhl Thomason
PlaySound SoundBuffer(0), SND_ASYNC Or SND_NODEFAULT Or SND_MEMORY
sndPlaySound SoundBuffer(0), SND_ASYNC Or SND_NODEFAULT Or SND_MEMORY
Norm
2007-06-06 22:08:54 UTC
Permalink
Darhl,

I am not sure, but do not see a resource ID for the sound file, unless
WaveFile is an Integer.

This is what I use, which loads the resource file first as a tmp file and
then plays it.

LoadDataIntoFile 101, App.Path & "\tmpfile.$$$" 'load sound file from
resource file

sndPlaySound App.Path & "\tmpfile.$$$", 1
--
Norm

Don't blame me, my programming is
self-taught and my teacher was not
very experienced. :-)
Post by Darhl Thomason
I 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.
Note: the constants are declared elsewhere, they are working when I step
through the code so I know it's not them.
sndPlaySound App.Path & "\sound.wav", SND_ASYNC
it plays fine.
sndPlaySound LoadResData(101, "SOUND"), SND_ASYNC
it does not play.
Global Const SoundBuffer() as Byte
Sub BeginPlaySound(ByVal ResourceId As Integer)
SoundBuffer = LoadResData(ResourceId, "ATM_SOUND")
sndPlaySound SoundBuffer(0), SND_ASYNC Or SND_NODEFAULT Or SND_MEMORY
End Sub
BeginPlaySound I
Global Const SoundBuffer() as Byte
Sub MakeNoise(ByVal ResourceID As Integer)
SoundBuffer = LoadResData(ResourceID, "SOUND")
PlaySound SoundBuffer(0), SND_ASYNC Or SND_NODEFAULT Or SND_MEMORY
End Sub
MakeNoise WaveFile
And it doesn't play...Any help???
d
Darhl Thomason
2007-06-06 22:15:48 UTC
Permalink
Post by Norm
Darhl,
I am not sure, but do not see a resource ID for the sound file, unless
WaveFile is an Integer.
Norm,

Yes, WaveFile is an Integer and it correctly matches the resource identifier
in the resource file.

d
Mike Williams
2007-06-07 10:26:51 UTC
Permalink
Post by Darhl Thomason
Yes, WaveFile is an Integer and it correctly matches the
resource identifier in the resource file.
Personally I'd advise you to use the newer playSound API, as others have
suggested. However, you should still be able to get your sndPlaySound code
working if you wish. One thing I notice is that you have not posted your
sndPlaySound declaration. I know it sounds a bit odd asking you to do such a
thing, but this particular API is commonly declared in a number of different
ways (with the first parameter sometimes being a String and sometimes a
Long) and the code you use to call it should match your own particular
declaration. I notice in your own code you are passing the Byte Array
returned by the LoadResData function. Have you checked your own sndPlaySound
declaration to see what the first parameter is. If it is a String then you
should change it to a Long, otherwise you could leave it as it is and use
the following:

sndPlaySound StrConv(LoadResData(101, "SOUND"), _
vbUnicode), SND_ASYNC Or SND_MEMORY

By the way, I assume that this specific resource is actually called "SOUND".

Mike
Darhl Thomason
2007-06-07 15:28:34 UTC
Permalink
I notice in your own code you are passing the Byte Array returned by the
LoadResData function. Have you checked your own sndPlaySound declaration
to see what the first parameter is. If it is a String then you should
change it to a Long, otherwise you could leave it as it is and use the
sndPlaySound StrConv(LoadResData(101, "SOUND"), _
vbUnicode), SND_ASYNC Or SND_MEMORY
By the way, I assume that this specific resource is actually called "SOUND".
Mike
Thanks Mike, that was the ticket! The first parameter was, in fact, a
string. I changed to Long and it now works like a charm! When I looked
closer at the ATM sample, the API call has the declaration as Any...but I
changed mine to Long as you suggested.

I'll also look at the PlaySound API instead of the sndPlaySound API.

Thanks again for everyone's suggestions and comments.

d
Darhl Thomason
2007-06-07 16:11:55 UTC
Permalink
Post by Darhl Thomason
I'll also look at the PlaySound API instead of the sndPlaySound API.
So, I need some help with the PlaySound API. at allapi.mentalis.org I read
about it. But I've never dealt with handles before, so I don't know how to
use it. It says that the hmod in the API call must be NULL unless
SND_RESOURCE is specified. Well, I'm using a resource file, so I obviously
need to pass my app's handle.

I also don't know how to tell it that I'm using a resource file...

I'm guessing here, but I think my call will be something like this:

Public Declare Function PlaySound Lib "winmm.dll" Alias "PlaySoundA" _
(ByVal lpszName As Long, ByVal hModule As Long, ByVal dwFlags As Long) As
Long

PlaySound LoadResData(ResourceID, "SOUNDS"), <??? not sure of the handle>,
SND_ASYNC Or SND_NODEFAULT Or SND_MEMORY Or SND_RESOURCE

I just did some more checking and I think that App.hInstance gives me the
handle of my app, right? So should I put App.hInstance where it's asking
for the handle?

I've played around with it, but still can't quite get the PlaySound API to
work.

I did get it to work with the sndPlaySound API, and may go back to that, but
I'd rather use the newer API call...

d
MikeD
2007-06-07 18:38:36 UTC
Permalink
Post by Darhl Thomason
Post by Darhl Thomason
I'll also look at the PlaySound API instead of the sndPlaySound API.
So, I need some help with the PlaySound API. at allapi.mentalis.org I
read about it. But I've never dealt with handles before, so I don't know
how to use it. It says that the hmod in the API call must be NULL unless
SND_RESOURCE is specified. Well, I'm using a resource file, so I
obviously need to pass my app's handle.
I also don't know how to tell it that I'm using a resource file...
Read my post. The one that Kevin Provance replied to and you replied to
Kevin. <g>

Apparently, you must have skipped over mine.
--
Mike
Microsoft Visual Basic MVP
Darhl Thomason
2007-06-07 20:27:06 UTC
Permalink
Post by MikeD
Read my post. The one that Kevin Provance replied to and you replied to
Kevin. <g>
Apparently, you must have skipped over mine.
--
Mike
Microsoft Visual Basic MVP
You're right Mike, I did skip over that...don't know how, but in any case it
helped me figure out what I needed to do. It's still playing from a buffer
not directly from the resource file, but I'll take it.

d

Option Explicit

Public Const SND_SYNC = &H0
Public Const SND_ASYNC = &H1
Public Const SND_NODEFAULT = &H2
Public Const SND_MEMORY = &H4
Public Const SND_LOOP = &H8
Public Const SND_NOSTOP = &H10
Public Const SND_RESOURCE = &H40004
Public SoundBuffer() As Byte

Public Declare Function PlaySound Lib "winmm.dll" Alias "PlaySoundA" _
(ByRef lpszName As Any, ByVal hModule As Long, ByVal dwFlags As Long) As
Long

Sub PlaySoundASync(ByVal ResourceID As Integer, ResourceCategory As String)
SoundBuffer = LoadResData(ResourceID, ResourceCategory)
PlaySound SoundBuffer(0), App.hInstance, SND_NODEFAULT Or SND_MEMORY Or
SND_ASYNC
End Sub

Sub PlaySoundSync(ByVal ResourceID As Integer, ResourceCategory As String)
SoundBuffer = LoadResData(ResourceID, ResourceCategory)
PlaySound SoundBuffer(0), App.hInstance, SND_NODEFAULT Or SND_MEMORY Or
SND_SYNC
End Sub
Mike Williams
2007-06-08 00:21:49 UTC
Permalink
You're right Mike [Mike D] , I did skip over that...don't know
how, but in any case it helped me figure out what I needed to
do. It's still playing from a buffer not directly from the resource
file, but I'll take it.
But it is loading the buffer from the resource file, so it amounts to the
same thing. If you'd rather perform the task "in one go" then you can do so
as follows. For this simple example to work you'll need to change the name
of the resource to "WAVE" (instead of "SOUNDS" or whatever it is you are
currently using):

PlaySound "101", App.hInstance, SND_ASYNC Or SND_RESOURCE

Where "101" is the identifier of a specific wav file in the "WAVE" resource
and the SND_RESOURCE constant is &H40004.

Mike
Darhl Thomason
2007-06-08 15:35:44 UTC
Permalink
If you'd rather perform the task "in one go" then you can do so as
follows. For this simple example to work you'll need to change the name of
the resource to "WAVE" (instead of "SOUNDS" or whatever it is you are
PlaySound "101", App.hInstance, SND_ASYNC Or SND_RESOURCE
Where "101" is the identifier of a specific wav file in the "WAVE"
resource and the SND_RESOURCE constant is &H40004.
Mike
Hmm, that's a no go. Does the 101 need to be in quotes? I made constants
for my sounds so I wouldn't have to remember what number went with what
sound...and I just put the constant name into the API call...

My modSoundPlayer now looks like this:
Option Explicit

Public Const SND_SYNC = &H0
Public Const SND_ASYNC = &H1
Public Const SND_NODEFAULT = &H2
Public Const SND_MEMORY = &H4
Public Const SND_LOOP = &H8
Public Const SND_NOSTOP = &H10
Public Const SND_RESOURCE = &H40004

Public Declare Function PlaySound Lib "winmm.dll" Alias "PlaySoundA" _
(ByRef lpszName As Any, ByVal hModule As Long, ByVal dwFlags As Long) As
Long

Sub PlaySoundASync(ByVal ResourceID As Integer)
PlaySound ResourceID, App.hInstance, SND_RESOURCE Or SND_ASYNC
End Sub

Sub PlaySoundSync(ByVal ResourceID As Integer)
PlaySound ResourceID, App.hInstance, SND_RESOURCE Or SND_SYNC
End Sub

My sound constants look like this:
Option Explicit

Public Const HOST = 101
Public Const DOUBLE = 102
Public Const FINAL = 103
Public Const OPENING = 104
Public Const THIS_IS = 105
Public Const BEEP_BEEP_BEEP = 106

and I call the API like this:
PlaySoundSync BEEP_BEEP_BEEP
and
PlaySoundASync HOST

I tried changing my sound constants to strings
Option Explicit

Public Const JEOPARDY_HOST = "101"
Public Const DAILY_DOUBLE = "102"
Public Const FINAL_JEOPARDY = "103"
Public Const JEOPARDY_OPENING = "104"
Public Const THIS_IS_JEOPARDY = "105"
Public Const BEEP_BEEP_BEEP = "106"

But that didn't help either. Is my declare correct? I know originally
lpszName was declared as a string, but I had to change it so it would load
from the buffer. It's set for Any now, so in theory that should cover all
contingencies, right?

What else am I missing?

d
Mike Williams
2007-06-08 20:16:54 UTC
Permalink
I know originally lpszName was declared as a string, but I had
to change it so it would load from the buffer. It's set for Any
now, so in theory that should cover all contingencies, right?
Well, it's not that simple in VB, with its silly Variants and its propensity
to coerce variable types at the drop of a hat! If you are using the default
101, 102, etc names in your Resource File then I would use a Long in your
declaration:

Private Declare Function PlaySound Lib "winmm.dll" _
Alias "PlaySoundA" (ByVal lpszName As Long, _
ByVal hModule As Long, ByVal dwFlags As Long) As Long

I would also make it doubly clear to Visual Basic what type of variable you
require for your constants. For example, instead of your current:

Public Const HOST = 101

I would use:

Public Const HOST As Long = 101

Then you should be able to play the sound using:

PlaySound HOST, App.hInstance, SND_ASYNC Or SND_RESOURCE

By the way, make sure that you have not got the playSound declared more than
once in your project (perhaps declared in one way in a Form and in another
way in a Module). Also, since you haven't yet responded to this, make
absolutely sure that the name of your resource for the sounds is called
"WAVE" (not "SOUNDS" or "WAV" or anything else). The playSound function by
default insist on it being called "WAVE".

Mike
Darhl Thomason
2007-06-08 20:41:18 UTC
Permalink
Post by Mike Williams
Well, it's not that simple in VB, with its silly Variants and its
propensity to coerce variable types at the drop of a hat!
Gotta love M$ for that <G>
Post by Mike Williams
If you are using the default 101, 102, etc names in your Resource File
I am using the default 101, 102, etc in the resource file
Post by Mike Williams
Private Declare Function PlaySound Lib "winmm.dll" _
Alias "PlaySoundA" (ByVal lpszName As Long, _
ByVal hModule As Long, ByVal dwFlags As Long) As Long
Updated to:
Public Declare Function PlaySound Lib "winmm.dll" Alias "PlaySoundA" _
(ByVal lpszName As Long, ByVal hModule As Long, ByVal dwFlags As Long) As
Long
Post by Mike Williams
I would also make it doubly clear to Visual Basic what type of variable
Public Const HOST = 101
Public Const HOST As Long = 101
Public Const HOST As Long = 101
Public Const DOUBLE As Long = 102
Public Const FINAL As Long = 103
Public Const OPENING As Long = 104
Public Const THIS_IS As Long = 105
Public Const BEEP_BEEP_BEEP As Long = 106
Post by Mike Williams
PlaySound HOST, App.hInstance, SND_ASYNC Or SND_RESOURCE
PlaySound HOST, App.hInstance, SND_ASYNC Or SND_RESOURCE

also tried:
PlaySoundASync HOST

Which is:
Sub PlaySoundASync(ByVal ResourceID As Long)
PlaySound ResourceID, App.hInstance, SND_RESOURCE Or SND_ASYNC
End Sub
Post by Mike Williams
By the way, make sure that you have not got the playSound declared more
than once in your project (perhaps declared in one way in a Form and in
another way in a Module). Also, since you haven't yet responded to this,
make absolutely sure that the name of your resource for the sounds is
called "WAVE" (not "SOUNDS" or "WAV" or anything else). The playSound
function by default insist on it being called "WAVE".
Double checked, the only declaration is in the module, and the resource name
is "WAVE"
Post by Mike Williams
Mike
Still no sounds...
Mike Williams
2007-06-08 21:51:54 UTC
Permalink
Post by Darhl Thomason
Double checked, the only declaration is in the module, and
the resource name is "WAVE". Still no sounds...
Well, it sounds like you've got all the bases covered. I can't hink of
anything else that might be causing the problem, except perhaps that the wav
file is a bit dodgy. I seem to remember either sndPlaySound or PlaySound
having problems on some machines playing mono wav files but it would play
stereo wav files okay, but I don't think that's likely to be the problem in
your case. Why not just zip up all your VB project files (make sure you've
got all of them, including the resource file) and send them to me so that I
can have a look at it? Email the zip file to ***@yahoo.co.uk after
first removing the non alcoholic beverage ;-)

Mike
Darhl Thomason
2007-06-08 22:43:21 UTC
Permalink
Post by Mike Williams
Well, it sounds like you've got all the bases covered. I can't hink of
anything else that might be causing the problem, except perhaps that the
wav file is a bit dodgy. I seem to remember either sndPlaySound or
PlaySound having problems on some machines playing mono wav files but it
would play stereo wav files okay, but I don't think that's likely to be
the problem in your case. Why not just zip up all your VB project files
(make sure you've got all of them, including the resource file) and send
them to me so that I can have a look at it? Email the zip file to
;-)
Mike
Thanks Mike! I'll zip them up and send them on the way. Thanks a ton for
taking a look at them!

d
Darhl Thomason
2007-06-08 22:45:51 UTC
Permalink
Post by Darhl Thomason
Thanks Mike! I'll zip them up and send them on the way. Thanks a ton for
taking a look at them!
d
I forgot I rebuilt my work computer a couple of weeks ago and haven't
reinstalled my remote control software yet. I'll zip them up first thing
Monday morning and send them to you then.

Thanks again!

d
Mike Williams
2007-06-07 11:41:42 UTC
Permalink
"Darhl Thomason" <***@papamurphys.nospamplease.com> wrote in message news:***@TK2MSFTNGP03.phx.gbl...

. . . by the way, my suggestion of using StrConv was merely to show how you
could get the code to work if you stick with the "String" declaration of
sndPlaySound. It is of course wasteful in terms of memory and it would be
better to change the declaration so that it works properly with the Byte
data, or, perhaps better still, use the newer playSound API.

Mike
BeastFish
2007-06-06 23:03:50 UTC
Permalink
In a bit of a hurry, but I just wanted to point out that you don't need to
use a tempfile. You can play the wav file directly from memory... just use
LoadResData to throw it into a byte array and use the SND_MEMORY flag (&H4 )
to play it from memory ("Or" it to your flags). Just note that you'd need
to change the PlaySound declaration a bit (define the first parameter
lpszName as Byte).
Post by Norm
Darhl,
I am not sure, but do not see a resource ID for the sound file, unless
WaveFile is an Integer.
This is what I use, which loads the resource file first as a tmp file and
then plays it.
LoadDataIntoFile 101, App.Path & "\tmpfile.$$$" 'load sound file from
resource file
sndPlaySound App.Path & "\tmpfile.$$$", 1
--
Norm
Don't blame me, my programming is
self-taught and my teacher was not
very experienced. :-)
Post by Darhl Thomason
I read the help on the sndPlaySound API, and also on the Resource File.
I
Post by Norm
Post by Darhl Thomason
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.
Note: the constants are declared elsewhere, they are working when I step
through the code so I know it's not them.
sndPlaySound App.Path & "\sound.wav", SND_ASYNC
it plays fine.
sndPlaySound LoadResData(101, "SOUND"), SND_ASYNC
it does not play.
Global Const SoundBuffer() as Byte
Sub BeginPlaySound(ByVal ResourceId As Integer)
SoundBuffer = LoadResData(ResourceId, "ATM_SOUND")
sndPlaySound SoundBuffer(0), SND_ASYNC Or SND_NODEFAULT Or SND_MEMORY
End Sub
BeginPlaySound I
Global Const SoundBuffer() as Byte
Sub MakeNoise(ByVal ResourceID As Integer)
SoundBuffer = LoadResData(ResourceID, "SOUND")
PlaySound SoundBuffer(0), SND_ASYNC Or SND_NODEFAULT Or SND_MEMORY
End Sub
MakeNoise WaveFile
And it doesn't play...Any help???
d
BeastFish
2007-06-06 23:19:58 UTC
Permalink
sndPlaySound is an older API, only there for backwards compatability
(off-hand, I'm not sure it even supports the memory flag). Try using the
PlaySound API instead...

Private Declare Function PlaySound Lib "winmm.dll" _
Alias "PlaySoundA" (ByVal lpszName As String, _
ByVal hModule As Long, ByVal dwFlags As Long) As Long

PlaySound also supports the SND_RESOURCE flag (&H40004), in case you wanna
go that route instead.

BTW, your SoundBuffer() declaration should have thrown an error. Try Public
SoundBuffer() As Byte instead.
Post by Darhl Thomason
I 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.
Note: the constants are declared elsewhere, they are working when I step
through the code so I know it's not them.
sndPlaySound App.Path & "\sound.wav", SND_ASYNC
it plays fine.
sndPlaySound LoadResData(101, "SOUND"), SND_ASYNC
it does not play.
Global Const SoundBuffer() as Byte
Sub BeginPlaySound(ByVal ResourceId As Integer)
SoundBuffer = LoadResData(ResourceId, "ATM_SOUND")
sndPlaySound SoundBuffer(0), SND_ASYNC Or SND_NODEFAULT Or SND_MEMORY
End Sub
BeginPlaySound I
Global Const SoundBuffer() as Byte
Sub MakeNoise(ByVal ResourceID As Integer)
SoundBuffer = LoadResData(ResourceID, "SOUND")
PlaySound SoundBuffer(0), SND_ASYNC Or SND_NODEFAULT Or SND_MEMORY
End Sub
MakeNoise WaveFile
And it doesn't play...Any help???
d
Darhl Thomason
2007-06-07 15:33:35 UTC
Permalink
Post by BeastFish
BTW, your SoundBuffer() declaration should have thrown an error. Try Public
SoundBuffer() As Byte instead.
It didn't...I copied that from the ATM sample referenced in the help files.
So, what is the difference between Global & Public?

d
BeastFish
2007-06-07 18:12:19 UTC
Permalink
Post by Darhl Thomason
Post by BeastFish
BTW, your SoundBuffer() declaration should have thrown an error. Try Public
SoundBuffer() As Byte instead.
It didn't...I copied that from the ATM sample referenced in the help files.
So, what is the difference between Global & Public?
Global is provided for backwards compatability to older VB (VB3 (or was it
4) and earlier) projects. Public is its "replacement", but is essentially
the same thing. What should have thrown the error is the "Const"...

Global Const SoundBuffer() as Byte

...I pasted it into a bas module (just to be sure I wasn't losing my mind
<g>), and sure enough, it is a pretty shade of red. As a constant
declaration, it is invalid because nothing is being assigned to the constant
(and because of the array thing too). Even if, it should throw an
"Assignment to constant not permitted" error when you try to run the
project.

Looking through the ATM sample in my VB5, it's declared as...

Global SoundBuffer As String
Darhl Thomason
2007-06-07 18:32:54 UTC
Permalink
Post by Darhl Thomason
Global Const SoundBuffer() as Byte
Yeah, well, my brain is evidently addled from trying to figure out this
PlaySound API. I just checked my VB6 ATM sample and it shows

Global SoundBuffer() As Byte

And I checked my code and it shows

Global SoundBuffer() As Byte

The line I had copied before was probably from me messing around trying to
get it to work <g>

But thanks for the explanation!

d
MikeD
2007-06-06 23:49:07 UTC
Permalink
Post by Darhl Thomason
I 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
Kevin Provance
2007-06-07 01:58:13 UTC
Permalink
| 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".

Well, in one can still find a working copy of the vbAdvance Add-In, it'll
let you create resource DLLs from the VB IDE without all the fuss of VC.
I've used it several times, works like a charm. :-)

- Kev
Darhl Thomason
2007-06-07 15:45:17 UTC
Permalink
Post by Kevin Provance
Well, in one can still find a working copy of the vbAdvance Add-In, it'll
let you create resource DLLs from the VB IDE without all the fuss of VC.
I've used it several times, works like a charm. :-)
- Kev
www.vbadvance.com Looks like they're not selling the full version any
longer, but you can get the functional 30 day trial for free.

I may try this just for kicks <g>

d
Norm
2007-06-07 16:20:07 UTC
Permalink
Mike,

I have a question about your Class module. If I copy the code into a Class
module I get a syntax error for

Attribute VB_Name = "Sound"

and the other Attributes.

Is there something missing in your example or should they be declared
another way?
--
Norm

Don't blame me, my programming is
self-taught and my teacher was not
very experienced. :-)
Post by MikeD
Post by Darhl Thomason
I 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
'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
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
Ken Halter
2007-06-07 16:56:11 UTC
Permalink
Post by Norm
Mike,
I have a question about your Class module. If I copy the code into a Class
module I get a syntax error for
Attribute VB_Name = "Sound"
and the other Attributes.
Is there something missing in your example or should they be declared
another way?
He provided the *entire* class module, hidden VB attributes and all... which
means, you have to copy everything into Notepad, or some other text editor,
and SaveAs the name of the class... after that, it can be loaded by VB.

Either that, or just add a class to your project, name it "Sound" and ignore
(don't copy/paste) everything before the the "Option Explicit" line.
--
Ken Halter - MS-MVP-VB - Please keep all discussions in the groups..
In Loving Memory - http://www.vbsight.com/Remembrance.htm
Norm
2007-06-07 22:59:22 UTC
Permalink
Thanks for the information Ken.
--
Norm

Don't blame me, my programming is
self-taught and my teacher was not
very experienced. :-)
Post by Ken Halter
Post by Norm
Mike,
I have a question about your Class module. If I copy the code into a
Class module I get a syntax error for
Attribute VB_Name = "Sound"
and the other Attributes.
Is there something missing in your example or should they be declared
another way?
He provided the *entire* class module, hidden VB attributes and all...
which means, you have to copy everything into Notepad, or some other text
editor, and SaveAs the name of the class... after that, it can be loaded
by VB.
Either that, or just add a class to your project, name it "Sound" and
ignore (don't copy/paste) everything before the the "Option Explicit"
line.
--
Ken Halter - MS-MVP-VB - Please keep all discussions in the groups..
In Loving Memory - http://www.vbsight.com/Remembrance.htm
Norm
2007-06-08 00:38:57 UTC
Permalink
Mike or Ken,

I have another question about this class, I am trying the code below and it
will work in the IDE mode, but returns false when compiled. I assume for
some reason it is not finding the resource file.


If IsIDE Then

m_sSoundBuffer = StrConv(LoadResData(ResourceId, "CUSTOM"), vbUnicode)

lRet = sndPlaySound(m_sSoundBuffer, Flags Or SND_MEMORY)

Else

lRet = PlaySound(ResourceId, App.hInstance, Flags Or SND_RESOURCE)

End If
--
Norm

Don't blame me, my programming is
self-taught and my teacher was not
very experienced. :-)

normfowler_don't ***@hotmail.com
Norm
2007-06-08 02:38:22 UTC
Permalink
Mike or Ken,

In reference to the previous question about the PlaySound API not working
when compiled. With further checking I get the same App.hInstance returned
when compiled as I do when running in the IDE mode. Reading Mike's post and
comments in the Class module I am assuming these should be different.

I must be missing something else, but so far have been unable to find it.
--
Norm

Don't blame me, my programming is
self-taught and my teacher was not
very experienced. :-)
Mike Williams
2007-06-08 10:01:22 UTC
Permalink
Post by Norm
I must be missing something else, but so far have been unable to find it.
It's all about who "owns" the resource. As a compiled exe it is the exe that
owns it, whereas as far as I am aware) when running in the IDE it is the VB
runtime that owns it, or something like that anyway ;-) Besides, I think
(but I'm not sure) that the PlaySound API "knows" the name of the module
that is calling it anyway, because it works just as well if you use a zero
instead of App.hInstance.

Regardless of that, looking at your example, the part of your code which
gets executed when running as a compiled exe is:

lRet = PlaySound(ResourceId, App.hInstance, Flags Or SND_RESOURCE)

Are you saying that the above code does not work in the compiled exe? If not
then perhaps you are using an invalid ResourceID or there is something wrong
with the rest of your Flags (you haven't posted that bit).

Or perhaps your resource section does not have the correct name. Did you
read my earlier message about the name of the resource when using code such
as the above example? The section containing the various wav files needs to
be called "WAVE" (not "SOUNDS" or "WAV" or anything else). Are you using the
name "WAVE"?

This is what my declaration looks like (note I am using a String for
lpszName):

Private Declare Function PlaySound Lib "winmm.dll" _
Alias "PlaySoundA" (ByVal lpszName As String, _
ByVal hModule As Long, ByVal dwFlags As Long) As Long
Private Const SND_ASYNC As Long = &H1&
Private Const SND_RESOURCE As Long = &H40004

And this is what my code looks like:

PlaySound "HELLOWORLD", App.hInstance, SND_ASYNC Or SND_RESOURCE

And this is what my Resource File looks like in the resource editor (as well
as I can present it in a newsgroup post):

+ "CUSTOM" ' (this folder shown closed)
- "WAVE" ' (this folder shown open) (The name "WAVE" is
IMPORTANT!)
"HELLOWORLD"
"RUM"
"COKE"

Are you doing something similar?

Mike
MikeD
2007-06-08 14:25:58 UTC
Permalink
Post by Norm
Mike or Ken,
I have another question about this class, I am trying the code below and
it will work in the IDE mode, but returns false when compiled. I assume
for some reason it is not finding the resource file.
If IsIDE Then
m_sSoundBuffer = StrConv(LoadResData(ResourceId, "CUSTOM"), vbUnicode)
lRet = sndPlaySound(m_sSoundBuffer, Flags Or SND_MEMORY)
Else
lRet = PlaySound(ResourceId, App.hInstance, Flags Or SND_RESOURCE)
End If
Based on that code, it appears your resource type is named "CUSTOM". It has
to be "WAVE", as I stated in my original post.

Also, personally, I wouldn't bother with the If statement to use
sndPlaySound in the IDE and PlaySound in the compiled EXE. You should
always test your compiled project too (because there CAN be differences
between running your compiled project and running it in the IDE) so just
test then that your sounds are working OK.
--
Mike
Microsoft MVP Visual Basic
Norm
2007-06-08 22:10:02 UTC
Permalink
Thanks very much, the name in the resource file was the problem. Once I
named it WAVE it worked.

Thanks again.
--
Norm

Don't blame me, my programming is
self-taught and my teacher was not
very experienced. :-)

normfowler_don't ***@hotmail.com
MikeD
2007-06-09 02:15:27 UTC
Permalink
Post by Norm
Thanks very much, the name in the resource file was the problem. Once I
named it WAVE it worked.
Glad you got it working. Not meaning to chastise you or anything, but
between Mike Williams' messages in this thread and my own, it was mentioned
a few times that the resource type needed to be named WAVE. You could have
saved yourself some time and possibly some aggravation if you'd just read
our messages more thoroughly. <g>
--
Mike
Microsoft MVP Visual Basic
Norm
2007-06-09 11:25:44 UTC
Permalink
Mike,

You are correct and it is my fault that I was having that problem.

Somewhat in my defense I started trying to use it right after you posted the
code and it was not quite as clear then. :-)

But I should have gone back and read all the post's again.
--
Norm

Don't blame me, my programming is
self-taught and my teacher was not
very experienced. :-)

normfowler_don't ***@hotmail.com
Loading...