PlaySound

  • Thread starter Thread starter Ot
  • Start date Start date
O

Ot

I found information on PlaySound. I implemented it in my program and it
works just dandy. The only little problem is that I have to package the
..wav files and send them along since PlaySound plays a sound file.

One of the options I found in a nice description of PlaySound says that
there are a couple of other choices.

1) The sound can be in the registry and actually controlled/selected by
the end user.

2) The sound can also be embedded in the assembly as long as I can point
to the area containing the sound.

I have no clue as to how to set up the registry for sounds for a particular
application. The wav files have to be installed somewhere on the user's
machine anyway, so this doesn't seem a really great way to go. If it is
fairly simple I might do it anyway.

The best seems to be to embed the wav in the application somehow and play
the in-memory copy. My problem here is I have no idea how to get the
contents of the wav into the application at a referenceable memory
location. And I don't know if there is any conversion required as I bring
it in. There must be some hint in the file as to, for example, how long
the wav is. Or maybe it is self defining with a termination byte
sequence -- maybe an all 0s or all Fs word. No clue.

Any help on the latter two possibilities would be appreciated!

Regards,
Ot
 
* "Ot said:
I found information on PlaySound. I implemented it in my program and it
works just dandy. The only little problem is that I have to package the
.wav files and send them along since PlaySound plays a sound file.

One of the options I found in a nice description of PlaySound says that
there are a couple of other choices.

1) The sound can be in the registry and actually controlled/selected by
the end user.

2) The sound can also be embedded in the assembly as long as I can point
to the area containing the sound.

I have no clue as to how to set up the registry for sounds for a particular
application. The wav files have to be installed somewhere on the user's
machine anyway, so this doesn't seem a really great way to go. If it is
fairly simple I might do it anyway.

The best seems to be to embed the wav in the application somehow and play
the in-memory copy. My problem here is I have no idea how to get the
contents of the wav into the application at a referenceable memory

See:

<http://groups.google.com/[email protected]>
 
Add the file to your application and set it's build action to
EmbeddedResource. You can reference it like this:
System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(
"myWavFile.wav"))
 
OT,

I wrote this class (below), to handle sound. Maybe you can modify it for
your own needs.

I made this because I had to make my own messsage box and didn't won't the
beep sound. You can call

PlaySoundFile passing a wavefile's path and it will play.

or you can call one of the system sounds like this

PlaySYSTEM_ASTERISK (this plays whatever is associated with Asterisk in the
windows sounds in control panel.)

There is a way to add your own sounds to the control panel as you spoke of.

****MSDN****
Registering Sound Events
Your application can register specific events to which the user can assign
sound files. When those events are triggered, the assigned sound file is
played. To register a sound event, create a key under the HKEY_CURRENT_USER
key, as follows:

HKEY_CURRENT_USER

AppEvents

Event Labels

EventName = Event Name

Set the value for EventName to a name that users can read. This is what will
appear in Control Panel.

Registering a sound event makes it available in Control Panel so that users
can assign a sound file to it. Your application must provide the code to
trigger that event when appropriate.

Defining as many sound events as possible for your application can be
especially helpful for users who need additional feedback - for example,
users with visual and some types of cognitive impairments. This does not
mean that your application must generate sounds for all events. You can
simply not assign sounds to an event by default. This way, users who want
additional feedback can use Control Panel to add appropriate sounds.

Always specify sounds to be played by using registry entries. Avoid
specifying sounds by file name or resource, because these cannot be
customized through Control Panel, and because accessibility aids cannot
determine the meaning of these sounds.

In addition, always trigger standard sound events when carrying out
equivalent actions. For example, if you display the equivalent of a critical
message box, play the SND_ALIAS_SYSTEMEXCLAMATION event sound.

More Information

For more information about system sound events, see the Microsoft Platform
SDK on the MSDN Online Web site at
http://msdn.microsoft.com/ui/guide/sdk.asp.

****end of MSDN****
search for Integrating With the Shell with no filtering....

HTH

Shane


Public Class clsSound

Declare Auto Function PlaySound Lib "winmm.dll" (ByVal name _

As String, ByVal hmod As Integer, ByVal flags As Integer) As Integer

' name specifies the sound file when the SND_FILENAME flag is set.

' hmod specifies an executable file handle.

' hmod must be Nothing if the SND_RESOURCE flag is not set.

' flags specifies which flags are set.

' The PlaySound documentation lists all valid flags.

Public Const SND_SYNC = &H0 ' play synchronously

Public Const SND_ASYNC = &H1 ' play asynchronously

Public Const SND_FILENAME = &H20000 ' name is file name

Public Const SND_RESOURCE = &H40004 ' name is resource name or atom

'private helper method to play system sound synch or async

Private Shared Sub PlaySystemSound(ByVal strSystemSound As String, ByVal
bSynchronous As Boolean)

If bSynchronous Then

PlaySound(strSystemSound, 0, SND_SYNC)

Else

PlaySound(strSystemSound, 0, SND_ASYNC)

End If

End Sub



Public Shared Sub PlaySoundFile(ByVal filename As String)

' Plays a sound from filename.

PlaySound(filename, Nothing, SND_FILENAME Or SND_ASYNC)

End Sub

Public Shared Sub PlaySYSTEM_ASTERISK(Optional ByVal bSynchronous As Boolean
= False)

PlaySystemSound("SystemAsterisk", bSynchronous)

End Sub

Public Shared Sub PlaySYSTEM_EXCLAMATION(Optional ByVal bSynchronous As
Boolean = False)

PlaySystemSound("SystemExclamation", bSynchronous)

End Sub

Public Shared Sub PlaySYSTEM_EXIT(Optional ByVal bSynchronous As Boolean =
False)

PlaySystemSound("SystemExit", bSynchronous)

End Sub

Public Shared Sub PlaySYSTEM_HAND(Optional ByVal bSynchronous As Boolean =
False)

PlaySystemSound("SystemHand", bSynchronous)

End Sub

Public Shared Sub PlaySYSTEM_QUESTION(Optional ByVal bSynchronous As Boolean
= False)

PlaySystemSound("SystemQuestion", bSynchronous)

End Sub

Public Shared Sub PlaySYSTEM_START(Optional ByVal bSynchronous As Boolean =
False)

PlaySystemSound("SystemStart", bSynchronous)

End Sub

End Class
 
a little research... at least in the win xp registry (regedit)

reveals

that under
HKEY_CURRENT_USER\AppEvents\Schemes\Apps

under it the sounds available (follow the example for MSN Messenger in
there

you should make a new key name for your app, (THE KEY IS TO MAKE SURE IT IS
THE SAME NAME AS YOUR PROGRAM!!!!!!!! IF NOT IT FAILS! took me hours to
figure this out.) If you program is called ABC123, then make this key
ABC123
Then as a subkey make whatever you want, maybe ABC_APPBegins and as a subkey
to that a key called .Current (here put the default sound file)

then using the same identifiers specified below this main key, add them to
HKEY_CURRENT_USER\AppEvents\EventLabels (creating a key for each one)

play with this in regedit and test via control panel sounds

easy to do..

once you have that working

use deployment project to do the same reg entries on setup....

when you call it using sound play sound you need to do so as follows.

' The PlaySound documentation lists all valid flags."

Public Const SND_SYNC = &H0 ' play synchronously

Public Const SND_ASYNC = &H1 ' play asynchronously

Public Const SND_ALIAS = &H10000 ' name is a WIN.INI [sounds] entry

Public Const SND_APPLICATION = &H80 ' look for application specific
association

Public Const SND_FILENAME = &H20000 ' name is file name

Public Const SND_RESOURCE = &H40004 ' name is resource name or atom

Private Shared Sub PlayAppSpecSystemSound(ByVal strSystemSound As String,
ByVal bSynchronous As Boolean, Optional ByVal bPlayDefaultIfNotSpecified As
Boolean = False)
Dim iFlags As Integer = SND_APPLICATION

iFlags = iFlags Or IIf(bSynchronous, SND_SYNC, SND_ASYNC)
PlaySound(strSystemSound, 0, iFlags)
End Sub

(remember to define playsound)

HTH

took me hours...

Shane
 
If I use the registry, it seems that the entry must refer back to a copy of
the wav file that I want to use, so I have to distribute the wav files I
want to use. The file goes wherever the user specifies (yes there is a
default, but they may override), so it would be difficult, wouldn't it, to
write the deployment project registry editor to point to the right place?
Or is there a substitution parameter that I can use in keys I build that
refers to the application folder as entered as the user executes the msi?

On the other hand, if I use the Embedded Resource method the files are
never seen by the user. They can't change them, but they are easily done.

Thanks,
Ot


SStory said:
a little research... at least in the win xp registry (regedit)

reveals

that under
HKEY_CURRENT_USER\AppEvents\Schemes\Apps

under it the sounds available (follow the example for MSN Messenger in
there

you should make a new key name for your app, (THE KEY IS TO MAKE SURE IT IS
THE SAME NAME AS YOUR PROGRAM!!!!!!!! IF NOT IT FAILS! took me hours to
figure this out.) If you program is called ABC123, then make this key
ABC123
Then as a subkey make whatever you want, maybe ABC_APPBegins and as a subkey
to that a key called .Current (here put the default sound file)

then using the same identifiers specified below this main key, add them to
HKEY_CURRENT_USER\AppEvents\EventLabels (creating a key for each one)

play with this in regedit and test via control panel sounds

easy to do..

once you have that working

use deployment project to do the same reg entries on setup....

when you call it using sound play sound you need to do so as follows.

' The PlaySound documentation lists all valid flags."

Public Const SND_SYNC = &H0 ' play synchronously

Public Const SND_ASYNC = &H1 ' play asynchronously

Public Const SND_ALIAS = &H10000 ' name is a WIN.INI [sounds] entry

Public Const SND_APPLICATION = &H80 ' look for application specific
association

Public Const SND_FILENAME = &H20000 ' name is file name

Public Const SND_RESOURCE = &H40004 ' name is resource name or atom

Private Shared Sub PlayAppSpecSystemSound(ByVal strSystemSound As String,
ByVal bSynchronous As Boolean, Optional ByVal bPlayDefaultIfNotSpecified As
Boolean = False)
Dim iFlags As Integer = SND_APPLICATION

iFlags = iFlags Or IIf(bSynchronous, SND_SYNC, SND_ASYNC)
PlaySound(strSystemSound, 0, iFlags)
End Sub

(remember to define playsound)

HTH

took me hours...

Shane




Ot said:
I found information on PlaySound. I implemented it in my program and it
works just dandy. The only little problem is that I have to package the
.wav files and send them along since PlaySound plays a sound file.

One of the options I found in a nice description of PlaySound says that
there are a couple of other choices.

1) The sound can be in the registry and actually controlled/selected by
the end user.

2) The sound can also be embedded in the assembly as long as I can point
to the area containing the sound.

I have no clue as to how to set up the registry for sounds for a particular
application. The wav files have to be installed somewhere on the user's
machine anyway, so this doesn't seem a really great way to go. If it is
fairly simple I might do it anyway.

The best seems to be to embed the wav in the application somehow and play
the in-memory copy. My problem here is I have no idea how to get the
contents of the wav into the application at a referenceable memory
location. And I don't know if there is any conversion required as I bring
it in. There must be some hint in the file as to, for example, how long
the wav is. Or maybe it is self defining with a termination byte
sequence -- maybe an all 0s or all Fs word. No clue.

Any help on the latter two possibilities would be appreciated!

Regards,
Ot
 
On the other hand, if I use the Embedded Resource method the files are
never seen by the user. They can't change them, but they are easily done.

Did you have a look at the sample code I posted?
 
Herfried K. Wagner said:
Did you have a look at the sample code I posted?

Indeed I did and I am doing exactly as you suggested.

Imports System.IO

Imports System.Reflection

Imports System.Runtime.InteropServices

Friend Class SoundHandler

Private Declare Auto Function PlaySound Lib "winmm.dll" ( _

ByVal pszSound As IntPtr, _

ByVal hModule As IntPtr, _

ByVal dwFlags As Int32 _

) As Boolean

Private Const SND_ASYNC As Int32 = &H1

Private Const SND_MEMORY As Int32 = &H4

Private Const SND_LOOP As Int32 = &H8

Private Const SND_PURGE As Int32 = &H40

Private Shared m_alertData As IntPtr

Private Shared m_alarmData As IntPtr

Private Shared m_warnData As IntPtr

Public Sub alarm()

PlaySound(m_alarmData, IntPtr.Zero, SND_MEMORY Or SND_ASYNC)

End Sub

Public Sub alert()

PlaySound(m_alertData, IntPtr.Zero, SND_MEMORY Or SND_ASYNC)

End Sub

Public Sub warn()

PlaySound(m_warnData, IntPtr.Zero, SND_MEMORY Or SND_ASYNC)

End Sub

Public Sub New()

Dim intLength As Integer

Dim st1 As Stream =
[Assembly].GetExecutingAssembly().GetManifestResourceStream("Ot.alert.wav")

intLength = CInt(st1.Length)

Dim abyt1(intLength - 1) As Byte

st1.Read(abyt1, 0, intLength)

st1.Close()

m_alertData = Marshal.AllocHGlobal(intLength)

Marshal.Copy(abyt1, 0, m_alertData, intLength)

st1 = Nothing

Dim st2 As Stream =
[Assembly].GetExecutingAssembly().GetManifestResourceStream("Ot.warn.wav")

intLength = CInt(st2.Length)

Dim abyt2(intLength - 1) As Byte

st2.Read(abyt2, 0, intLength)

st2.Close()

m_warnData = Marshal.AllocHGlobal(intLength)

Marshal.Copy(abyt2, 0, m_warnData, intLength)

st2 = Nothing

Dim st As Stream

st =
[Assembly].GetExecutingAssembly().GetManifestResourceStream("Ot.alarm.wav")

intLength = CInt(st.Length)

Dim abyt(intLength - 1) As Byte

st.Read(abyt, 0, intLength)

st.Close()

m_alarmData = Marshal.AllocHGlobal(intLength)

Marshal.Copy(abyt, 0, m_alarmData, intLength)

st = Nothing

End Sub

Protected Overrides Sub Finalize()

MyBase.Finalize()

Marshal.FreeHGlobal(m_alertData)

Marshal.FreeHGlobal(m_alarmData)

Marshal.FreeHGlobal(m_warnData)

End Sub

End Class
 
Ot, the code I sent you is a simple class and works well.

just be sure that
Private Shared Sub PlayAppSpecSystemSound(ByVal strSystemSound As String,
ByVal bSynchronous As Boolean, Optional ByVal bPlayDefaultIfNotSpecified As
Boolean = False)
Dim iFlags As Integer = SND_APPLICATION

iFlags = iFlags Or IIf(bSynchronous, SND_SYNC, SND_ASYNC)
PlaySound(strSystemSound, 0, iFlags)
End Sub

is added to that class and a public method to call it.

Follow the rest of my emails. It works great for me. I have defined 5 custom
system sounds for my app, they show up in control panel and play from the
vb.net app.

Shane

Ot said:
Herfried K. Wagner said:
Did you have a look at the sample code I posted?

Indeed I did and I am doing exactly as you suggested.

Imports System.IO

Imports System.Reflection

Imports System.Runtime.InteropServices

Friend Class SoundHandler

Private Declare Auto Function PlaySound Lib "winmm.dll" ( _

ByVal pszSound As IntPtr, _

ByVal hModule As IntPtr, _

ByVal dwFlags As Int32 _

) As Boolean

Private Const SND_ASYNC As Int32 = &H1

Private Const SND_MEMORY As Int32 = &H4

Private Const SND_LOOP As Int32 = &H8

Private Const SND_PURGE As Int32 = &H40

Private Shared m_alertData As IntPtr

Private Shared m_alarmData As IntPtr

Private Shared m_warnData As IntPtr

Public Sub alarm()

PlaySound(m_alarmData, IntPtr.Zero, SND_MEMORY Or SND_ASYNC)

End Sub

Public Sub alert()

PlaySound(m_alertData, IntPtr.Zero, SND_MEMORY Or SND_ASYNC)

End Sub

Public Sub warn()

PlaySound(m_warnData, IntPtr.Zero, SND_MEMORY Or SND_ASYNC)

End Sub

Public Sub New()

Dim intLength As Integer

Dim st1 As Stream =
[Assembly].GetExecutingAssembly().GetManifestResourceStream("Ot.alert.wav")

intLength = CInt(st1.Length)

Dim abyt1(intLength - 1) As Byte

st1.Read(abyt1, 0, intLength)

st1.Close()

m_alertData = Marshal.AllocHGlobal(intLength)

Marshal.Copy(abyt1, 0, m_alertData, intLength)

st1 = Nothing

Dim st2 As Stream =
[Assembly].GetExecutingAssembly().GetManifestResourceStream("Ot.warn.wav")

intLength = CInt(st2.Length)

Dim abyt2(intLength - 1) As Byte

st2.Read(abyt2, 0, intLength)

st2.Close()

m_warnData = Marshal.AllocHGlobal(intLength)

Marshal.Copy(abyt2, 0, m_warnData, intLength)

st2 = Nothing

Dim st As Stream

st =
[Assembly].GetExecutingAssembly().GetManifestResourceStream("Ot.alarm.wav")

intLength = CInt(st.Length)

Dim abyt(intLength - 1) As Byte

st.Read(abyt, 0, intLength)

st.Close()

m_alarmData = Marshal.AllocHGlobal(intLength)

Marshal.Copy(abyt, 0, m_alarmData, intLength)

st = Nothing

End Sub

Protected Overrides Sub Finalize()

MyBase.Finalize()

Marshal.FreeHGlobal(m_alertData)

Marshal.FreeHGlobal(m_alarmData)

Marshal.FreeHGlobal(m_warnData)

End Sub

End Class
 
Back
Top