Solved

Closing while in DoEvents causes exception

Posted on 1998-10-29
13
450 Views
Last Modified: 2013-12-26
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
0
Comment
Question by:skin
  • 7
  • 5
13 Comments
 
LVL 15

Expert Comment

by:ameba
ID: 1488038
paint loop with DoEvents? Can we see this portion of code, and where did you put it.
And what does AfxLockApp do?
0
 

Author Comment

by:skin
ID: 1488039
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

0
 
LVL 15

Expert Comment

by:ameba
ID: 1488040
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
0
PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

 
LVL 15

Expert Comment

by:ameba
ID: 1488041
Sorry, my comment was added before I saw your code. I will read it in a moment.
0
 

Author Comment

by:skin
ID: 1488042
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.  
0
 

Author Comment

by:skin
ID: 1488043
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.  
0
 

Author Comment

by:skin
ID: 1488044
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.  
0
 
LVL 15

Expert Comment

by:ameba
ID: 1488045
OK. Can you try the second (mExecuting flag)
0
 
LVL 15

Expert Comment

by:ameba
ID: 1488046
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

0
 
LVL 15

Expert Comment

by:ameba
ID: 1488047
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

0
 
LVL 13

Accepted Solution

by:
Mirkwood earned 200 total points
ID: 1488048
DOEVENTS == CRASH!!!

This is just a fact. Show me in an app that does doevents where it does doevents and I can make it crash.

DoEvents causes VB to stop what it is doing and go into the messageloop again. DoEvents basically equals TranslateMessage and DispatchMessage. Would you as a C programmer ever use that in a C application? I don't think so.
DoEvents causes looping of events and reentrency of code.

DoEvents can always be removed by starting a timer with a delay of one. In your case

private sub form_paint
     if (not m_bInPaint) then  'prevent reentrancy
           m_bInPaint = true
           m_iPainting = 1
           timerpaint.enabled = true
     end if
end sub

private sub timerpaint_timer
   if (m_iPainting <= m_nPagesInOpenDoc) then
        PaintOpenDoc  m_iPainting
        m_iPainting = m_iPainting + 1
   else
        timerpaint.enabled = false
        m_bInPaint =false
   end if
end sub

0
 
LVL 15

Expert Comment

by:ameba
ID: 1488049
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.
0
 

Author Comment

by:skin
ID: 1488050
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.  
0

Featured Post

Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Have you ever wanted to restrict the users input in a textbox to numbers, and while doing that make sure that they can't 'cheat' by pasting in non-numeric text? Of course you can do that with code you write yourself but it's tedious and error-prone …
You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question