Best way to wait politely 
Author Message
 Best way to wait politely

I have a function that calls a lengthy external process in a loop as
many times as required.  Each time before calling the lengthy process
there is some setup work which must be done.  Then, while the lengthy
process is running, there is also work which can be done to prepare
for the next run.

So the function (in pure air code) looks something like this

Do While lngCnt < lngRequired
    lngCnt = lngCnt + 1

    'Prepare values for processing
    '...
    '...

    lngAppPID = Shell("LongRunningprocess.exe")

    'Do some house keeping while the process is running

    Prepare for the next run

    'Wait for process (started by shell) to complete
    Do While ProcessIsRunning(lngAppPID)
        DoEvents
    Loop
Loop

Question is, how do I wait politely?  I know I can simply do a
Doevents loop waiting for the lngAppPID, returned from shell, to no
longer exist (as shown in the air code above), but that seems a bit
brutish.  Is there a way to wait for the process to complete without
tying up my app.  I am familiar with the ShellAndWait examples that
essentially make the call to Shell a synchronous call, but that is not
what I need here.  I need to shell (asynchronously), do some work
while the shelled app is running and then (assuming I finish my work
before the shelled app exits) wait for the shelled app to exit.

thanks,
Steve



Mon, 16 Jan 2012 09:17:34 GMT  
 Best way to wait politely

Quote:

> I have a function that calls a lengthy external process in a loop as
> many times as required.  Each time before calling the lengthy
> process there is some setup work which must be done.  Then, while
> the lengthy process is running, there is also work which can be
> done to prepare for the next run.

This cries out for threading, but that's not trivial in VB.

One relatively simple way (depending on how tightly coupled the
external function is), would be to call the function from an ActiveX
EXE -- an out of process component.

Your main app can invoke the AX EXE, which can use a timer to kick off
the external function and return to the caller (you) immediately. When
processing is done, it can notify you by signaling an event that
you're waiting on / polling.

--
        Jim

Quote:

> So the function (in pure air code) looks something like this

> Do While lngCnt < lngRequired
>     lngCnt = lngCnt + 1

>     'Prepare values for processing
>     '...
>     '...

>     lngAppPID = Shell("LongRunningprocess.exe")

>     'Do some house keeping while the process is running

>     Prepare for the next run

>     'Wait for process (started by shell) to complete
>     Do While ProcessIsRunning(lngAppPID)
>         DoEvents
>     Loop
> Loop

> Question is, how do I wait politely?  I know I can simply do a
> Doevents loop waiting for the lngAppPID, returned from shell, to no
> longer exist (as shown in the air code above), but that seems a bit
> brutish.  Is there a way to wait for the process to complete without
> tying up my app.  I am familiar with the ShellAndWait examples that
> essentially make the call to Shell a synchronous call, but that is
> not what I need here.  I need to shell (asynchronously), do some
> work while the shelled app is running and then (assuming I finish
> my work before the shelled app exits) wait for the shelled app to
> exit.

> thanks,
> Steve



Mon, 16 Jan 2012 09:34:11 GMT  
 Best way to wait politely

Quote:
> I have a function that calls a lengthy external process in a loop as
> many times as required. ?Each time before calling the lengthy process
> there is some setup work which must be done. ?Then, while the lengthy
> process is running, there is also work which can be done to prepare
> for the next run.

> So the function (in pure air code) looks something like this

> Do While lngCnt < lngRequired
> ? ? lngCnt = lngCnt + 1

> ? ? 'Prepare values for processing
> ? ? '...
> ? ? '...

> ? ? lngAppPID = Shell("LongRunningprocess.exe")

> ? ? 'Do some house keeping while the process is running

> ? ? Prepare for the next run

> ? ? 'Wait for process (started by shell) to complete
> ? ? Do While ProcessIsRunning(lngAppPID)
> ? ? ? ? DoEvents
> ? ? Loop
> Loop

> Question is, how do I wait politely? ?I know I can simply do a
> Doevents loop waiting for the lngAppPID, returned from shell, to no
> longer exist (as shown in the air code above), but that seems a bit
> brutish. ?Is there a way to wait for the process to complete without
> tying up my app. ?I am familiar with the ShellAndWait examples that
> essentially make the call to Shell a synchronous call, but that is not
> what I need here. ?I need to shell (asynchronously), do some work
> while the shelled app is running and then (assuming I finish my work
> before the shelled app exits) wait for the shelled app to exit.

> thanks,
> Steve

My experience with the sleep() API function seemed to indicate that it
slowed down the system and caused gridlock. In other words, too much
sleeping had a negative effect on other applications. Less sleeping
wouldn't have less of an effect, but still not be good for the
system.

 See this thread:

http://groups.google.com/group/microsoft.public.vb.winapi/browse_thre...



Mon, 16 Jan 2012 09:38:18 GMT  
 Best way to wait politely



Quote:
> Question is, how do I wait politely?

Take a look at the MsgWaitForMultipleObjects-API -
and wait for the Process-Handle of your externally
shelled process - this function will give you different
return-values (in case of expired TimeOut-intervals,
the finished ProcessHandle - or in case of a received
WinMessage, which you would have to "serve" with
an appropriate DoEvents then.

Olaf



Mon, 16 Jan 2012 09:53:41 GMT  
 Best way to wait politely

Quote:

> > I have a function that calls a lengthy external process in a loop as
> > many times as required. ?Each time before calling the lengthy
> > process there is some setup work which must be done. ?Then, while
> > the lengthy process is running, there is also work which can be
> > done to prepare for the next run.

> This cries out for threading, but that's not trivial in VB.

> One relatively simple way (depending on how tightly coupled the
> external function is), would be to call the function from an ActiveX
> EXE -- an out of process component.

> Your main app can invoke the AX EXE, which can use a timer to kick off
> the external function and return to the caller (you) immediately. When
> processing is done, it can notify you by signaling an event that
> you're waiting on / polling.

> --
> ? ? ? ? Jim

> > So the function (in pure air code) looks something like this

> > Do While lngCnt < lngRequired
> > ? ? lngCnt = lngCnt + 1

> > ? ? 'Prepare values for processing
> > ? ? '...
> > ? ? '...

> > ? ? lngAppPID = Shell("LongRunningprocess.exe")

> > ? ? 'Do some house keeping while the process is running

> > ? ? Prepare for the next run

> > ? ? 'Wait for process (started by shell) to complete
> > ? ? Do While ProcessIsRunning(lngAppPID)
> > ? ? ? ? DoEvents
> > ? ? Loop
> > Loop

> > Question is, how do I wait politely? ?I know I can simply do a
> > Doevents loop waiting for the lngAppPID, returned from shell, to no
> > longer exist (as shown in the air code above), but that seems a bit
> > brutish. ?Is there a way to wait for the process to complete without
> > tying up my app. ?I am familiar with the ShellAndWait examples that
> > essentially make the call to Shell a synchronous call, but that is
> > not what I need here. ?I need to shell (asynchronously), do some
> > work while the shelled app is running and then (assuming I finish
> > my work before the shelled app exits) wait for the shelled app to
> > exit.

> > thanks,
> > Steve- Hide quoted text -

> - Show quoted text -

Actually the shell call is in an ActiveX out of process server.  I
fail to see how this resolves my problem though.  When the ActiveX
server signals (via an event) that the shelled process has terminated
I still need to resume processing where I left off...inside the loop.
So I still will end up sitting in a Doevents loop at the bottom of the
loop waiting on that event.

Am I missing something here?

Thanks,
Steve



Mon, 16 Jan 2012 11:07:21 GMT  
 Best way to wait politely

Quote:

> > Question is, how do I wait politely?

> Take a look at the MsgWaitForMultipleObjects-API -
> and wait for the Process-Handle of your externally
> shelled process - this function will give you different
> return-values (in case of expired TimeOut-intervals,
> the finished ProcessHandle - or in case of a received
> WinMessage, which you would have to "serve" with
> an appropriate DoEvents then.

> Olaf

This looks promising.  I do not have much experience with Windows wait
functions.  Can you tell me what my applications does during this wait
period?  Is it dead as though I had called Sleep? or does it respond
to user input and other events?

Thanks,
Steve



Mon, 16 Jan 2012 11:15:39 GMT  
 Best way to wait politely
What Jim said.

If you don't want to be that elegant I'd suggest adding a Sleep statement in
the DoEvents loop.  Some environments will be dragged down with the simple
DoEvents loop.  You'll  particularly run into that on some terminal services
environments.

Dan


I have a function that calls a lengthy external process in a loop as
many times as required.  Each time before calling the lengthy process
there is some setup work which must be done.  Then, while the lengthy
process is running, there is also work which can be done to prepare
for the next run.

So the function (in pure air code) looks something like this

Do While lngCnt < lngRequired
    lngCnt = lngCnt + 1

    'Prepare values for processing
    '...
    '...

    lngAppPID = Shell("LongRunningprocess.exe")

    'Do some house keeping while the process is running

    Prepare for the next run

    'Wait for process (started by shell) to complete
    Do While ProcessIsRunning(lngAppPID)
        DoEvents
    Loop
Loop

Question is, how do I wait politely?  I know I can simply do a
Doevents loop waiting for the lngAppPID, returned from shell, to no
longer exist (as shown in the air code above), but that seems a bit
brutish.  Is there a way to wait for the process to complete without
tying up my app.  I am familiar with the ShellAndWait examples that
essentially make the call to Shell a synchronous call, but that is not
what I need here.  I need to shell (asynchronously), do some work
while the shelled app is running and then (assuming I finish my work
before the shelled app exits) wait for the shelled app to exit.

thanks,
Steve



Mon, 16 Jan 2012 11:35:09 GMT  
 Best way to wait politely
Sorry, rereading this I think I wasn't specific enough regarding the
terminal services situation.

By "dragged down" I mean that your app can/will heavily load the server even
though it's doing nothing.  A few users each with apps doing just a
"doevents wait" can bring a server to it's knees.  Adding a short Sleep will
make a big difference in server loading.

Dan


Quote:
> What Jim said.

> If you don't want to be that elegant I'd suggest adding a Sleep statement
> in the DoEvents loop.  Some environments will be dragged down with the
> simple DoEvents loop.  You'll  particularly run into that on some terminal
> services environments.

> Dan



> I have a function that calls a lengthy external process in a loop as
> many times as required.  Each time before calling the lengthy process
> there is some setup work which must be done.  Then, while the lengthy
> process is running, there is also work which can be done to prepare
> for the next run.

> So the function (in pure air code) looks something like this

> Do While lngCnt < lngRequired
>    lngCnt = lngCnt + 1

>    'Prepare values for processing
>    '...
>    '...

>    lngAppPID = Shell("LongRunningprocess.exe")

>    'Do some house keeping while the process is running

>    Prepare for the next run

>    'Wait for process (started by shell) to complete
>    Do While ProcessIsRunning(lngAppPID)
>        DoEvents
>    Loop
> Loop

> Question is, how do I wait politely?  I know I can simply do a
> Doevents loop waiting for the lngAppPID, returned from shell, to no
> longer exist (as shown in the air code above), but that seems a bit
> brutish.  Is there a way to wait for the process to complete without
> tying up my app.  I am familiar with the ShellAndWait examples that
> essentially make the call to Shell a synchronous call, but that is not
> what I need here.  I need to shell (asynchronously), do some work
> while the shelled app is running and then (assuming I finish my work
> before the shelled app exits) wait for the shelled app to exit.

> thanks,
> Steve



Mon, 16 Jan 2012 12:00:55 GMT  
 Best way to wait politely
You basically need some multi-threading in order to wait (one one thread)
for process completion while working (on another thread) to prepare for the
next run.  Ideally both would be on background threads, allowing your GUI to
remain responsive.

Slight problem - VB6 is very thread UN-friendly.  If you're using VB5 you
can still utilise the CreateThread API call, but later service packs for the
msvbvm60.dll runtime prevented you from using that particularly useful API,
thus limiting VB6 to single threaded operations.

Alternatively, you could use COM interop with a VB.NET DLL and leverage the
threading capabilities of the .NET Framework, but depending on your
resources this may not be trivial either.


I have a function that calls a lengthy external process in a loop as
many times as required.  Each time before calling the lengthy process
there is some setup work which must be done.  Then, while the lengthy
process is running, there is also work which can be done to prepare
for the next run.

So the function (in pure air code) looks something like this

Do While lngCnt < lngRequired
    lngCnt = lngCnt + 1

    'Prepare values for processing
    '...
    '...

    lngAppPID = Shell("LongRunningprocess.exe")

    'Do some house keeping while the process is running

    Prepare for the next run

    'Wait for process (started by shell) to complete
    Do While ProcessIsRunning(lngAppPID)
        DoEvents
    Loop
Loop

Question is, how do I wait politely?  I know I can simply do a
Doevents loop waiting for the lngAppPID, returned from shell, to no
longer exist (as shown in the air code above), but that seems a bit
brutish.  Is there a way to wait for the process to complete without
tying up my app.  I am familiar with the ShellAndWait examples that
essentially make the call to Shell a synchronous call, but that is not
what I need here.  I need to shell (asynchronously), do some work
while the shelled app is running and then (assuming I finish my work
before the shelled app exits) wait for the shelled app to exit.

thanks,
Steve



Mon, 16 Jan 2012 13:02:14 GMT  
 Best way to wait politely

Quote:


>>> I have a function that calls a lengthy external process in a loop
>>> as many times as required. Each time before calling the lengthy
>>> process there is some setup work which must be done. Then, while
>>> the lengthy process is running, there is also work which can be
>>> done to prepare for the next run.

>> This cries out for threading, but that's not trivial in VB.

>> One relatively simple way (depending on how tightly coupled the
>> external function is), would be to call the function from an
>> ActiveX EXE -- an out of process component.

>> Your main app can invoke the AX EXE, which can use a timer to kick
>> off the external function and return to the caller (you)
>> immediately. When processing is done, it can notify you by
>> signaling an event that you're waiting on / polling.

> Actually the shell call is in an ActiveX out of process server.  I
> fail to see how this resolves my problem though.  When the ActiveX
> server signals (via an event) that the shelled process has
> terminated I still need to resume processing where I left
> off...inside the loop. So I still will end up sitting in a Doevents
> loop at the bottom of the loop waiting on that event.

> Am I missing something here?

Rather than thinking of the tasks to be done as a loop, think of it as
a list. You know your position in the list when you make the external
call, so you can 'bookmark' there.

Make the call, and on (immediate) return, prepare for the next call
and simply exit the function. When you're signalled, enter the
function again using the bookmarked index.

--
        Jim



Mon, 16 Jan 2012 20:06:45 GMT  
 Best way to wait politely

Quote:

> > Am I missing something here?

> Rather than thinking of the tasks to be done as a loop, think of it as
> a list. You know your position in the list when you make the external
> call, so you can 'bookmark' there.

> Make the call, and on (immediate) return, prepare for the next call
> and simply exit the function. When you're signalled, enter the
> function again using the bookmarked index.

I think I am starting to get what you are saying but I still can not
quite get my mind around it.  Could you please post a small pseudo-
code sample to illustrate this concept.

Thanks,
Steve



Mon, 16 Jan 2012 20:47:02 GMT  
 Best way to wait politely


Quote:
> > Am I missing something here?

I think I am starting to get what you are saying but I still can not
quite get my mind around it.  Could you please post a small pseudo-
code sample to illustrate this concept.
---------------

If you have something like:

  Do While Looping
        ' Prep code
        ' Call to Shell
        'Wait if not Done
 Loop

You can think of it wrapped in a routine:

  Do While Looping
    Looping = ShellRoutine()
  Loop

Where ShellRoutine has all the grunt work code.
Then its a matter of substituting an event for the looping process

Sub Timer1_Timer()
  Timer1.Enabled = False
  AX_Event()
End Sub

Sub AX_Event()
  Timer1.Enabled = ShellRoutine()
End Sub

When you want to start the process, enable the timer.
The timer is used to allow the call stack of AX_Event to
conclude, avoiding a stack overflow if it just called the routine
directly (some large number of times).

Done that way, your app is in the input idle state while waiting.

HTH
LFS



Mon, 16 Jan 2012 22:53:54 GMT  
 Best way to wait politely
Dan Appleman has written a nice article about using state machines, I
think it could be useful. (Section "long syncronous operations".)

http://www.desaware.com/tech/statemachineintro.aspx



Tue, 17 Jan 2012 01:19:18 GMT  
 Best way to wait politely



Quote:
> > Take a look at the MsgWaitForMultipleObjects-API -
> This looks promising.  I do not have much experience
> with Windows wait functions.
> Can you tell me what my applications does during this wait
> period?  Is it dead as though I had called Sleep?
> or does it respond to user input and other events?

Sorry for the late reply...

Yes, it can respond to user-input during the wait -
the MsgWaitForMultipleObjects returns (in case you
specified the appropriate Flags) as soon as there's
Input in the Apps MsgQueue - just look at the following
Code-example...

It's not "production-quality-code"  - but you should
get the idea.

'***Into a Form
Option Explicit

Private Type PROCESS_INFORMATION
  hProcess As Long
  hThread As Long
  dwProcessID As Long
  dwThreadId As Long
End Type

Private Type StartupInfo
  cb As Long
  lpReserved As String
  lpDesktop As String
  lpTitle As String
  dwX As Long
  dwY As Long
  dwXSize As Long
  dwYSize As Long
  dwXCountChars As Long
  dwYCountChars As Long
  dwFillAttribute As Long
  dwFlags As Long
  wShowWindow As Integer
  cbReserved2 As Integer
  lpReserved2 As Long
  hStdInput As Long
  hStdOutput As Long
  hStdError As Long
End Type

Private Const QS_ALLINPUT As Long = &H4FF
Private Declare Function MsgWaitForMultipleObjects& Lib "user32" _
  (ByVal nCount&, pHandles&, ByVal fWaitAll&, ByVal dwMilliseconds&, _
   ByVal dwWakeMask&)
Private Declare Function CreateProcessA& Lib "kernel32" _
  (ByVal AppName&, ByVal CommandLine$, ByVal ProcAttr&, _
   ByVal ThrAttr&, ByVal InheritHdls&, ByVal CreationFlags&, _
   ByVal Env&, ByVal CurDir&, StartupInfo As StartupInfo, _
   ProcessInformation As PROCESS_INFORMATION)
Private Declare Function TerminateProcess& Lib "kernel32" _
  (ByVal hProcess&, ByVal uExitCode&)
Private Declare Function CloseHandle& Lib "kernel32" (ByVal hObj&)



Private WithEvents Cmd As CommandButton

Private Sub Form_Load()
  AutoRedraw = True
  Set Cmd = Controls.Add("VB.CommandButton", "Cmd")
  Cmd.Visible = True
  Cmd.Caption = "shell notepad"
  Print: Print: Print 'only to shift Form-printouts below the Button
End Sub

Private Sub Cmd_Click()
Dim T#, B() As Byte
  T = HPTimer
    Select Case ShellAndWait("NotePad.exe", 5)
      Case 0: Print "couldn't start process"
      Case 1: Print "success, process finished within the Tout-interval"
      Case 2: Print "process hard closed (not finished within Tout-Interv.)"
    End Select
  Caption = HPTimer - T
End Sub

Public Function ShellAndWait(cmdLine$, ByVal TimeOutSeconds#) As Long
Dim Proc As PROCESS_INFORMATION, Start As StartupInfo, T#

  Start.cb = Len(Start)
  CreateProcessA 0&, cmdLine, 0&, 0&, 1&, &H20, 0&, 0&, Start, Proc
  If Proc.hProcess = 0 Then Exit Function

  T = HPTimer + TimeOutSeconds
  Dim Ret&
  Do
    Ret = MsgWaitForMultipleObjects(1, Proc.hProcess, 0, 50, QS_ALLINPUT)
    Select Case Ret
      Case 0: ShellAndWait = 1: Exit Do 'process finished within the Tout
      Case 1: DoEvents 'a win-message is in the queue, so let's process it
    End Select
  Loop Until HPTimer > T

  If HPTimer > T Then 'Process is yet running, but our timeout is over...
    TerminateProcess Proc.hProcess, 0 '...so we terminate it the hard way
    ShellAndWait = 2 'signalize "no success" (execution took too long)
  End If
  CloseHandle Proc.hProcess
End Function

Private Function HPTimer#()

  If Frq = 0 Then QueryPerformanceFrequency Frq
  If QueryPerformanceCounter(X) Then HPTimer = X / Frq
End Function

Olaf



Fri, 20 Jan 2012 00:33:43 GMT  
 
 [ 14 post ] 

 Relevant Pages 

1. dropdownlists and grids, which ways is the best?

2. good ways to use recordsets without autocommit?

3. Better ways to schedule?

4. good ways to use recordsets without autocommit?

5. Better ways to put text into textbox??

6. Waiting.......waiting.....waiting....

7. IE window won't close politely

8. best way to sleep or wait specified amount of time

9. Better wait procedure?

10. A good question...waiting for same answer!

11. How to wait for a form to unload WITHOUT busy waiting

12. A good, better, best idea

 

 
Powered by phpBB® Forum Software