?
Solved

How do I pause processing in VB6

Posted on 2010-01-11
7
Medium Priority
?
782 Views
Last Modified: 2012-06-21
I am writing multiple reports out to a PDF-XChange printer using the printer.print statements. I use the printer.EndDoc to close the report currently being written to and then immediately start printing to the next report. The PDF-Xchange printer is confiured to write the files out using the date, time and the username as a part of the filename, but what is happening is that the files are being written out with very little time in between each report, so the output files are having the same name, leading to the files overwriting each other. I want to be able to insert a wait or a pause between closing a report and starting on the next report so that the files don't get the same name and overwrite each other.
How can I insert a wait in VB6?
0
Comment
Question by:Butterfield_Cayman
[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
7 Comments
 
LVL 81

Accepted Solution

by:
zorvek (Kevin Jones) earned 2000 total points
ID: 26287188
The best way to pause code execution is to provide a mechanism that gives the parent application such as Excel or Word opportunities to handle events as well as other operating system tasks. The routine below provides both and allows a pause of as little as a hundredth of a second.

Note that the declaration of the Sleep API function has to be placed above all other routines in the module.

[Begin Code Segment]

Public Declare Sub Sleep Lib "kernel32" (ByVal Milliseconds As Long)

Public Sub Pause( _
      ByVal Seconds As Single, _
      Optional ByVal PreventVBEvents As Boolean _
   )

' Pauses for the number of seconds specified. Seconds can be specified down to
' 1/100 of a second. The Windows Sleep routine is called during each cycle to
' give other applications time because, while DoEvents does the same, it does
' not wait and hence the VB loop code consumes more CPU cycles.

   Const MaxSystemSleepInterval = 25 ' milliseconds
   Const MinSystemSleepInterval = 1 ' milliseconds
   
   Dim ResumeTime As Double
   Dim Factor As Long
   Dim SleepDuration As Double
   
   Factor = CLng(24) * 60 * 60
   
   ResumeTime = Int(Now) + (Timer + Seconds) / Factor
   
   Do
      SleepDuration = (ResumeTime - (Int(Now) + Timer / Factor)) * Factor * 1000
      If SleepDuration > MaxSystemSleepInterval Then SleepDuration = MaxSystemSleepInterval
      If SleepDuration < MinSystemSleepInterval Then SleepDuration = MinSystemSleepInterval
      Sleep SleepDuration
      If Not PreventVBEvents Then DoEvents
   Loop Until Int(Now) + Timer / Factor >= ResumeTime
   
End Sub

[End Code Segment]

Note that the expression

   Int(Now) + Timer / Factor

is used to create a time that both handles midnight crossovers and is accurate to within 1/100 of a second. Just the Timer function alone is accurate to within 1/100 of a second but does not handle midnight crossovers. The Now function is only accurate to within about 1/4 of a second.

The DoEvents call is used to give the managed environment such as Excel or Word opportunities to handle events and do other work. But DoEvents only works within the managed environment and can still consume a considerable amount of resources without some other throttling mechanism. By also using the Windows Sleep API call the Windows operating system is given an opportunity to let other processes run. And, since the code is doing nothing but waiting, it is the appropriate thing to do.

Often the task involves waiting for an asynchronous task to complete such as a web query. To use the above routine while waiting for such a task to compete, two time durations are needed: the total amount of time to wait until it can be assumed that a failure has occurred in the other task, and the amount of time to wait between checks that the other task has completed. Determining how long to wait until giving up requires consideration of the longest possible time that the task could reasonably take and how long the user is willing to wait for that task to complete - wait too long and the user gets frustrated, don't wait long enough and the risk increases of falsely assuming an error occurred when it didn't. This duration is the more difficult to determine of the two. The second time, the duration between checks for completion, is easier to determine. This duration should be long enough to not consume unnecessary CPU cycles doing the check, but short enough to respond quickly when the status of the asynchronous task changes. A duration of between a quarter of a second and one second is usually reasonable. The sample code below illustrates how to wait for an asynchronous task to complete that usually finishes in less than 10 seconds.

   Dim TimeoutTime As Date
   TimeoutTime = Now() + TimeSerial(0, 0, 30) ' Allow 30 seconds for the asynchronous task to complete before assuming it failed
   Do While Now() < TimeoutTime And Not IsTaskComplete
      Pause 0.5 ' Pause half a second to allow the ashyncronous task (and the rest of the environment) to do work
   Loop

The above example uses a function named IsTaskComplete to determine if the asynchronous task completed. The function can do anything such as checking if a cell changed, checking if a control's property is set, or checking if a file exists.


Other techniques for pausing code execution and the problems with each are listed below. These should all be avoided in any well-designed application.

Wait Method (VBA only):

   Application.Wait Now() + TimeSerial(0, 0, 10)

The Wait method suspends all application activity and may prevent other operations from getting processing time while Wait is in effect. However, background processes such as printing and recalculation continue. The net effect of pausing using the Wait method is to shut down the application (e.g. Excel) event handling and slow or stop other applications. This method does not allow any fractional seconds to be used.

Windows Sleep:

   Public Declare Sub Sleep Lib "kernel32" (ByVal Milliseconds As Long)
   Sleep 10000

Using the Sleep Windows API call is system friendly by allowing all other processes to get processing time but it effectively shuts down the parent application. This is generally not a good idea as an application should always be responsive to user requests, even if the application is waiting for an asynchronous task to complete. Extended sleep periods can also cause problems when Windows is sending out system events such as system shut down notifications.

DoEvents Loop

   TimeoutTime = Now() + TimeSerial(0, 0, 10)
   Do
      DoEvents
   Loop Until Now > TimeoutTime

Performing a DoEvents loop to pause gives the parent application a chance to handle events but, because there is no pause between DoEvents calls, virtually all available processing time is dedicated to the loop and nothing else which means this is not a good way to pause code execution. This method does not allow any fractional seconds to be used.

Basic Loop without DoEvents

   TimeoutTime = Now() + TimeSerial(0, 0, 10)
   Do
   Loop Until Now > TimeoutTime

A tight loop without a DoEvents call effectively brings the workstation to a halt until the loop exits. This is the worst technique to pause code execution. This method does not allow any fractional seconds to be used.

There are other, more sophisticated, techniques that monitor event queues and other system resources but the net result is the same as a simple loop with both a DoEvents and a Sleep. As long as some other throttling mechanism is used such as the Windows Sleep function, DoEvents will consume very little resources as all it does is look for any pending events and then either processes those events or returns immediately to the caller.

Kevin
0
 
LVL 16

Expert Comment

by:HooKooDooKu
ID: 26288105
In all that Zorvek posted, he might have basically said the following, but for your purposes, it sounds like all you need is the 'Now' command, the sleep command, and Do Events.  After EndDoc, insert the following code:

Dim D1 as Date = Now
Do
    DoEvents
    Sleep( 100 )  'The sleep command Zorvek declared... 100 = 1/10th of a second
Loop While( DateDiff( D1, Now, "s") < 1 )


Now I might have the order of D1 and Now swapped, and the value of '1' assumes that the time used to name the files is in one second intervales.

But the basic idea is that after you've finished printing a document, you go into an infinite loop until the minimum time needed between jobs has passed to make sure the names are unique.

Process the 1st document.
After EndDoc, record the 'Now' time.
Before starting the next document, sit in an infinite loop doing Sleep commands, DoEvents, and checking the time...
Before you start a document (or perhaps the time stamp is based on when EndDoc is encountered), record the 'Now' time
0
 
LVL 81

Expert Comment

by:zorvek (Kevin Jones)
ID: 26288446
What Hoo... has conveniently omitted from his comments about my solution is that the routine I provided, Pause, is optimized to consume as few cycles as possible while providing the maximum time for other system tasks. It is presented in a form that requires the minimal amount of code to be written. With the routine in place, a pause of 1/4 second is as simple as:

   Pause .25

Once installed in your VBA project, you can use the Pause function from anywhere in the project. To install it, place the code below into any general code module.

Public Declare Sub Sleep Lib "kernel32" (ByVal Milliseconds As Long)

Public Sub Pause( _
      ByVal Seconds As Single, _
      Optional ByVal PreventVBEvents As Boolean _
   )

' Pauses for the number of seconds specified. Seconds can be specified down to
' 1/100 of a second. The Windows Sleep routine is called during each cycle to
' give other applications time because, while DoEvents does the same, it does
' not wait and hence the VB loop code consumes more CPU cycles.

   Const MaxSystemSleepInterval = 25 ' milliseconds
   Const MinSystemSleepInterval = 1 ' milliseconds
   
   Dim ResumeTime As Double
   Dim Factor As Long
   Dim SleepDuration As Double
   
   Factor = CLng(24) * 60 * 60
   
   ResumeTime = Int(Now) + (Timer + Seconds) / Factor
   
   Do
      SleepDuration = (ResumeTime - (Int(Now) + Timer / Factor)) * Factor * 1000
      If SleepDuration > MaxSystemSleepInterval Then SleepDuration = MaxSystemSleepInterval
      If SleepDuration < MinSystemSleepInterval Then SleepDuration = MinSystemSleepInterval
      Sleep SleepDuration
      If Not PreventVBEvents Then DoEvents
   Loop Until Int(Now) + Timer / Factor >= ResumeTime
   
End Sub

Pretty simple really.

Kevin
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 16

Expert Comment

by:HooKooDooKu
ID: 26288522
Of course if your application doesn't have an user interface that needs to respond to anything (that's the purpose of the DoEvents), just simply used the Sleep command (i.e. API function zorvek has already provided).

Basically, if the reports only have to be seperated by one second on the clock to ensure unique names, then simply add "Sleep( 1000 )" after EndDoc.   (Sleep will cause your application to do no processing for the time period specified in 1/1000th of a second increments, and would therefore be even more optimized that ANY code executing).

About the only thing that would not be optimized (using Sleep alone) would be the fact that if you only have to make sure the reports run on different one second intervals, it can make your program run faster to watch the clock so that if one report takes 3/4 of a second, after 1/4 of a second, your next report gets processed.  With the single line "Sleep" method, you will be adding a full one second (or what ever time period is needed) between each report.  Obviously if you have 10,000 reports, an extra 5,000 to 10,000 seconds makes a difference.  If you have only something like 120 reports, does it mater if the application takes an extra 2 minutes to execute?
0
 
LVL 81

Expert Comment

by:zorvek (Kevin Jones)
ID: 26288631
Visual Basic is a managed environment like Office applications and, as such, intercepts and handles all system events including user initiated events. This includes break requests (CTRL+SYSREQ). Using the Sleep command turns control over to the operating system and suspends all event processing in your application. If not used carefully, it can lock up your application even when debugging.

Kevin
0
 
LVL 13

Expert Comment

by:game-master
ID: 26289659


good morning!

u can use the Sleep API..


Declaration:
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)



how to use..
for example

Private Sub Form_Load()
   
    Sleep 5000
   
End Sub
0
 

Author Closing Comment

by:Butterfield_Cayman
ID: 31675723
i'm sure all the answers worked but this is the one i chose. thanks for the help.
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

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

There is an easy way, in .NET, to centralize the treatment of all unexpected errors. First of all, instead of launching the application directly in a Form, you need first to write a Sub called Main, in a module. Then, set the Startup Object to th…
Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
This tutorial will introduce the viewer to VisualVM for the Java platform application. This video explains an example program and covers the Overview, Monitor, and Heap Dump tabs.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
Suggested Courses

765 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