How Can I Temporarily Pause a Script in an HTA?

How Can I Temporarily Pause a Script in an HTA?

  • Comments 9
  • Likes
Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I temporarily pause a script in an HTA?

-- TJ

SpacerHey, Scripting Guy! AnswerScript Center

Hey, TJ. You know, throughout history people have spent an enormous amount of time and energy searching for the meaning of life. The Scripting Guys have never taken part in this quest. Why not? Well, laziness aside, we know that it doesn’t matter: even if you did find the meaning of life, no one would care. No one wants to know why we exist; instead, they - like you - just want to know how the heck they can pause a script embedded in an HTML Application (HTA). That’s the cause the Scripting Guys have dedicated their lives to.

Now, if you’re not familiar with HTAs you’re first thought will likely be, “Just use Wscript.Sleep.” (Incidentally, if you’re not familiar with HTAs, you might want to wander over to the HTA Developers Center.) That’s a good thought, but it won’t work. Why not? That’s because the Wscript object is a somewhat-unique object; for one thing, you can’t actually create an instance of this object. Instead, the Wscript object is automatically provided for you any time you’re running under Windows Script Host. And that’s the problem right there: when you’re running code within an HTA you are not running under Windows Script Host. Instead, you’re running under the script host provided by Internet Explorer. Because you’re not running under Windows Script Host you aren’t automatically given access to the Wscript object, and because you can’t create the Wscript object on your own there’s no way to access Wscript.Sleep. You are - in highly-technical terms - hosed.

This wouldn‘t be that big of a deal if Internet Explorer provided a method comparable to Wscript.Sleep; unfortunately, it doesn’t. So is there some kind of crazy workaround we can use instead of a Sleep method? Did you even have to ask?

<script language = "VBScript">

    Dim dtmStartTime

    Sub Test
        dtmStartTime = Now 
        idTimer = window.setTimeout("PausedSection", 5000, "VBScript")
    End Sub

    Sub PausedSection
        Msgbox dtmStartTime & vbCrLf & Now
    End Sub


    <input id=runbutton  type="button" value="Run Button" onClick="Test">

What we have is a very simple HTA: it consists entirely of a single button that, when clicked, runs a subroutine named Test. Big deal, you say? Well, let’s take a look at the <SCRIPT> section of our HTA and decide how big a deal it really is.

The first thing we do within the <SCRIPT> section is declare a global variable named dtmStartTime:

Dim dtmStartTime

This actually has nothing to do with pausing the script; instead it’s just a variable we use to help us see that the script really did pause as expected. If that doesn’t make any sense to you at the moment, just be patient: it should all become clear very soon.

Next we have the Test subroutine, which gets called when we click the button:

Sub Test
    dtmStartTime = Now 
    idTimer = window.setTimeout("PausedSection", 5000, "VBScript")
End Sub

Notice that we have just two lines of code in this subroutine. In the first line we simply assign the current date and time (using the Now function) to the variable dtmStartTime. That brings us to this line of code:

idTimer = window.setTimeout("PausedSection", 5000, "VBScript")

Believe it or not, this is how we mimic the function of the Sleep method. What we’re doing here is using the setTimeout method to create a timer, which we give the ID idTimer. As you can see, we pass setTimeout three parameters:

PausedSection. This is the name of the subroutine we want to run when the timer expires.

5000. This is the amount of time (in milliseconds; 5000 milliseconds equals 5 seconds) we want the timer to wait before calling PausedSection. In other words, that’s our pause. If we want to pause the script for 30 seconds then we’d set this parameter to 30000.

VBScript. A required parameter that simply lets the script know that PausedSection is written in VBScript.

In other words, when we click the button the Test subroutine will run. When the Test subroutine runs, it creates a timer named idTimer. The sole function of idTimer is to wait 5 seconds and then call the subroutine PausedSection. Does that make sense? Good.

So what do we do inside the subroutine PausedSection? Well, obviously we could run any code we wanted; for simplicity’s sake we do only two things here. First, we display a message box showing the time we clicked the button and the time that the message box itself actually appeared on screen:

Msgbox dtmStartTime & vbCrLf & Now

Allowing for rounding errors, the difference between the time we clicked the button and the time the message box appeared should be 5 seconds. Is that important? You bet it is. Remember, displaying this message box is the first thing that happens inside the PausedSection subroutine. If it shows up 5 second after we click the button then that means we paused our script for 5 seconds. Which, as you might recall, was the whole idea in the first place.

The other thing we do inside the PausedSection subroutine is call the clearTimeout method and effectively get rid of our timer:


Why do we do that? That’s easy: timers are designed to run forever. If we don’t clear the timer then every 5 seconds idTimer will call the PausedSection subroutine, and every 5 seconds our little message box will pop up onscreen. We don’t really want to see that message box every 5 seconds, so we use clearTimeout to remove the timer.

Admittedly, this isn’t quite as easy as simply saying Wscript.Sleep 5000; that means you’ll probably have to think a little bit before you start enabling and disabling timers. In turn, that can be a bit of a challenge, but, hey, isn’t that what life’s all about?

And no, that wasn’t a rhetorical question. Like we said, we’ve been busy trying to pause HTAs; beyond that we have no idea whatsoever what life is all about.

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • You are interested for a solution for create an instance of the WScript object in an HTA script ?

    Reply to me at: aletrm AT tin DOT it

  • I release the HTA code for free, of course

  • "Why do we do that? That’s easy: timers are designed to run forever."

    this is not true, window.settimeout just run code ONCE, and window.setinterval run code repeatedly.

  • you can use the following:

    timeinseconds = 1

    with createobject("")

          .run "timeout " & timeinseconds, 0, True

    end with

  • someone posted this and it works great .with createobject("") .run "timeout " & timeinseconds, 0, True end with And I thought but what if i don't want to wait a whole second and it gave me an idea(which I might not have thought of had I not found this page): with createobject("") .run "wscript.exe TimeOutScript.vbs " & timeinmilliseconds, 0, True end with The code for TimeOutScript.vbs would be something like: WScript.Sleep WScript.Arguments.Item(0) where WScript.Arguments.Item(0) would be the timeinmilliseconds which was passed to the script via the run command. Keep in mind that this will not be as accurate as simply calling the sleep function in a .VBS script because you will have a bit of overhead from the time it takes to start and end the new wscript process. And, depending on how its hosted, for example on a network file server the time to access the TimeOutScript.vbs file will vary due to traffic and other variables. But overall it should be be way closer than whole seconds. The accuracy issue is to be expected though when using a work around.

  • well that had formatting in but apparently it was removed. Sorry for that. Anyway hope you still get the idea.

  • Hi Folks,
    didn't work for me.

    Background: I'm Scripting a small GUI for WinPE, configuring networkinterfaces via WMI. Since IP Adresses are obtained via DHCP, i have a small Timing issue, cause the HTA Comes up when the NIC still has noch IP.

    So i needed a method to wait a few seconds for my IP and found this blogpost:

    I put the exakt same code in the "Window_onLoad" section of my HTA. What the script does:
    It runs over the code, executing the window.SetTimeout and then doesn't wait with execution, but proceeds to execute everything underneath.

    Can somebody explain that? I thought there was no asynchronous execution of interpreted scriptcode...

  • Wait(2000) 'pauses 2 seconds

    Sub Wait(Time)
    Dim wmiQuery, objWMIService, objPing, objStatus
    wmiQuery = "Select * From Win32_PingStatus Where Address = '' AND Timeout = " & Time
    Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
    Set objPing = objWMIService.ExecQuery(wmiQuery)
    For Each objStatus in objPing
    End Sub

  • You could always call the Powershell sleep function if you want a proper "please stop doing things" sleep.

    Sub Sleep(iMilliseconds)
    CreateObject("WScript.Shell").Run "PowerShell -NoProfile -windowstyle hidden -ExecutionPolicy Bypass -Command "" Start-Sleep -m " & iMilliseconds & " """,0,True
    End Sub

    I shouldn't have to mention this but this will not work on any system without PowerShell installed.