skin
asked on
Closing while in DoEvents causes exception
I'm a VC programmer that used VB to create a control to embed in my MFC MDI Application. I am getting an unhandled exception when I close my MFC application while my VB control is in a paint loop. I have a DoEvents in the loop, which, if I remove, prevents the exception from occuring but then I can't process other messages.
My question is: Is there some way to do the equivalent of an ::AfxLockApp() in VB? I think the rug is getting pulled out from underneath my control while it's in this paint loop. I just want to lock things down while it's in this paint loop so it can't go away until it finishes.
Thanks in advance
My question is: Is there some way to do the equivalent of an ::AfxLockApp() in VB? I think the rug is getting pulled out from underneath my control while it's in this paint loop. I just want to lock things down while it's in this paint loop so it can't go away until it finishes.
Thanks in advance
ASKER
I should have said AfxOleLockApp(). It just keeps the OLE object locked down so it can't go away until the AfxOleUnlockApp() is called
Here's the code. Basically it is doing some calculations and then calling the Picture method on an ImageArray:
For i = 0 To m_nPagesInOpenDoc - 1
DoEvents
If imgArray(i).Visible = True Then
' If it doesn't have a picture, create the picture
If imgArray(i).Picture = 0 Then
IDMViewerCtrl1.pageNumber = i + 1
Set pg = IDMViewerCtrl1.Page
Dim pixX As Integer
Dim pixY As Integer
pixX = m_propThumbWidth / Screen.TwipsPerPixelX
pixY = m_propThumbHeight / Screen.TwipsPerPixelY
Set imgArray(i).Picture = pg.Picture(pixX, pixY, idmBrightnessEnhance, 0)
' The picture can be a little larger than we asked for. Fix up the text
lblNumArray(i).Top = imgArray(i).Top + imgArray(i).Height + m_propThumbBorder / 4
shpSelection(i).Top = imgArray(i).Top - selborder * Screen.TwipsPerPixelY
shpSelection(i).Left = imgArray(i).Left - selborder * Screen.TwipsPerPixelX
shpSelection(i).Width = imgArray(i).Width + selborder * 2 * Screen.TwipsPerPixelX
shpSelection(i).Height = imgArray(i).Height + selborder * 2 * Screen.TwipsPerPixelY
End If
End If ' visible
Next i
Here's the code. Basically it is doing some calculations and then calling the Picture method on an ImageArray:
For i = 0 To m_nPagesInOpenDoc - 1
DoEvents
If imgArray(i).Visible = True Then
' If it doesn't have a picture, create the picture
If imgArray(i).Picture = 0 Then
IDMViewerCtrl1.pageNumber = i + 1
Set pg = IDMViewerCtrl1.Page
Dim pixX As Integer
Dim pixY As Integer
pixX = m_propThumbWidth / Screen.TwipsPerPixelX
pixY = m_propThumbHeight / Screen.TwipsPerPixelY
Set imgArray(i).Picture = pg.Picture(pixX, pixY, idmBrightnessEnhance, 0)
' The picture can be a little larger than we asked for. Fix up the text
lblNumArray(i).Top = imgArray(i).Top + imgArray(i).Height + m_propThumbBorder / 4
shpSelection(i).Top = imgArray(i).Top - selborder * Screen.TwipsPerPixelY
shpSelection(i).Left = imgArray(i).Left - selborder * Screen.TwipsPerPixelX
shpSelection(i).Width = imgArray(i).Width + selborder * 2 * Screen.TwipsPerPixelX
shpSelection(i).Height = imgArray(i).Height + selborder * 2 * Screen.TwipsPerPixelY
End If
End If ' visible
Next i
I think your goal should be avoiding DoEvents. This is why I asked for this code.
If you cannot avoid DoEvents:
' declarations of your user control
Private mExecuting As Integer
At the top of your loop add:
mExecuting = 1
In your paint loop add this after each 2-3 paint operations:
If mExecuting = 0 Then
' some exit operations, e.g mousepointer=vbNormal
Exit Sub
End If
' in other words, often chack mExecuting flag
Here you will set flag to 0, allow processing of small portion (2-3 lines) of your paint loop, and terminate all
Private Sub UserControl_Terminate()
mExecuting = 0
Doevents ' allow 2-3 lines
' now set all object references to Nothing
.
End ' brute force, but sometimes we cannot do any better
' you can also try without it
End Sub
Other causes:
Do you have circular references in your VB code?
But, first, let's try to avoid DoEvents
If you cannot avoid DoEvents:
' declarations of your user control
Private mExecuting As Integer
At the top of your loop add:
mExecuting = 1
In your paint loop add this after each 2-3 paint operations:
If mExecuting = 0 Then
' some exit operations, e.g mousepointer=vbNormal
Exit Sub
End If
' in other words, often chack mExecuting flag
Here you will set flag to 0, allow processing of small portion (2-3 lines) of your paint loop, and terminate all
Private Sub UserControl_Terminate()
mExecuting = 0
Doevents ' allow 2-3 lines
' now set all object references to Nothing
.
End ' brute force, but sometimes we cannot do any better
' you can also try without it
End Sub
Other causes:
Do you have circular references in your VB code?
But, first, let's try to avoid DoEvents
Sorry, my comment was added before I saw your code. I will read it in a moment.
ASKER
I really can't get away from using DoEvents and I do not suspect any circular references. My best guess is that the rug is being pulled out from underneath my control. So far I have been debugging in the VC Dev studio and I only see VB on the call stack when the error occurs.
ASKER
I really can't get away from using DoEvents and I do not suspect any circular references. My best guess is that the rug is being pulled out from underneath my control. So far I have been debugging in the VC Dev studio and I only see VB on the call stack when the error occurs.
ASKER
I really can't get away from using DoEvents and I do not suspect any circular references. My best guess is that the rug is being pulled out from underneath my control. So far I have been debugging in the VC Dev studio and I only see VB on the call stack when the error occurs.
OK. Can you try the second (mExecuting flag)
In the mean time 2 small tips (when you'll have time):
Use With keyword to reduce number of dots:
For i = 0 To m_nPagesInOpenDoc - 1
DoEvents
With imgArray(i)
If .Visible = True Then
....etc
End With
Intead of setting shpSelection(i).Top, left , Width
use Move method:
Dim tmpTop as single
Dim tmpLeft as single
tmpTop = ...
tmpLeft = ...
shpSelection(i).Move tmpTop, tmpLeft, tmpWidth, tmpHeight
Use With keyword to reduce number of dots:
For i = 0 To m_nPagesInOpenDoc - 1
DoEvents
With imgArray(i)
If .Visible = True Then
....etc
End With
Intead of setting shpSelection(i).Top, left , Width
use Move method:
Dim tmpTop as single
Dim tmpLeft as single
tmpTop = ...
tmpLeft = ...
shpSelection(i).Move tmpTop, tmpLeft, tmpWidth, tmpHeight
At the top of your loop add:
mExecuting = 1 ' before loop
but I forgot reseting flag:
mExecuting = 0 ' after your loop
' checking flag:
If mExecuting = 0 Then Exit Sub
In UserControl_Terminate add more doevents (1 to 100 ?)
Doevents ' allow 2-3 lines
Doevents
Doevents
mExecuting = 1 ' before loop
but I forgot reseting flag:
mExecuting = 0 ' after your loop
' checking flag:
If mExecuting = 0 Then Exit Sub
In UserControl_Terminate add more doevents (1 to 100 ?)
Doevents ' allow 2-3 lines
Doevents
Doevents
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
I don't think skin put his code in "Sub UserControl_Paint()".
If he did, I agree with Mirkwood - this is disaster. Paint event will be raised again during Doevents.
But I don't think he is entering his paint loop again while in a loop.
My example where I was forced to use End is in Form, not in UserControl. It is controlled loop, which checks for existence of a file. There is no reentering the loop. Doevents is in loop to allow user pressing "Exit" or "Quit" button.
When button is pressed, I have to unload form and use End or ExitProcess.
I described how I solved problem, but this is for "in house use" util, and I didn't look for better solution because it worked.
I will see if I can use Mirkwoods' "Timer" solution.
If he did, I agree with Mirkwood - this is disaster. Paint event will be raised again during Doevents.
But I don't think he is entering his paint loop again while in a loop.
My example where I was forced to use End is in Form, not in UserControl. It is controlled loop, which checks for existence of a file. There is no reentering the loop. Doevents is in loop to allow user pressing "Exit" or "Quit" button.
When button is pressed, I have to unload form and use End or ExitProcess.
I described how I solved problem, but this is for "in house use" util, and I didn't look for better solution because it worked.
I will see if I can use Mirkwoods' "Timer" solution.
ASKER
Thanks for the suggestions. As it turns out when I used the member variable idea ameba suggested I found out it is not throwing the exception when in the DoEvents. I have not yet figured out how to tell where the exception is coming from. Since these are good suggestions, I'll close this and keep trying to figure out where the exception is coming from.
And what does AfxLockApp do?