|
-
Jul 10th, 2013, 02:58 PM
#1
[RESOLVED] Callback Sub causes App to crash on Form_Unload
Everytime I unload the app it crashes. I have narrowed it down to code in a callback sub but for the likes of me I can't understand why the code will cause the crash.
Here is the callback sub in a BAS module
Code:
Public Sub WaveCallbackProc(ByVal hwi As Long, _
ByVal uMsg As Long, _
ByVal dwInstance As Long, _
ByVal dwParam1 As Long, _
ByVal dwParam2 As Long)
Select Case uMsg
Case MM_WIM_OPEN
' Here when waveInOpen called
Case MM_WIM_DATA
' Here when sound buffer is full
Case MM_WIM_CLOSE
' Here when waveInClose called
Case MM_WOM_OPEN
' Here when waveOutOpen called
Case MM_WOM_DONE
'Here when sound buffer has finished or empty
Form1.Timer1.Enabled = False
Form1.picFreq(0).Cls
Form1.picFreq(1).Cls
Form1.Command2.Enabled = False
Form1.Command1.Enabled = True
Case MM_WOM_CLOSE
' Here when waveOutClose called
End Select
End Sub
Here is the Form_Unload
Code:
Private Sub Form_Unload(Cancel As Integer)
Timer1.Enabled = False
End Sub
Here is the Timer Sub
Code:
Private Sub MyTmrVis_Timer()
On Error GoTo ER
CopyMemory intSamples(0), WavSound(iOffset), FFT_SAMPLES
iOffset = iOffset + FFT_SAMPLES
DrawFrequencies intSamples, picFreq(0), picFreq(1)
Exit Sub
ER:
Form1.MyTmrVis.Enabled = False
Form1.picFreq(0).Cls
Form1.picFreq(1).Cls
Form1.Command2.Enabled = False
Form1.Command1.Enabled = True
CloseWaveOut
End Sub
In all cases I have not unloaded the App until after the code in the callback had finished so that means I do not kill app during the sound out (playing) time.
The only error that could occur in the timer sub is an index out of bounds but in the case of my testing that does not occur because the size of the WavSound buffer is exactly divisible by FFT_SAMPLES so I never get an odd results which would cause the CopyMemory function to fail and it is in sync with the callback sub which means that the callback at Case MM_WOM_DONE is executed when the last chunk has be extracted from the buffer in the timer event.
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.
-
Jul 10th, 2013, 03:27 PM
#2
Re: Callback Sub causes App to crash on Form_Unload
Do you get a meaningful error message when the crash occurs? If so, what is it?
-
Jul 10th, 2013, 04:13 PM
#3
Re: Callback Sub causes App to crash on Form_Unload
It's one of those VB has encounter a problem and must shut down, Sorry for the inconvience type. I know it has to do with the callback as I ran the same app without the callback and it doesn't crash. I know that you cannot call APIs while in the callback as I have already dealt with that problem so I'm guessing that the code in the callback is executing calls into the VB runtime module which I have been told will also cause unexpected results. I have a work around for this if it turns out I won't be able to use the callback with that code in it. I can put a boolean variable in place of the present code and set it to True when Case MM_WOM_DONE is called by the MM system then in my regular code I just test for that and then execute the same code outside of the callback. I would rather use the callback if at all possible with the code I presently have in it.
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.
-
Jul 10th, 2013, 04:58 PM
#4
Re: Callback Sub causes App to crash on Form_Unload
 Originally Posted by jmsrickland
I know that you cannot call APIs while in the callback....
You know wrong. What you can't do is use a Declare Function since that has to do an interpretive thunk to resolve the entrypoint at runtime (and this requires that the thread at least have COM initialized on it, and probably other things to "reach" the VB runtime).
 Originally Posted by jmsrickland
... so I'm guessing that the code in the callback is executing calls into the VB runtime module which I have been told will also cause unexpected results.
Your callback cannot touch anything but simple variables declared in a static (.BAS) module. No objects, including Forms, Controls, etc. This is also, at least in part, because the multimedia thread does not have COM initialized on it.
Basically you have about 3 options:
- Use something like a static Boolean that your UI thread (your VB code outside the callback) polls using a Timer control.
- Send a user message to the hWnd of a Form or UserControl which is subclassed to pick it up and process it.
- Skip all of this and just use subclassing in the first place to handle these multimedia messages.
-
Jul 11th, 2013, 04:52 PM
#5
Re: Callback Sub causes App to crash on Form_Unload
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.
-
Jul 11th, 2013, 05:01 PM
#6
Re: [RESOLVED] Callback Sub causes App to crash on Form_Unload
If that Schmidt guy takes an interest he might have more detail to contribute. He dives deeper into COM and VB issues than most of us need to.
-
Jul 12th, 2013, 06:17 AM
#7
Re: [RESOLVED] Callback Sub causes App to crash on Form_Unload
Sorry, discovered this invitation a bit late ... ;-)
Well, decoupling with Typelib-defined Calls, usually per PostMessage and then leaving the CallBack as fast as possible -
this approach was already mentioned - and that's what works and what I usually do as well (when we talk about Callbacks from different threads)...
which would be definitely the issue e.g. with the Multimedia-Timer-Callbacks ...
Not sure, if the WaveIn-callbacks fall into the same (foreign threaded) category, since I never forced those (by passing a Zero-Param)
whilst working with the WaveIn-API ... a normal polling per API-Timer (which may serve here now as an example for:
"friendly and secure callbacks on the same thread") was entirely enough.
Here's some code, not in the context of a working example, but "copied as found" from an already 13 year old Demo, which still works here.
It is using a (class-encapsulated) API-Timer - in conjunction with a RingBuffer-Array (and -Indexing).
Maybe that worth' a look from jmsrickland
Code:
Private Type Stereo
L As Integer
R As Integer
End Type
Private Type FFTStereo
L As Double
R As Double
End Type
Private Type WaveHdr
lpData As Long
dwBufferLength As Long
dwBytesRecorded As Long
dwUser As Long
dwFlags As Long
dwLoops As Long
lpNext As Long 'wavehdr_tag
reserved As Long
End Type
Private Type WavBuf
Hdr As WaveHdr
Arr(1023) As Stereo '23 msec (4kB ByteSize - and 43Hz at 44100)
FFT(1023) As FFTStereo
End Type
Private RBuf(29) As WavBuf, RIdx&, xt 'As APITimerClassEncapsulation
Private Sub DoStop()
Dim i&
xt.Enabled = False
If DevHandle Then
For i = 0 To UBound(RBuf)
waveInUnprepareHeader DevHandle, RBuf(i).Hdr, Len(RBuf(i).Hdr)
Next i
waveInReset DevHandle
waveInClose DevHandle
DevHandle = 0
End If
End Sub
Private Sub xt_Timer() '<- API-Timer-Eventsink (the normal one, not a MultiMedia-Timer)
Dim i&
Do While RBuf(RIdx).Hdr.dwFlags And WHDR_DONE
ProcessBuf RBuf(RIdx)
RIdx = CIdx(RIdx + 1)
Loop
For i = RIdx To RIdx + UBound(RBuf)
InitBuf RBuf(CIdx(i))
Next i
End Sub
Private Sub InitBuf(Buf As WavBuf)
If Buf.Hdr.dwUser Then Exit Sub
With Buf.Hdr
.dwUser = 1
If .lpData = 0 Then .lpData = VarPtr(Buf.Arr(0))
If .dwBufferLength = 0 Then .dwBufferLength = (UBound(Buf.Arr) + 1) * 4
waveInPrepareHeader DevHandle, Buf.Hdr, Len(Buf.Hdr)
waveInAddBuffer DevHandle, Buf.Hdr, Len(Buf.Hdr)
End With
End Sub
Private Sub ProcessBuf(Buf As WavBuf)
waveInUnprepareHeader DevHandle, Buf.Hdr, Len(Buf.Hdr)
Buf.Hdr.dwFlags = 0
Buf.Hdr.dwUser = 0
'your Buffer-Handling-Code here
End Sub
Private Function CIdx&(ByVal Idx&)
CIdx = Idx Mod (UBound(RBuf) + 1)
End Function
Olaf
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|