Can I implement timeout on VB6? - vb6

I wanted to know if there is an implement of timeout on VB6.
I have some function Do(), Can I call this method with timeout?
something like:
Call(Do, 5);
that will quit after 5 seconds.
Do() function is not my it so I can't change it.
Thanks!

Yes you can. You have to create a background worker, implement a sleep (5000) then terminate the background process. You can take a look here http://msdn.microsoft.com/en-us/library/aa719109(v=vs.71).aspx

Related

How do I handle exiting ScalaFX

I use java.util.Timer to run a method every 10th of a second.
I have to cancel this before exiting ScalaFX.
How do I accomplish this?
JFXApp has method stopApp that is called when the application stops. You can cancel your timer there.

How to call SetWaitableTimerEx correctly

We have a long standing bug report in Boost.Thread where apparently thread sleeps will wake the computer from sleep on timer elapse (https://svn.boost.org/trac/boost/ticket/11368). This is apparently due to the new use of SetWaitableTimerEx() to implement coalescing timer support which we call with a REASON_CONTEXT like this:
REASON_CONTEXT default_reason_context={0/*POWER_REQUEST_CONTEXT_VERSION*/, 0x00000001/*POWER_REQUEST_CONTEXT_SIMPLE_STRING*/, (LPWSTR)L"generic"};
If timer firing is causing the PC to wake from sleep, it surely must have something to do with this REASON_CONTEXT value.
Can anyone here tell us what the appropriate value to use to not have the PC wake from sleep on timer expiry?
According to this document from Microsoft: Windows Timer Coalescing, page 8-9:
SetWaitableTimerEx has two new parameters: WakeContext and TolerableDelay. You use the WakeContext parameter only when you set a timer that can wake the system from a sleep state.
It looks like passing NULL for the WakeContext parameter is fine and it's the only way SetWaitableTimerEx will not wake the system. Timer coalescing should still work.
I tried it in Windows 10 and it seems to work correctly. It doesn't wake the system and also doesn't look like it's just calling SetWaitableTimer. It could be different in older versions of Windows though, I haven't tested.

Efficient daemon in Vala

i'd like to make a daemon in Vala which only executes a task every X seconds.
I was wondering which would be the best way:
Thread.usleep() or Posix.sleep()
GLib.MainLoop + GLib.Timeout
other?
I don't want it to eat too many resources when it's doing nothing..
If you spend your time sleeping in a system call, there's won't be any appreciable difference from a performance perspective. That said, it probably makes sense to use the MainLoop approach for two reasons:
You're going to need to setup signal handlers so that your daemon can die instantaneously when it is given SIGTERM. If you call quit on your main loop by binding SIGTERM via Posix.signal, that's probably going to be a more readable piece of code than checking that the sleep was successful.
If you ever decide to add complexity, the MainLoop will make it more straight forward.
You can use GLib.Timeout.add_seconds the following way:
Timeout.add_seconds (5000, () => {
/* Do what you want here */
// Continue this "loop" every 5000 ms
return Source.CONTINUE;
// Or remove it
return Source.REMOVE;
}, Priority.LOW);
Note: The Timeout is set as Priority.LOW as it runs in background and should give priority to others tasks.

Timer Queues, immediately terminate a timer?

I'm trying to achieve high frame-per-second on Windows GDI by using Windows Timer Queues. The relevant APIs are CreateTimerQueue, DeleteTimerQueueEx, CreateTimerQueueTimer, and DeleteTimerQueueTimer .
The timer is created using CreateTimerQueueTimer(&m_timer, m_timer_queue, TimerCallback, this, 0, 20, WT_EXECUTEINTIMERTHREAD); to achieve some 50fps of speed. GDI operations (some painting in the backstore, plus InvalidateRect) cannot be asynchronous, therefore I can't choose other flags but WT_EXECUTEINTIMERTHREAD so that no extra sync op is required on the drawing code. The idea is to achieve 50fps when possible, and when it's not, just show each frame at the maximum possible speed.
At the end of the animation (reached a total frame count), DeleteTimerQueueTimer is called to destroy the timer.
The problem is that DeleteTimerQueueTimer doesn't immediately turn off the callings of the callback function. When it's not possible to achieve the 50fps requirement, the timer pumps the call into a queue. Calling DeleteTimerQueueTimer inside the callback function doesn't destroy the queue. As a result, the callback is still being called even though it decided to shutdown the timer.
How do I deal with this problem?
-
On another note, the old timeSetEvent / timeKillEvent multimedia API doesn't seem to have this problem. There are no queues and the calling of the callback function is immediately stopped when I call timeKillEvent. Is it possible to achieve the same behavior with timer queues?
You can pass the WT_EXECUTEONLYONCE flag to the CreateTimerQueueTimer function. This will cause the timer to trigger only once and not periodically.
You can then reschedule the timer with the ChangeTimerQueueTimer method.
To cover the times where your drawing takes too long too complete in the frame, you can add a CriticalSection to the beginning of the TimerHandler method, which will cause the 2nd timer to wait until the first one completes.
If you want to run something at 50fps+, you'd probably do better to actually just have a draw loop which computes the amount of time between frames and scales the animation accordingly. Timers aren't really meant to fire so often. So (and this would probably be in your Idle handler). Like, this pseudocode (ignore lack of error handling):
static longlong last_frame;
while(1) {
longlong current_frame = QueryPerformanceCounter();
long delta = current_frame - last_frame;
// Do drawing here, scale amount to move by how much time has elapsed
last_frame = current_frame;
}
DeleteTimerQueueTimer will cancel the timer provided it has not already been scheduled. (When you use WT_EXECUTEINTIMERTHREAD I believe they are queued as an APC on a thread from a thread pool shared by the timer queues and worker threads. ) If it has already been scheduled (not just running) - it will be run and the DeleteTimerQueueTimer call will block until completion.
If I understand your problem correctly, may I suggest the following?
1. Before calling DeleteTimerQueueTimer - set a flag say abortAllTimers to true.
2. In each timer call back function check to see if abortAllTimers is true. If it is true - then return at once without doing any drawing.
And finally - DeleteTimerQueueTimer should not be called from the timer callback. Instead I would suggest you should call it from any other thread - say the thread you used to start the timers.
Hope this helps.

Cancelling a long running process in VB6.0 without DoEvents?

Is it possible to cancel out of a long running process in VB6.0 without using DoEvents?
For example:
for i = 1 to someVeryHighNumber
' Do some work here '
...
if cancel then
exit for
end if
next
Sub btnCancel_Click()
cancel = true
End Sub
I assume I need a "DoEvents" before the "if cancel then..." is there a better way? It's been awhile...
Nope, you got it right, you definitely want DoEvents in your loop.
If you put the DoEvents in your main loop and find that slows down processing too much, try calling the Windows API function GetQueueStatus (which is much faster than DoEvents) to quickly determine if it's even necessary to call DoEvents. GetQueueStatus tells you if there are any events to process.
' at the top:
Declare Function GetQueueStatus Lib "user32" (ByVal qsFlags As Long) As Long
' then call this instead of DoEvents:
Sub DoEventsIfNecessary()
If GetQueueStatus(255) <> 0 Then DoEvents
End Sub
No, you have to use DoEvents otherwise all UI, keyboard and Timer events will stay waiting in the queue.
The only thing you can do is calling DoEvents once for every 1000 iterations or such.
Is the "for" loop running in the GUI thread? If so, yes, you'll need a DoEvents. You may want to use a separate Thread, in which case a DoEvents would not be required. You can do this in VB6 (not simple).
You could start it on a separate thread, but in VB6 it's a royal pain. DoEvents should work. It's a hack, but then so is VB6 (10 year VB veteran talking here, so don't down-mod me).
Divide up the long-running task into quanta. Such tasks are often driven by a simple loop, so slice it into 10, 100, 1000, etc. iterations. Use a Timer control and each time it fires do part of the task and save its state as you go. To start, set up initial state and enable the Timer. When complete, disable the Timer and process the results.
You can "tune" this by changing how much work is done per quantum. In the Timer event handler you can check for "cancel" and stop early as required. You can make it all neater by bundling the workload and Timer into a UserControl with a Completed event.
This works well for me when I need it. It checks to see if the user has pressed the escape key to exit the loop.
Note that it has a really big drawback: it will detect if the user hit the escape key on ANY application - not just yours. But it's a great trick in development when you want to give yourself a way to interrupt a long running loop, or a way to hold down the shift key to bypass a bit of code.
Option Explicit
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
Private Sub Command1_Click()
Do
Label1.Caption = Now()
Label1.Refresh
If WasKeyPressed(vbKeyEscape) Then Exit Do
Loop
Label1.Caption = "Exited loop successfully"
End Sub
Function WasKeyPressed(ByVal plVirtualKey As Long) As Boolean
If (GetAsyncKeyState(plVirtualKey) And &H8000) Then WasKeyPressed = True
End Function
Documentation for GetAsyncKeyState is here:
http://msdn.microsoft.com/en-us/library/ms646301(VS.85).aspx
Here is a pretty standard scheme for asynchronous background processing in VB6. (For instance it's in Dan Appleman's book and Microsoft's VB6 samples.) You create a separate ActiveX EXE to do the work: that way the work is automatically on another thread, in a separate process (which means you don't have to worry about variables being trampled).
The VB6 ActiveX EXE object should expose an event CheckQuitDoStuff(). This takes a ByRef Boolean called Quit.
The client calls StartDoStuff in the ActiveX EXE object. This routine starts a Timer on a hidden form and immediately returns. This unblocks the calling thread. The Timer interval is very short so the Timer event fires quickly.
The Timer event handler disables the Timer, and then calls back into the ActiveX object DoStuff method. This begins the lengthy processing.
Periodically the DoStuff method raises the CheckQuitDoStuff event. The client's event handler checks the special flag and sets Quit True if it's necessary to abort. Then DoStuff aborts the calculation and returns early if Quit is True.
This scheme means that the client doesn't actually need to be multi-threaded, since the calling thread doesn't block while "DoStuff" is happening. The tricky part is making sure that DoStuff raises the events at appropriate intervals - too long, and you can't quit when you want to: too short, and you are slowing down DoStuff unecessarily. Also, when DoStuff exits, it must unload the hidden form.
If DoStuff does actually manage to get all the stuff done before being aborted, you can raise a different event to tell the client that the job is finished.
EDIT it turns out the MSDN article is flawed and the technique DOESN'T WORK :(
Here's an article on using the .NET BackgroundWorker component to run the task on another thread from within VB6.

Resources