experchange > vb.* > vb.general.discussion

Jasper (11-15-19, 06:38 PM)
I need a proper wait routine.
One that I can set a dwell time.

Main app starts some long process in an ActiveX.EXE.
The Main App waits for the ActiveX.EXE to complete or times out if it
takes too long.
The ActiveX.EXE raises an Event when completed.

What is the proper way to do this so that the Main app is aparently
released to the user for mouse and keyboard user events.

I seem to think I read that using DoEvents was not a good idea and that
using Sleep for long delays freezes my app.

The following is a bad example probably but this is what I now know.
So please provide improvements to it.

(air code)
Do While lCount < lDelayCount
DoEvents
Sleep lSleep_mSec
lCount = lCount + 1
If bExit then Exit Do
Loop

bExit is set by an external ActiveX.EXE event.
lSleep_mSec the dwell time is programmable
lDelayCount (combined with lSleep_mSec which should be short) is such
that it may be a very short wait or a very long wait on anything in
between.

Other I have seen

Has no Sleep and pounds DoEvents
Public Sub delay(PauseTime as integer)
Dim start As single
start = Timer
Do While Timer < start + PauseTime
If (Timer < start) Then ' midnight crossover
start = start - (86400 + 1)
End If
DoEvents ' Yield to other processes.

Loop
End Sub

I seem to remember that there are API calls to monitor if the mouse or
keyboard is being used so that only then the DoEvents or whatever will
be executed.

What are those APIs ?

Suggestion, links or samples please.
Code needs to allow the user to interact with the app while the Wait
routine is waiting.
ObiWan (11-15-19, 06:58 PM)
:: On Fri, 15 Nov 2019 08:38:32 -0800
:: (microsoft.public.vb.general.discussion)
:: <qqmka9$vrg$1>
:: Jasper <Jasper> wrote:

> I need a proper wait routine.
> One that I can set a dwell time.


Skipping the other stuff, may be added at a later time, the basic is

Private Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMillisec As Long)

Public Sub GiveTime(Optional ByVal lMilliSec As Long = 0)
Dim fTasks As Single
Dim lMouse As Long
lMouse = Screen.MousePointer
fTasks = DoEvents()
Call Sleep(lMilliSec)
DoEvents
Screen.MousePointer = lMouse
End Sub

the above will save the mouse pointer (since the doevents will change
it), leave time to other VB tasks, wait for the desired time (or just
leave time to other system processes), call the DoEvents again, but
this time as a "sub" and then restore the mouse pointer and return,
nothing special but should achieve what you asked for, then willing to
only "give time" in case there's some pending event, you may check your
process input queue for whatever user event (key press, mouse click)
but before doing that, try the above "as is", for example

GiveTime 75

will give out 75 milliseconds which is quite enough to keep your GUI
active and responsive, calling the function w/o parameters will result
in a "0" wait time and will act more or less like a "DoEvents"
Arne Saknussemm (11-15-19, 07:05 PM)
:: On Fri, 15 Nov 2019 17:58:20 +0100
:: (microsoft.public.vb.general.discussion)
:: <20191115175820.000055cb>
:: ObiWan <obiwan> wrote:

> only "give time" in case there's some pending event, you may check
> your process input queue for whatever user event (key press, mouse
> click)


forgot, here is how to check if there's a pending event so that you may
call the "GiveTime" to leave time for processing the request/event

Declare Function GetQueueStatus Lib "user32" _
(ByVal dwFlag As Long) As Long

Public Function GotEvent()
GotEvent = False
If GetQueueStatus(255) <> 0 Then
GotEvent = True
End If
End Function

so that you may do something like

If GotEvent() Then
GiveTime(75)
End If
David Youngblood (11-16-19, 06:01 PM)
> "Jasper" wrote in message news:vrg1
> I need a proper wait routine.
> One that I can set a dwell time.


Take a look at the MsgWaitForMultipleObjects, this is basically what's it's
for. You create an event, pass the event and time interval to the the API
and the delay will end on which ever occurs first (event or timeout). It is
a little more complicated than that though, you have to put it in a Do Loop
and restart on all OTHER events. You continue the Do Loop until the API
return value is either WAIT_OBJECT_0 (event triggered) or WAIT_TIMEOUT. I
use a procedure based on this that is both cancelable and resettable, and
that can provide a delay up to ~ 3.1 days

David
Larry Serflaten (11-16-19, 10:57 PM)
Jasper wrote:
> I need a proper wait routine.
> One that I can set a dwell time.
> Main app starts some long process in an ActiveX.EXE.
> The Main App waits for the ActiveX.EXE to complete or times out if it
> takes too long.
> The ActiveX.EXE raises an Event when completed.
> What is the proper way to do this so that the Main app is aparently
> released to the user for mouse and keyboard user events.


I guess I am not seeing this like the others.

I was thinking you can just use a Timer in the main app
(on a hidden form or no) and mark the time you launch the
AX exe app, plus kick off the timer to fire every quarter
second or so. If you do not get your finished event in
the appropriate amount of time, you kill the timer and treat
it as timed out. Otherwise, when you get the finished event
you kill the timer and continue.

LFS
Jim Mack (11-17-19, 01:31 PM)
On 11/16/2019 3:57 PM, Larry Serflaten wrote:
> Jasper wrote:
> I guess I am not seeing this like the others.
> I was thinking you can just use a Timer in the main app
> (on a hidden form or no) and mark the time you launch the
> AX exe app, plus kick off the timer to fire every quarter
> second or so. If you do not get your finished event in
> the appropriate amount of time, you kill the timer and treat
> it as timed out. Otherwise, when you get the finished event
> you kill the timer and continue.
> LFS


Another possibility: have the AX EXE raise a 'progress' event every N
mSec. In the main app, increment a counter when this event occurs (and
maybe display progress in some way... spin a wheel 1/4 turn, etc). If
the 'done' event doesn't occur within N ticks, you've timed out.
ObiWan (11-18-19, 01:44 PM)
:: On Fri, 15 Nov 2019 08:38:32 -0800
:: (microsoft.public.vb.general.discussion)
:: <qqmka9$vrg$1>
:: Jasper <Jasper> wrote:

> I seem to remember that there are API calls to monitor if the mouse
> or keyboard is being used so that only then the DoEvents or whatever
> will be executed.


see below; the code exposes two functions, one allows to detect if
there's a pending input event, the other to release time so that the
paint and other stuff will take place as needed; in the code below the
"GetQueueStatus" call doesn't consider mousemove events since I don't
think you'll need it in your case, but it's easy to modify the flags in
case you need them; for further informations about the flags and their
meaning, see



then, in your code you may have something like
dtLast = Now
While (yourLoopConditions)
If CheckEvent() Then
GiveTime 5
dtLast = Now
Else
If DateDiff("s", dtLast, Now) > 10
GiveTime 75
dtLast = Now
End If
End If
Wend

so that, in case there's a pending event you'll release time to allow
proper processing, otherwise the code will release time at intervals to
avoid wasting CPU cycles with a too "strict" wait loop

' base event flags
Private Const QS_KEY = &H0001
Private Const QS_MOUSEMOVE = &H0002
Private Const QS_MOUSEBUTTON = &H0004
Private Const QS_POSTMESSAGE = &H0008
Private Const QS_TIMER = &H0010
Private Const QS_PAINT = &H0020
Private Const QS_SENDMESSAGE = &H0040
Private Const QS_HOTKEY = &H0080
Private Const QS_ALLPOSTMESSAGE = &H0100
Private Const QS_RAWINPUT = &H0400

' combined event flags
Private Const QS_MOUSE (QS_MOUSEMOVE + QS_MOUSEBUTTON)

Private Const QS_INPUT (QS_MOUSE + QS_KEY + QS_RAWINPUT)

Private Const QS_ALLEVENTS (QS_INPUT + QS_POSTMESSAGE + _
QS_TIMER + QS_PAINT + QS_HOTKEY)

Private Const QS_ALLINPUT (QS_INPUT + QS_POSTMESSAGE + _
QS_TIMER + QS_PAINT + _
QS_HOTKEY + QS_SENDMESSAGE)

' APIs
Private Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMillisec As Long)
Private Declare Function GetQueueStatus Lib "user32" _
(ByVal dwFlag As Long) As Long

' true if there's a pending event
Public Function CheckEvent()
Dim lFlags As Long
Dim bRet As Boolean
lFlags = QS_KEY + QS_MOUSEBUTTON + QS_POSTMESSAGE + QS_TIMER + _
QS_PAINT + QS_SENDMESSAGE + QS_HOTKEY
bRet = False
If GetQueueStatus(lFlags) <> 0 Then
bRet = True
End If
CheckEvent = bRet
End Function

' waits and/or release time
Public Sub GiveTime(Optional ByVal lMilliSec As Long = 0)
Dim fTasks As Single
Dim lMouse As Long
lMouse = Screen.MousePointer
fTasks = DoEvents()
Call Sleep(lMilliSec)
DoEvents
Screen.MousePointer = lMouse
End Sub
ObiWan (11-18-19, 01:46 PM)
>

notice that an alternative to the above call may be



in such a case, you won't need flags and will just get a bool telling
you if there are pending events (kbd or mouse clicks)
ObiWan (11-18-19, 02:03 PM)
:: On Sun, 17 Nov 2019 06:31:26 -0500
:: (microsoft.public.vb.general.discussion)
:: <ZpmdnaPeObQVskzAnZ2dnUU7-KnNnZ2d>
:: Jim Mack <no-ube-uce> wrote:

> Another possibility: have the AX EXE raise a 'progress' event every N
> mSec. In the main app, increment a counter when this event occurs
> (and maybe display progress in some way... spin a wheel 1/4 turn,
> etc). If the 'done' event doesn't occur within N ticks, you've timed
> out.


Yes, that's another approach, the OP focused on the "polling" one,
which may be ok but will just "waste" time, while the event driven
async approach is usually more efficient; in such a case the external
AX may expose a "Working" event which may be fired at regular intervals
(say timer driven) to tell the main app it's still alive and working;
another good idea may be exposing the following events

Starting(vID) tells us that the AX is starting, the ID
may be useful in case we have multiple AX

Working(bCancel) fired at regular intervals to signal that
the AX is working, setting bCancel to true
will tell the AX to terminate operations

Cancelled() fired if operation cancelled

Progress(nCurr, nTot) operation progress with current value and
total limit (if available), fired when the
progress changes

Terminated(vID) operations terminated, also fired after
the cancelled event

Error(nErr, sErr) reports an error number/description, the
Cancelled/Terminated events may follow in
case it's a critical error
Similar Threads