Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

VB6: How to abort a procedure that's taking too long

Posted on 2009-05-06
6
Medium Priority
?
834 Views
Last Modified: 2012-05-06
Dear Experts,

I am using a subroutine to shrink and antialias images. It works well in general, but on very large images it takes too long and in Windows Vista, this has caused freezing of the system.

I would like recommendations on the best way to abort a subroutine if it is taking longer than a specified number of seconds (I have experimented with using a timer and DoEvents command but so far I'm not satisfied).

Also, if anyone can recommend a very fast method of resizing with antialiasing, it would be very helpful.

Thank you!
0
Comment
Question by:ttobin333
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
6 Comments
 
LVL 16

Accepted Solution

by:
HooKooDooKu earned 1000 total points
ID: 24318780
Well, fundimentally speaking, once VB starts a subroutine, the only way to get the application to do anything other than run the subroutine to completion is to insert DoEvents.

But that's just the 1st part of the problem.  That's how to allow windows to respond to messages such as minimize the window, move the window, or process a timer event.

What you need in addition to DoEvents is an event that sets a flag that the subroutine tests for and aborts the subroutine when the flag is set.

As an example, here's the code I use within a Form that has a subroutine that needs to be terminated if the user clicks on an abort button.  The main keys are:
1. Flags to allow attempts to close the form to react like the abort button was clicked instead.
2. AbortProcess function that includes 'DoEvents' and returns the current Abort status
3. Abort Command Button that simply sets the Abort Flag (after user confirms abort)
4. Periodically calling the AbortProcess function during the long subroutine.

Option Explicit
 
Private m_Abort As Boolean  'Flag that Abort Button has been Clicked and Confirmed
'How should the X System Button be Treated
Private Enum enumXButton
    X_NA        'Has No Effect
    X_ABORT     'Like an Abort Button
    X_CLOSE     'Like a Cancel Button
End Enum
Dim m_X As enumXButton
 
'Has the Abort Button been Clicked (and confirmed)?
Public Function AbortProcess() As Boolean
    DoEvents
    AbortProcess = m_Abort
End Function
Private Sub cmdAbort_Click()
    Dim Reply As VbMsgBoxResult
    Reply = MsgBox("Abort Process?", vbQuestion + vbYesNo + vbDefaultButton2)
    If Reply = vbYes Then
        m_Abort = True
    End If
End Sub
Private Sub Form_Load()
    m_X = X_CLOSE
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
    Select Case m_X
        Case X_NA:      Cancel = 1
        Case X_ABORT:   Call cmdAbort_Click
                        Cancel = 1
        Case X_CLOSE:   'NOP - Allow Shutdown
    End Select
End Sub
 
'Now to code the really long subroutine
Private Sub SomeReallyLongProcess()
    'Initialize the Abort Flags
    m_Abort = False
    m_X = X_ABORT   'Makes any attempt to close the form react as if the Abort Button was clicked
 
    'Other intitilizing code...
 
    'The processing loop 
    Dim Index as Long
    For Index = 1 to 100000
        'Test for Abort - This single command can be sprinkled through out the processing loop
        if AbortProcess then Goto CloseAndExitSub
 
        'The rest of your processing logic goes here...
    Next I
 
CloseAndExitSub:
    m_X = X_CLOSE    'Reset how form reacts to a Close Command
    'Other common clean up code here...
End Sub

Open in new window

0
 
LVL 16

Expert Comment

by:HooKooDooKu
ID: 24318834
Additional though!

If all you are interested in doing is abort the subroutine if it runs too long, at the start of the subroutine, simply record the current system Date/Time.  Periodically, test how much time has elapsed, and abort the subroutine if too much time has passed.  (Note, I might have the order of the two dates in DateDiff backwards).
Private Sub SomeLongProcess()
    Dim StartTime as Date
 
    StartTime = Now
 
    Dim I as Long
    For I = 1 to 100000
        'Abort if Process has run longer than 10 seconds
        if DateDiff("s",StartTime,Now) > 10 Then Goto CloseAndExitSub
 
        'The rest of the process here
    Next I
 
CloseAndExitSub:
    'Cleanup code
End Sub

Open in new window

0
 
LVL 10

Assisted Solution

by:peetm
peetm earned 1000 total points
ID: 24325736
You don't need to use DoEvents - and you probably shouldn't, as you can easily check your message queue directly.  Certain messages are buffered in the process' message queue, and you simply access that to see what's waiting - like a critical key press.

I've attached a small routine from one of my old projects that sets a Global called Abort to true if the Esc key is hit/released.

Cheers
Public Function AbortCheck() As Boolean
 
    Dim Msg As Msg
 
    ' The improvement over using GetAsyncKeyState [IsKeyDown below] is that the check for the Esc key in
    ' GetAsyncKeyState will only work if the key is down when we call the function. By using the message
    ' queue, it doesn't matter when the key is pressed.
 
    If Not Screen.ActiveForm Is Nothing Then
    
        ' If we've a WM_KEYUP message in our queue: go and remove it.  NOTE - we ignore anything else.
        '
        Do While PeekMessage(Msg, Screen.ActiveForm.hWnd, WM_KEYUP, WM_KEYUP, PM_REMOVE)
        
            ' If the virtual keycode of the WM_KEYUP is VK_ESCAPE.
            '
            If Msg.wParam = VK_ESCAPE Then
            
                ' Flush the message queue of all keyboard messages.
                '
                Do While PeekMessage(Msg, Screen.ActiveForm.hWnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)
                
                    ' Nothing.
                    
                Loop
    
                Abort = True
                
                AbortCheck = Abort
            
            End If
        
        Loop
    
    End If
 
End Function

Open in new window

0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 16

Expert Comment

by:HooKooDooKu
ID: 24326572
@peetm
I'm curious as to why you say that you probably shouldn't use DoEvents?

From what I see, it looks like your AbortCheck() is sort of like a special purpose DoEvents.  But rather than allowing the events to happen, it just ignores them as it looks for a specific event.  If so, that would seem to make an application look stuck because it looks like it's not responding to events (like Minimize the Window, Move the Window, refresh the window if something has been drawn on top of it).  But with DoEvents, the application will continue to be responsive to windows messages, allow for the testing of an abort condition, and continue processing the subroutine.
0
 
LVL 10

Expert Comment

by:peetm
ID: 24326865
>>I'm curious as to why you say that you probably shouldn't use DoEvents?


Simply because one cannot 'filter' what messages will be flushed, and sent to your app whenever it's called - this may lead to all manner of state changes that can really 'hurt'.

Yes, polling the message queue is like a filtering DoEvents - just what's needed!

>>If so, that would seem to make an application look stuck because it looks like it's not responding to events (like Minimize the Window, Move the Window, refresh the window if something has been drawn on top of it)

Not at all, in that I've used the same technique to allow moving/resizing/re-painting - all with absolute 'control', and without calling DoEvents.
0
 

Author Closing Comment

by:ttobin333
ID: 31578578
Thanks guys, both methods will be very useful in my toolbox!
0

Featured Post

Ask an Anonymous Question!

Don't feel intimidated by what you don't know. Ask your question anonymously. It's easy! Learn more and upgrade.

Question has a verified solution.

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

I’ve seen a number of people looking for examples of how to access web services from VB6.  I’ve been using a test harness I built in VB6 (using many resources I found online) that I use for small projects to work out how to communicate with web serv…
This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
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…
Suggested Courses

636 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