Ok, this seems to do the trick.
I haven't found anything at all that can perform the equivalent of VB's DoEvents. What you need to do in an HTM or HTA is make sure event handlers terminate without running too long, or the user interface becomes unresponsive just like a VB program in a loop with no DoEvents calls.
In practical terms this means
no long-running loops at all! It also implies that nearly all script in your project needs to be contained in an event handler for
some event.
The
window object exposes some useful methods that can be used to cause a bit of script to be invoked repeatedly every time a specified amount of time elapses. One of these methods can terminate the repeated timer/invokation as well. Hmm... repeated execution of script, until stopped.
Almost sounds like a loop!
The sample here is lengthy. I apologize but I wasn't sure how else to get the point across. The basic function of this demo is to read and display itself line-by-line and repeat this starting from the beginning.... forever. Or to be more precise until the Quit button is pressed.
I unrolled my subroutine "Looper( )" into three parts:
Looper( )
Looper_Loop( )
Looper_Finish( )
Looper( ) is called just as a normal subroutine with an embedded loop would be. What Looper( ) does now is process all logic that I wanted done prior to looping, then it uses
window.setInterval to set up Looper_Loop( ) to be repeatedly called every 100 milliseconds. Then it exits.
Looper_Loop( ) checks for its terminating condition and if True it cancels the timer via the
window.clearInterval method, and calls Looper_Finish( ). Otherwise it does whatever it normally would happen in the loop. Here that means reading lines until EOF, displaying them, and at EOF closing and later re-opening the file. Then it exits.
Looper_Finish( ) does whatever I originally wanted Looper( ) to do after the loop. In this case I just make sure we've closed out the file.
Awkward, and it requires more planning than just coding a tight loop, but it does do the trick!
Looper.hta
Code:
<html>
<head>
<script language="Javascript">
function VBDecodeURI(s) {
return decodeURI(s)
}
</script>
<script language="VBScript">
Option Explicit
Dim blnQuit
Dim FSO
Const ForReading = 1
Sub btnQuit_onclick()
blnQuit = True
End Sub
Sub ShowText(ByVal strNewText)
Dim strText
strText = txtDisplay.innerText
'Trim back the history text occasionally.
If Len(strText) > 6000 Then
strText = Right(strText, 4000)
End If
txtDisplay.innerText = strText & vbNewLine & strNewText
txtDisplay.doScroll "down"
End Sub
'---------------------------------------------------------
'Looper Begins
'
'Special "subroutine" that contains a hard loop within
'which we need to simulate VB's *DoEvents* functionality.
'Looper control.
Dim LPRTIMER
'Global Looper data & objects that must be preserved
'across iterations.
Dim LPRtsIn, LPRblnOpen, LPRstrFName
Sub Looper()
'Do everything prior to the loop.
LPRstrFName = VBDecodeURI(document.location.pathname)
If Left(LPRstrFName, 1) = "/" Then
'Running as HTM, truncate leading "/" char.
LPRstrFName = Mid(LPRstrFName, 2)
End If
LPRTIMER = window.setInterval("Looper_Loop", 100, "VBScript")
End Sub
Sub Looper_Loop()
'Loop control and logic within the loop.
If blnQuit Then
window.clearInterval LPRTIMER
Looper_Finish
Else
If Not LPRblnOpen Then
Set LPRtsIn = FSO.OpenTextFile(LPRstrFName, ForReading)
LPRblnOpen = True
End If
If Not LPRtsIn.AtEndOfStream Then
ShowText(LPRtsIn.ReadLine)
Else
LPRtsIn.Close
Set LPRtsIn = Nothing 'Release reference.
LPRblnOpen = False 'Remind myself next trip.
End If
End If
End Sub
Sub Looper_Finish()
'Do everything after the loop.
If IsObject(LPRtsIn) Then
LPRtsIn.Close
Set LPRtsIn = Nothing
LPRblnOpen = False
End If
End Sub
'Looper Ends
'---------------------------------------------------------
Sub window_onload()
Set FSO = CreateObject("Scripting.FileSystemObject")
Looper
End Sub
Sub window_onunload()
Set FSO = Nothing
End Sub
</script>
</head>
<body style="background-color: #bbbbee">
<h2>Simple HTM/HTA "DoEvents" demonstration:</h2>
<p>This script will list itself over and
over until you press Quit.</p>
<p>
<textarea id="txtDisplay"
style="background-color: #ccccff"
rows="25" cols="72" readonly="true">
</textarea>
</p>
</body>
</html>
Note that this only works when the page is loaded via a file URL, i.e. on the local hard drive. That's because I am using
document.location.pathname to find the file to read via FSO. This technique is common in HTA's to let the script locate itself or its own directory.
I hope this helps. At least it actually works!