Results 1 to 7 of 7

Thread: PlaySound API + SND_MEMORY + VB6 don't work well together?

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Oct 2008
    Posts
    1,006

    PlaySound API + SND_MEMORY + VB6 don't work well together?

    Ok, so I've loaded the entire contents of a WAV file (headers and EVERYTHING) into a byte array and am now trying to get the PlaySound API calle to play it, and I'm using the SND_MEMORY flag as I should to get it to look to an in-memory array for the data (instead of a file as is its default opperation). And I've read this is what I need to do. But it's not working. Could you provide some insight as to WHY? Does PlaySound with SND_MEMORY flag not work in VB6 and instead require .Net to use SND_MEMORY properly? Or is there something else I need to do?

    Please help me. Thanks.

  2. #2
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,057

    Re: PlaySound API + SND_MEMORY + VB6 don't work well together?

    Code:
    Private Const SND_MEMORY As Long = &H4
    
    Private Declare Function PlaySound Lib "winmm.dll" Alias "PlaySoundW" (ByRef pszSound As Any, ByVal hmod As Long, ByVal fdwSound As Long) As Long
    
    PlaySound bytWav(0), 0&, SND_MEMORY
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  3. #3
    PowerPoster Keithuk's Avatar
    Join Date
    Jan 2004
    Location
    Staffordshire, England
    Posts
    2,235

    Re: PlaySound API + SND_MEMORY + VB6 don't work well together?

    Public Const SND_APPLICATION = &H80 'The sound is played using an application-specific association
    Public Const SND_ALIAS = &H10000 'The pszSound parameter is a system-event alias in the registry or the WIN.INI file. Do not use with either SND_FILENAME or SND_RESOURCE.
    Public Const SND_ALIAS_ID = &H110000 'The pszSound parameter is a predefined sound identifier.
    Public Const SND_ASYNC = &H1 'The sound is played asynchronously and PlaySound returns immediately after beginning the sound. To terminate an asynchronously played waveform sound, call PlaySound with pszSound set to NULL.
    Public Const SND_FILENAME = &H20000 'The pszSound parameter is a filename
    Public Const SND_LOOP = &H8 'The sound plays repeatedly until PlaySound is called again with the pszSound parameter set to NULL. You must also specify the SND_ASYNC flag to indicate an asynchronous sound event
    Public Const SND_MEMORY = &H4 'A sound event’s file is loaded in RAM. The parameter specified by pszSound must point to an image of a sound in memory.
    Public Const SND_NODEFAULT = &H2 'No default sound event is used. If the sound cannot be found, PlaySound returns silently without playing the default sound.
    Public Const SND_NOSTOP = &H10 'The specified sound event will yield to another sound event that is already playing. If a sound cannot be played because the resource needed to generate that sound is busy playing another sound, the function immediately returns FALSE without playing the requested sound. If this flag is not specified, PlaySound attempts to stop the currently playing sound so that the device can be used to play the new sound.
    Public Const SND_NOWAIT = &H2000 'If the driver is busy, return immediately without playing the sound.
    Public Const SND_PURGE = &H40 'Sounds are to be stopped for the calling task. If pszSound is not NULL, all instances of the specified sound are stopped. If pszSound is NULL, all sounds that are playing on behalf of the calling task are stopped. You must also specify the instance handle to stop SND_RESOURCE events.
    Public Const SND_RESOURCE = &H40004 'The pszSound parameter is a resource identifier; hmod must identify the instance that contains the resource.
    Public Const SND_SYNC = &H0 'Synchronous playback of a sound event. PlaySound returns after the sound event completes.
    Keith

    I've been programming with VB for 20 years. Started with VB4 16bit Pro, VB5 Pro, VB6 Pro/Enterprise and now VB3 Pro. But I'm no expert, I'm still learning.

  4. #4
    PowerPoster
    Join Date
    Jan 2008
    Posts
    11,074

    Re: PlaySound API + SND_MEMORY + VB6 don't work well together?

    This works for me
    Attached Files Attached Files


    Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.

  5. #5
    PowerPoster
    Join Date
    Jan 2008
    Posts
    11,074

    Re: PlaySound API + SND_MEMORY + VB6 don't work well together?

    This example plays from the resource file.

    1) Add three Command buttons to the Form:

    Command1.Caption = "Load WAV Sound from Resource File"

    Command2.Caption = "Play WAV Sound"

    Command3.Caption = "Stop WAV Sound"


    2) Open the Resource Editor and click on Add Custom Resource. This will give you a dialog box and you select a .WAV file and load it. This will add the sound file the the resource file and give it a default name of "Custom" and an ID of 101


    3) Compile to EXE first to make it work


    4) Run the project and click on Command1 to load the sound file from the resource then click on Command2 to play the sound.


    Code:
    Private Declare Function PlaySound Lib "winmm.dll" Alias "PlaySoundA" _
     (ByRef lpszName As Any, _
      ByVal hModule As Long, _
      ByVal dwFlags As Long) As Long
    
    Private Const SND_ASYNC = &H1
    Private Const SND_MEMORY = &H4
    
    Dim WavSound() As Byte
    
    Private Sub Command1_Click()
     WavSound = LoadResData(101, "custom")
     MsgBox "WavSound Loaded"
    End Sub
    
    Private Sub Command2_Click()
     On Error Resume Next
     PlaySound WavSound(0), 0, SND_MEMORY Or SND_ASYNC
    End Sub
    
    Public Sub Command3_Click()
     PlaySound "", ByVal 0&, SND_MEMORY
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
     Command3_Click
     End
    End Sub
    Last edited by jmsrickland; Dec 20th, 2012 at 08:47 PM.


    Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.

  6. #6

    Thread Starter
    Fanatic Member
    Join Date
    Oct 2008
    Posts
    1,006

    Re: PlaySound API + SND_MEMORY + VB6 don't work well together?

    Quote Originally Posted by jmsrickland View Post
    Code:
    Private Declare Function PlaySound Lib "winmm.dll" Alias "PlaySoundA" _
     (ByRef lpszName As Any, _
      ByVal hModule As Long, _
      ByVal dwFlags As Long) As Long
    
    Private Const SND_ASYNC = &H1
    Private Const SND_MEMORY = &H4
    
    Dim WavSound() As Byte
    
    Private Sub Command1_Click()
     WavSound = LoadResData(101, "custom")
     MsgBox "WavSound Loaded"
    End Sub
    
    Private Sub Command2_Click()
     On Error Resume Next
     PlaySound WavSound(0), 0, SND_MEMORY Or SND_ASYNC
    End Sub
    
    Public Sub Command3_Click()
     PlaySound "", ByVal 0&, SND_MEMORY
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
     Command3_Click
     End
    End Sub


    This works for some reason, but there are a couple problems I see, things that will need to be changed to be technically correct.

    1. Your PlaySound declare statement uses ByVal for hModule, and later when calling it to stop the playing you use ByVal 0&. This is redundant, as ByVal is only needed when calling if you have ByRef in the declaration.

    2. You use pass the number zero as 0& instead of 0. This is also redundant. In your declaration, you use ByVal hModule As Long. This means any value you supply to it will automatically be converted to a long (just like with the CLng function) prior to being passed to the DLL file for processing. So manually setting it as a zero-valued long (by saying 0&) instead of a zero-valued integer (by saying 0) is redundant.

    3. In your line to stop the playing sound your first argument you pass is "" (an empty string), which is actually the pointer to an empty string because it was declared ByRef in the declaration. But you aren't supposed to pass a pointer to an empty string. In order to stop playing (according to Microsoft's official documentation) you are supposed to pass a pointer to to a NULL string, which is to say a 1-character string who's ascii value is 0x00 (the NULL ascii character). So instead of typing "" for the first argument, you should have put vbNullchar (the VB constant for a string consisting of a a single ascii NULL character), or just to make sure you are passing just 1 byte to the function (since all strings in VB are unicode, 2bytes per character) is to have passed this instead StrConv(vbNullchar,vbFromUnicode). This command will convert the 1 unicode character long string which is a NULL character (having a 2byte unicode value of 0x0000) into a true ascii (1 byte per character) string consisting of 1 ascii character long string which is a NULL character (having a 1byte ascii value of 0x00). It would output a proper single character (1 byte) ascii string of a NULL character and would have passed the pointer to the string, to the DLL file.

    You put:
    Code:
    Public Sub Command3_Click()
     PlaySound "", ByVal 0&, SND_MEMORY
    End Sub
    You should have put:
    Code:
    Public Sub Command3_Click()
     PlaySound vbNullchar, 0, SND_MEMORY
    End Sub
    or even better:
    Code:
    Public Sub Command3_Click()
     PlaySound StrConv(vbNullchar,vbFromUnicode), 0, SND_MEMORY
    End Sub
    If I'm mistaken in this, please correct me, so I can see where my understanding is wrong.

  7. #7
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,057

    Re: PlaySound API + SND_MEMORY + VB6 don't work well together?

    Quote Originally Posted by Ben321 View Post
    If I'm mistaken in this, please correct me, so I can see where my understanding is wrong.
    2. It may be redundant, but it also means there's no automatic conversion going on at run time, resulting in slightly faster code. Whenever possible, you would want data type coercions, string concatenations, arithmetic calculations and the like to be done only once at compile time rather than always doing it at run time.


    3. In the PlaySound documentation, the pszSound parameter (first argument) was declared as a LPCTSTR, that is, it is a pointer to a constant (as opposed to writable), generic type (either ANSI or Unicode, depending on version used) string. It says there that "if this parameter is NULL, any currently playing waveform sound is stopped". C/C++'s NULL is equivalent to VB6's 0&. That is, passing a NULL pointer to that parameter stops the playing sound.

    When using the W version, the pszSound parameter should be declared ByVal pszSound As Long, while in the A version, it should be ByVal pszSound As String. However, that parameter can be made more flexible by declaring it as ByRef pszSound As Any. Ultimately, that parameter is just a pointer, which is equivalent to VB6's Long data type.

    A NULL string is different from a string containing a single Null character. In both VB6 and C/C++, a NULL string is a pointer pointing to address 0. VB6 has this constant vbNullString which is just that, a pointer pointing to nothing (0). On the other hand, you are correct about vbNullChar.

    So, in order to stop playing a sound, here's how the pszSound parameter should be passed:

    ByVal pszSound As Long 0&
    ByVal pszSound As String vbNullString
    ByRef pszSound As Any ByVal 0&



    BTW, if your app doesn't plan to support Win9x anymore, then you should always use the Unicode versions of APIs as much as possible. One compelling reason is because Unicode APIs are much faster to call on native Unicode systems. VB6 won't convert string parameters to ANSI and the OS won't have to either. This is from Working with Strings:

    Quote Originally Posted by MSDN
    New applications should always call the Unicode versions. Many world languages require Unicode. If you use ANSI strings, it will be impossible to localize your application. The ANSI versions are also less efficient, because the operating system must convert the ANSI strings to Unicode at run time.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width