Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Pausing a script 2

Status
Not open for further replies.

PhillipFoster

Technical User
May 23, 2002
41
GB
How can I detect a keypress during the execution of a script?

I want to be able to hit the P key and have the script pause by using a msgbox offering a resume or quit option.

Thanks - Phil.
 
I don't think you can trap a keystroke in VBScript (by definition, the only inputs you have to the script are MsgBox and InputBox. I assume you don't want a box to popup every minute saying "Continue (Y/N)?").

You could invoke a pause by reading from an object that has this feature. I don't know of any objects that trap and expose keystrokes, but you could use the File System Object to pause the script based on the presence or absence of a file (C:\PauseMe.txt for example).
 
If you are talking about a WSH script, your options are pretty limited. Normally this would be done using a non-modal dialog of some sort, and WSH explicitly doesn't support them (though people have constructed work-arounds).

A much easier option is to rewrite the script as an HTML Application (HTA). This give you something more like a VB program: a user-interface hosting code instead of WSH's model of code hosting UIs. An HTA will fit the bill whenever you don't need to use WScript.Sleep (or a very few other special functions exposed by WSH that IE does not expose or provide alternatives for).

Something like (non-working sample code):

myscript.hta
Code:
<html>
  <head>
    <title>My Script</title>
    <script language=&quot;VBScript&quot;>
      Option Explicit
      Dim blnQuit

      Sub MyLogic()
        Dim {some stuff}

        {code}
        Do While Not blnQuit
          {loop code}
        Loop
        If blnQuit Then
          {early quit cleanup code}
        Else
          {normal completion code}
        End If
      End Sub

      Sub btnQuit_onclick()
        {other &quot;quit&quot; stuff, &quot;are you sure&quot; MsgBox, etc.}
        blnQuit = True
      End Sub

      Sub window_onload()
        {init code if any}
        MyLogic
        {finish code if any}
      End Sub
    </script>
  </head>
  <body>
    Welcome to the amazing <i>My Script.</i><br>
    I'm doing important stuff, quit if you get<br>
    tired of waiting.<br>
    <input type=&quot;button&quot; id=&quot;btnQuit&quot; value=&quot;Quit&quot;>
  </body>
</html>
Just double-click on the HTA file to run it.

You can get more control over the UI by use of the <hta:application> tag as well. You can even assign an icon or desktop or start menu shortcut to an HTA.

This might give you what you need with minimal pain. It also means you could easily add progress bars, running information displays, or a whole lot of things that are tough in a WSH script.

Of course if you wanted a cscript WSH script this won't help, because it needs to display its GUI on the desktop. Since you are running this script attended (thus the &quot;quit&quot; option) using the desktop should be no hardship.
 
Wow, you've just solved the next {insert (big) number here} enhancements.

Cheers - and a gold star (obscure UK reference) too.

Regards - Phil
 
Alas! You &quot;starred me&quot; too soon.

Usually before shooting off my mouth here I actually try code before I ever post it. I should have known better at the time, and now I can only say mea culpa.

The problem is that VBScript lacks VB's DoEvents and this is very important. While in a loop you won't get visible page updating, and a Quit button as I described won't function at all. The IE thread that runs scripts is tied up in your loop.

This doesn't mean we're doomed, it's just that we need to keep in mind that HTM/HTA script needs to be event-driven in most circumstances. As I said, much like VB. VB has the &quot;escape&quot; of allowing you DoEvents calls but we don't have that luxury here.

I've not given up however, and will experiment a bit and post additional information later. Sorry to send you in pursuit of undomesticated waterfowl in this manner.
 
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 &quot;Looper( )&quot; 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=&quot;Javascript&quot;>
      function VBDecodeURI(s) {
        return decodeURI(s)
      }
    </script>
    <script language=&quot;VBScript&quot;>
      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 &quot;down&quot;
      End Sub

      '---------------------------------------------------------
      'Looper Begins
      '
      'Special &quot;subroutine&quot; 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) = &quot;/&quot; Then
          'Running as HTM, truncate leading &quot;/&quot; char.
          LPRstrFName = Mid(LPRstrFName, 2)
        End If
        LPRTIMER = window.setInterval(&quot;Looper_Loop&quot;, 100, &quot;VBScript&quot;)
      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(&quot;Scripting.FileSystemObject&quot;)
        Looper
      End Sub

      Sub window_onunload()
        Set FSO = Nothing
      End Sub
    </script>
  </head>
  <body style=&quot;background-color: #bbbbee&quot;>
    <h2>Simple HTM/HTA &quot;DoEvents&quot; demonstration:</h2>
    <p>This script will list itself over and
       over until you press Quit.</p>
    <p>
      <textarea id=&quot;txtDisplay&quot;
         style=&quot;background-color: #ccccff&quot;
         rows=&quot;25&quot; cols=&quot;72&quot; readonly=&quot;true&quot;>
      </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!
 
Oops!

The web-based message reply editing here chopped out a vital part of the code above!

To test the above, copy/paste it into a file. Then replace the missing line as highlighted below:
Code:
  <body style=&quot;background-color: #bbbbee&quot;>
    <h2>Simple HTM/HTA &quot;DoEvents&quot; demonstration:</h2>
    <p>This script will list itself over and
       over until you press Quit.</p>
    <p>
      <textarea id=&quot;txtDisplay&quot;
         style=&quot;background-color: #ccccff&quot;
         rows=&quot;25&quot; cols=&quot;72&quot; readonly=&quot;true&quot;>
      </textarea>
    </p>
Code:
    <p><input type=&quot;button&quot; id=&quot;btnQuit&quot; value=&quot;Quit&quot;></p>
Code:
  </body>
Let's see if this gets through!
 
dilettante you amaze me with the amount of effort you've expended on a complete stranger's problem - thanks.

The bad news is that the script doesn't seem to do anything on my PC. Win2k Server, SP3 all service applied.

I thought that it was because my default browser - Opera, wasn't playing nicely - but it has the same effect (or lack of effect) in IE6.

I understand if you don't want to take this any further, but a working example would, I suspect, provide a solution to lot of people's problems.

Anyway I'm going to see if I can solve loopers lack of effect.

Regards - Phil.
 
Thanks for the positive comments.

I just copied/pasted the code above (plus the correction line) into a fresh file. As an HTM, on load I get the security popup due to the FSO being created, and after OKing it things roll merrily along. As an HTA it takes right off, even though because I hadn't bothered to resize the window on loading I sometimes need to scroll to see where the Quit button is and to click it.

Does Opera support VBScript and ActiveX fully? Does it support window.setInterval/.clearInterval at all? I think only IE will run an HTA though anyhow.

Win2K Pro SP3 here, IE6, but I have done this very thing on Win98SE using IE 5.5 for certain. Just tested it on XP Pro as well. I suppose putting in MsgBox calls to see where the script is (or isn't) getting executed would be a start.

This same technique ought to work fine in Javascript, but as I said HTAs (and maybe .setInterval?) are only supported by IE as far as I know. Could your problem be that Opera is assigned to the HTA extension as well as HTM, HTML, etc?
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top