Sometimes I realise that I need to stop the prog.
Is there a way I can programme combination of keys to escape from the loop ?
Some other method ?
Right now I'm crashing the process through the Ctrl + Alt + Del + Programme
Manager. None too elegant, I must admit.
Could someone please paste an example ? Or point me to a link.
Thanks in advance.
Andy Morton.
I can't think of any easy input, offhand, unless you
put the script into an HTA. Then you could just click
a button that changes a variable value, and your
check in the loop could act on that.
Something like:
i = 0
BoolQuit = False
Do While....
i = i + 1
If i Mod 100 = 0 then '-- hundredth loop
If BoolQuit = True then Exit Do
End If
s = TS.ReadLine
' ...etc....
Loop
----
BoolQuit would then be toggled by a button in the
HTA GUI. By only checking once every hundred lines
your loop only has to add a simple arithmetic
operation on most iterations.
It might be just as efficient to just do:
If BoolQuit = True then Exit Do
with each iteration if you're using a simple boolean
flag. But if you have to do something more intensive, like
check for an existing file, then you'd want to counter.
I suggest making yourself a gui by using (ugh, gross,
bloated) IE as a graphical interface. You can find
numerous examples of this by searching the archives.
Go to google => groups => advanced group search, and
look for: CreateObject("InternetExplorer.Application").
In particular, you might focus on status message /
progressbar (IE) dialogs. And finally, add a button
(call it: "Exit" or "Close Script") to your dialog.
And using "GetRef", hook the dialog back to your
script. That is, connect the button's "onClick"
event to a subroutine in your script, which will
include coding to terminate the script directly
(say, by using WScript.Quit)..
cheers, jw
____________________________________________________________
You got questions? WE GOT ANSWERS!!! ..(but,
no guarantee the answers will be applicable to the questions)
Have actually tested this? At what point would the message generated by the
button click be processed?? I would not have thought that UI events in the
HTA would be processed until the currently executing function is finished.
In the script, you can make a provision for receiving
events by placing "WScript.Sleep" in your loop. That
is because wscript.sleep is not exactly the same as
the sleep api. I don't know the exact interval, but
if you go into wscript.sleep it does not sleep forever,
rather it checks periodically for any events to process.
In this respect, wscript.sleep resembles vb's "DoEvents".
Why is that? Suppose the system wants to shutdown.
If the script is not processing events, it will not
detect the shutdown notification.
And, if you don't mind calling api's from script,
you can use hedge your bets and vb's "DoEvents"
directly, like this:
--- <snip> ---
Sub wshDoEvents()
' instantiate dynawrap
Dim oDW : Set oDW = CreateObject("DynamicWrapper")
' note: rtcDoEvents has no input or return values
oDW.Register "MSVBVM50.DLL", "rtcDoEvents", "f=s"
oDW.rtcDoEvents
' if you trust ms to release objects when they go
' out-of-scope, then you don't need set oDW = nothing...
End Sub
--- </snip> ---
cheers, jw
____________________________________________________________
You got questions? WE GOT ANSWERS!!! ..(but,
no guarantee the answers will be applicable to the questions)
Good point. I just tried it out and you're
right. Maybe the Sleep idea would work
as a DoEvents, as mr_U. suggested, but
the only way I know to call a Sleep in an
HTA is to run an external VBScript that
calls WScript.Sleep.
Maybe there's an easy solution I'm not
thinking of, but it does seem like the stop
would have to be set externally, for instance
by having the script check a given file
for the content "stop" at intervals....a file to
which one could save the word "stop" to
via Notepad at any time.
That's a bit hokey, though. It'd be interesting
to hear if someone figures out a better solution
that doesn't start getting into external components.
Here is a short hta as an example:
<head>
<title>Do Events Demo</title>
<HTA:APPLICATION APPLICATIONNAME='Do Events Demo' SCROLL='no'
SINGLEINSTANCE='yes' WINDOWSTATE='normal' SYSMENU='yes' CONTEXMANU='no'
>
</head>
<script language="VBScript">
'Global objects and variables
dim LoopFlag
dim i
'==============================================================================
sub SetupLoop
'Include code here to setup you loop processing.
'Most of your objects and variables will need to be global so you can
access them in you loop sub
LoopText.InnerHTML = "Start"
LoopFlag = true
i=0
'Call the first instance of your loop sub
SetTimeout "MyLoop",10
' it is very important that your code be done here - so that control
is returned to the interface.
' If you have post processing code - then you will have to call that
code in another sub from your loop sub.
end sub
'==============================================================================
sub MyLoop
'Here is where you would do you iterations. ie rstRecordSet.Movenext
i=i+1
'Body of your code will go here
'It is ok to have oter loops inside here. Just be aware that the
script will not yeild until this sub completes.
LoopText.InnerHTML = LoopText.InnerHTML & "."
'Test for completion here.
if i < 200 and LoopFlag then
'We are not done so we call the loop again on a timer
SetTimeout "MyLoop",1
else
'This is where you would call you post processing code
LoopText.InnerHTML = LoopText.InnerHTML & "Done" & " i=" & i
end if
end sub
'==============================================================================
Sub Pointer
document.body.style.cursor = "hand"
End Sub
'==============================================================================
Sub DefaultCursor
document.body.style.cursor = "default"
End Sub
'==============================================================================
</script>
<body>
<span onclick="SetupLoop" onmouseover="Pointer"
onmouseout="DefaultCursor">
<font color="blue"><h2><u>Start</u></h2></font>
</span>
<span onclick="LoopFlag=false" onmouseover="Pointer"
onmouseout="DefaultCursor">
<font color="blue"><h2><u>Stop</u></h2></font>
</span>
<span id="LoopText"></span>
</body>
The point being made is that setTimeout can be used to effect a "DoEvents".
SetTimeout queues a function to execute on the arrival of a windows timer
message.
The windows timer message ends up in the same message queue that all the
other window messages end up in such as button click. Hence setTimeout can
be used to yield the processing of a long operation to after outstanding
messages in the queue can be processed. You can even use 0 timeout value
which if the existing message queue is empty would cause the function to
execute immediately. I use this technique extensively to provide progress
bar updates and a cancel button for long running operations.
See the attached HTA.
--
→ Ayush
-------------
Search - www.Google.com | Wikipedia - http://en.wikipedia.org
Snip your long urls - http://snipurl.com/
-------------
In other words, it's easy enough to run one
sub from another, and check between subs
for the flag. But the question was whether one
could create the equivalent of DoEvents and
stop a loop at any point.
If the setTimeout call were doing that then the
second button click message would be recieved
and the loop could be stopped in the middle.
I haven't used setTimeout or setInterval before,
so i'm not sure I've got it right. But I've tried it
several ways to do the operation that the OP
wanted to do, and I just can't get it to work.
The following sample is an HTA that processes
a text file of 19,000 lines. (The file is actually
Wednesday's transcript of the Comes vs Microsoft
court proceedings.) The complex operation
with each line was just added to slow it down.
Maybe I'm misunderstanding this, but it seems
to me that if setTimeout can *really* produce a
DoEvents then the following code should be
able to process the Stop button click at 100ms
intervals. But it doesn't. The whole operation
takes 3-5 seconds to run on my machine and
I'm unable to stop it.
--------------------------------------
<HTML>
<HEAD>
<TITLE></TITLE>
<SCRIPT LANGUAGE="VBScript">
Dim BooStop, iVal
Sub LoadOps()
iVal = window.setTimeout("CheckBool()", 100)
End Sub
Sub ButStart_onclick()
Dim i2, FSO, s2, TS, i3, s4, iRet
BooStop = False
Set FSO = CreateObject("Scripting.FileSystemObject")
Set TS = FSO.OpenTextFile("C:\windows\desktop\iowa1-17.txt", 1)
Do While TS.AtEndOfStream = False
If BooStop = True Then Exit Do
s2 = TS.ReadLine
For i3 = 1 to Len(s2)
s4 = Left(Chr(Asc(mid(s2, i3, 1))) & "ssss", 3)
Next
i2 = i2 + 1
Loop
TS.Close
Set TS = Nothing
MsgBox i2
Set FSO = Nothing
window.clearTimeout iVal
End Sub
Sub CheckBool()
window.clearTimeout iVal
iVal = window.setTimeout("CheckBool()", 100)
End Sub
Sub ButStop_onclick()
BooStop = True
End Sub
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" onload="LoadOps()">
<INPUT type="button" value="Start" ID="ButStart"></INPUT>
<INPUT type="button" value="Stop" ID="ButStop"></INPUT>
</BODY></HTML>
what is DoEvents ?
It's a reference to VB that got into the
discussion earlier in the thread. In VB,
DoEvents can be added anywhere in
the code. What it does is to hand control
over to the Windows message queue,
allowing any pending operations to be
carried out, after which control is returned.
It's a bit like: "If anyone needs to use the
bathroom, this would be a good time." :)
And it can be called at any point.
DoEvents is often used to do things
like make sure that a window gets
"repainted" when necessary during
long operations, so that a program GUI
doesn't end up looking frozen.
Mr_U. was saying that WScript.Sleep
can have the same effect as a VB
DoEvents, letting other things carry
on while the script pauses. But in a
webpage a WScript.Sleep can only
be done by using WScript.Shell to
run a .vbs file that calls a sleep, so that's
not realistic to test as part of a loop
that might want to check a flag 2 or
3 times per second. So I was thinking
about whether there might be another
way to do a "DoEvents".
The setTimeout method seems to be good
as a timer. The MS sample I found showed
an example of using it to change a webpage
background color at intervals. But it doesn't
seem to work as a DoEvents method.
The script that you posted is not using the settime function like what
was demostrated.
The code you want to execute must be the sub that is called recrusively
by the settimer function.
Thanks for this great explanation !!
I think setTimeout/interval is the only possible workaround.. :(
--
→ Ayush [ Good :-) Luck ]
<HTML>
<HEAD>
<TITLE></TITLE>
<SCRIPT LANGUAGE="VBScript">
Dim BooStop
Dim FSO
Dim TS
Dim i2
Sub ButStart_onclick()
BooStop = False
Set FSO = CreateObject("Scripting.FileSystemObject")
Set TS = FSO.OpenTextFile("C:\windows\desktop\iowa1-17.txt", 1)
SetTimeout "MyLoop",1
end sub
Sub myLoop()
s2 = TS.ReadLine
For i3 = 1 to Len(s2)
s4 = Left(Chr(Asc(mid(s2, i3, 1))) & "ssss", 3)
Next
i2 = i2 + 1
if BooStop or TS.AtEndofStream then
SetTimeout "PostLoop",1
else
SetTimeout "myLoop",1
end if
end sub
Sub PostLoop()
TS.Close
Set TS = Nothing
MsgBox i2
Set FSO = Nothing
End Sub
Sub ButStop_onclick()
BooStop = True
End Sub
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
Also note, doevents in VisualBasic or VBA will not stop a loop at any
point. It will only yeild when it was called.
We get the same functionality by the settimer called subs.
This will also not work. Because between subs, the scripting engine
will not yeild to the ui. A button cick will never get processed,
becuase the interface will be locked.
the attached file is better than previous one(and faster) and much close to DoEvents..
what i used is :
[Do Loop] inside a function -- when the function starts it checks for the variable
(continue or not)
then it starts the loop and in the loop there is a counter. when the counter reaches
20, setTimeout function is used to restart the function and reset the counter then
exit the Loop.
This is a good alt if you are havig preformance issues with calling
settimeout on every cycle. It would speed up the whole process becuase
you are only yeilding every 20 loop cycles.
Thanks for the code sample.
setTimeout, by contrast, seems to yield to all
Window operations, only "firing" when IE is not
otherwise busy.
I'm afraid we've led the OP on a wild goose
chase...but it has been interesting. :)
I'm not sure I follow your reasoning. In both cases the processor is
yeilded to allow the main message loop to draw off messages from the queue.
It may be that DoEvents may not allow all messages to be processed however I
can't see how using the setTimeout is 'a wild goose chase'.
Because it doesn't seem to work as an actual
DoEvents operation. I tried several variations on
Ayush's ideas.
First, as I pointed out earlier, I couldn't run Ayush's
script directly because I don't have WMI installed.
It also has some errors. It's not a "real world" sample.
(Subs are named as functions, for instance. Maybe
WSH will allow that. I don't know. But it's also
not written to work properly. If allowed to run
it should error out with "invalid ubound" on the array
unless the operation is interrupted in time.)
But aside from that, Ayush's script is not a sample
of doing what we were originally talking about.
I suspect that if Ayush got the sample to work
it was probably because the loop is actually
doing operations on the webpage itself. It's
setting a timeout on operations that IE is doing.
My own tests have been with writing a script to carry
out the original request - a way to stop
the script while processing files. In that case
I haven't found a way that allows the click message
to get processed. Several people keep saying that
can be done but so far no one else has even tried
to write that script.
Would it not be possible to launch two vbscripts,
(from a main vbs script ? from a WMI script ?).
Script A would launch B1 and B2.
Script B1 would just launch a dialogue box with an OK button.
The dialogue would be (significantly)
" Press OK to stop the other script ! "
So that would just pause itself, waiting for the user to click.
If or when the user clicks OK, the next line of script in B1 creates a file
(Stop.txt) on the disk.
Then exits.
The second script, B2, is my original script with a new twist :
in the main loop there is now a condition
Do while not End of text stream (My Big text file) and Not exist Stop.txt
...
Loop
The idea is to get the two scripts to run simultaneously and to use the
Stop.txt as a flag.
Once the user presses the OK button in B1, the stop file is created and the
Do Loop in B2 detects it and stops.
(Err, hopefully ?)
Would that work ?
If that flag mechanism is OK, how do I go about lanching B2 while B1 is
still running ?
Andy
"mr_unreliable" <kindlyReply...@notmail.com> a écrit dans le message
de news: ukqjlLy...@TK2MSFTNGP04.phx.gbl...
Thank you for the challenge. This exchange has been a great learning
experience for me!
Woud be glad to help you redesign your code Andy... This method works!
<HTML>
<HEAD>
<TITLE></TITLE>
<SCRIPT LANGUAGE="VBScript">
Dim BooStop
Dim FSO
Dim TS
Dim s2
Dim i2
Dim i3
Sub ButStart_onclick()
BooStop = False
Set FSO = CreateObject("Scripting.FileSystemObject")
Set TS = FSO.OpenTextFile("temp.txt", 1)
myOutput.InnerHTML ="<br>Start<br>"
SetTimeout "MyLoop1",1
end sub
Sub myLoop1()
s2 = TS.ReadLine
i3 = 0
SetTimeout "MyLoop2",1
end sub
Sub myLoop2()
i3 = i3 + 1
i2 = i2 + 1
s4 = Left(Chr(Asc(mid(s2, i3, 1))) & "ssss", 3)
myOutput.Innerhtml = myOutput.InnerHTML & s4
if not(BooStop) and i3 < len(s2) Then
SetTimeout "MyLoop2",1
else
SetTimeout "EndLoop1",1
end if
end sub
Sub EndLoop1()
myOutput.Innerhtml = myOutput.Innerhtml & "<br>"
if BooStop or TS.AtEndofStream then
SetTimeout "PostLoop",1
else
SetTimeout "myLoop1",1
end if
end sub
Sub PostLoop()
myOutput.Innerhtml = myOutput.Innerhtml & "Stop. Executed " & i2 & "
functions."
TS.Close
Set TS = Nothing
Set FSO = Nothing
End Sub
Sub ButStop_onclick()
BooStop = True
End Sub
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<INPUT type="button" value="Start" ID="ButStart"></INPUT>
<INPUT type="button" value="Stop" ID="ButStop"></INPUT>
<span id="myOutput">
</span>
</BODY></HTML>
I'll have to play around with this. It's confusing.
I've never used setTimeout before. I also wonder
what the deal is with ClearTimeout. No one seems
to use it. That's OK?
I belive the ClearTimeout function is used to canacel a timer event
created with SetInterval.
That is a serious performance diffrence!
I guess calling settimeout every loop cycle, has a serious preformance
hit.
In the docs I find both: setTimeout and setInterval.
clearTimeout and clearInterval. They seem to be
pretty much the same thing.
The description just says:
"Cancels a time-out that was set with the setTimeout method"
So maybe that's only needed if one wants to stop
the timeout occurring between the time it was set
and the time that it runs.
You do seem to have got it, though. I guess
my mistake in the tests I did must have been
in trying to do it in a recursive sub. I came up with
a variation of your version that's only about
10 times slower and could be adjusted to run
faster. (If not stopped in time this sample would
probably error out with an invalid line number read
attempt. My sample file is 19,000 lines.)
I wondered whether there's a level of frequency where
the button clicked just won't be picked up. But this
sample only checks after every 100 lines read and
still works.
-----------------------
<HTML>
<HEAD>
<TITLE></TITLE>
<SCRIPT LANGUAGE="VBScript">
Dim BooStop
Dim FSO
Dim TS
Dim s2
Dim i2
Dim i3
Sub ButStart_onclick()
BooStop = False
Set FSO = CreateObject("Scripting.FileSystemObject")
Set TS = FSO.OpenTextFile("C:\windows\desktop\iowa1-17.txt", 1)
SetTimeout "MyLoop2", 1
End Sub
Sub myLoop2()
Dim i4
For i4 = 1 to 100
i2 = i2 + 1
s2 = TS.ReadLine
If Len(s2) > 0 Then
For i3 = 1 to Len(s2)
s4 = Left(Chr(Asc(mid(s2, i3, 1))) & "ssss", 3)
Next
End If
Next
EndLoop1
End Sub
Sub EndLoop1()
If BooStop or TS.AtEndofStream Then
SetTimeout "PostLoop",1
Else
SetTimeout "myLoop2",1
End If
End Sub
Sub PostLoop()
TS.Close
Set TS = Nothing
Set FSO = Nothing
End Sub
Sub ButStop_onclick()
BooStop = True
MsgBox i2
End Sub
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<INPUT type="button" value="Start" ID="ButStart"></INPUT>
<INPUT type="button" value="Stop" ID="ButStop"></INPUT>
<span id="myOutput">
</span>
</BODY></HTML>
------------
That's exactly what it does. I use it to defer postback (XMLHTTP)
operations. As users make changes I setTimeout a function to post changes
to the server (after say 5 seconds), if the user makes another change in
that 5 seconds I clearTimeout and re setTimeout. Hence only after the user
has stopped fiddling around with things does the set of changes get posted
to the server.
There is no need to user clearTimeout when the function pointed to by
setTimeout fires since setTimeout is one shoot.