Link to home
Start Free TrialLog in
Avatar of Tom McDonald
Tom McDonaldFlag for United States of America

asked on

how to make a vbscript sleep w/o pinning the cpu

I am trying to make a client-side vbscript sleep but can't do it w/o pinning the cpu

The Code is below, pretty straight forward, but I get the following error:

error: object doesn't support this property or method 'Wscript.Sleep'

***********code
<html>
<head>
<SCRIPT LANGUAGE="vbscript" > 
      function bSleep()
            document.All.whatsup.innerHTML = "I'm sleepy"
            Set WScript = CreateObject("WScript.Shell")
            WScript.Sleep 2000
            document.All.whatsup.innerHTML = "Done sleeping"
      end function
</script>
<body onload="call bSleep()">
<div id="whatsup"></div>
</body>
</html>

***********end code

To workaround, I swap out the wscript.sleep and use a loop, but it pins the cpu and that isn't acceptable because I am sleeping so other stuff can happen in the background.  Here is the loop code that pins the cpu:

***********code  snip (loop1)

StartTime=Now()
Do While Now() < StartTime + 8.0 / (3600.0 * 24.0)
      '      loop
Loop

***********end code snip

I also tried this loop:

***********code  snip (loop2)

Do While Not oBrowser.readyState = READYSTATE_COMPLETE
'      sometimes this fails--failure is unacceptable
Loop

***********end code snip

FYI, You're probably wondering how the oBrowser object got involved in loop2 (above).  If you want some background on the context. . . I am using this sleep code while a internetexplorer object navigates.  I've found that looping structure #2 doesn't work when a site is a slow loader, i.e., it will say the readystate is complete, but it really isn't!  Additionally, loop2 pins the cpu too and the spawned browser can't download anything.

Below is the complete code for my application if you want to put it all in context run this code below.  For this to work you have to set your ie default tools-options-security-default level to 'low'

***********all code

<html>
<head>
<SCRIPT LANGUAGE="vbscript" > 
      function bUpdateAll()
            document.All.whatsup.innerHTML = "starting"
            sUrl = "http://www.aspfree.com"

            const READYSTATE_COMPLETE = 4
            on error resume next

            Set oBrowser = CreateObject("InternetExplorer.Application")

            if err.number <> 0 then            
                  document.All.whatsup.innerHTML = "set your ie default tools-options-security-default level to 'low'"
                  exit function
            end if

            on error goto 0

            oBrowser.Width = 600
            oBrowser.Height = 400
            oBrowser.Left = 50
            oBrowser.Top = 50
            oBrowser.Visible = true      
            oBrowser.Silent = true

            oBrowser.Navigate(sUrl)
            StartTime=Now()
            Do While Not oBrowser.readyState = READYSTATE_COMPLETE
                  '      loop
            Loop
            set oBrowser = nothing
            document.All.whatsup.innerHTML = "done"
      end function
</script>
</head>
<body onload="call bUpdateAll()">
      <div id="whatsup"></div>
</body>
</html>

***********end all code
Avatar of fritz_the_blank
fritz_the_blank
Flag of United States of America image

In general, you don't want to do this. It is much better to arrange your code in such a way this isn't necessary.

FtB
You're trying a server script in client side script.  Would need to be:

<%
     function bSleep()
          Set WScript = Server.CreateObject("WScript.Shell")
          WScript.Sleep 2000
      end function
%>

What you are trying is not possible.  Client side VB will not control sevrer side sleep.  Do you understand the differecne?
Avatar of BChan
BChan


What are you trying to do? if it is client side, and you can use javascricpt, you can use the setTimeout method

self.setTimeout('method()', 5000)  //-- Call method() in 5000 miliseconds

http://www.devguru.com/Technologies/ecmascript/quickref/win_settimeout.html
You can't do this in ASP because by its very nature, it is single-threaded, and interpreted at runtime. In other words, you can spark up a process as you've done above, wait for it, but you can't go beyond the wait. The only way to effectively do this is to build a multi-threaded COM or ActiveX object that does the processing in the background that periodically checks for the ready state transmitted from the client to the server (though I'm not sure if WScript can actually call WinAPI functions where you can call CreateThread yourself). The object in turn will transfer processing control back to your script once your ready state is achieved.

GoofyDawg
Avatar of Tom McDonald

ASKER

BChan: yes, I am doing this client side.  Go ahead and copy the code into a asp page and it will work.

GoofyDawg:  In the '***********all code' section in my original question (above) I believe the internetexplorer.application object is asynchronous, i.e., I spawn it and it runs side by side with my vbscript code.  

I think, the problem stems from the fact that the vbscript code will pin the cpu when running the 'do while' loop, thus the spawned browser can't get many cpu cycles to download content.  If the vbscript code could just sleep for a second and give up some cycles then the spawned browser could finish its work (note, the 'all code' will work, as is, but sometimes not when you're navigating to a really slow site it fails--which is my problem).
Bchan, is there a way to do the settimeout in vbscript?  I'd rather not convert all my code to javascript

alorentz, oh, I didn't realize that wscript wasn't available on the client side.  But, if that is so, then why doesn't the script bomb when I create the wscript object?
When you execute a wscript shell, it is running on the server, not the client machine. Otherwilse, I could call a script that would delete files on a client's machine and etc.

This brings me back to my first point--it is best not to build something that is going to require a wait as this is a bad situation for the server to be in.

FtB
tomandlis,
Why not use the window.open method?
window.open("Sample.htm",null,
    "height=200,width=400,status=yes,toolbar=no,menubar=no,location=no");
What is the goal of your script?

You might be able to use this, or another approacr, such as an iframe. You then will not need to have the security settings change.
bchan, I believe window.open is a javascript function.  Please note that this is in vbscript.

If you really want to know the purpose of this script is essentially screen scraping

1. have the client side browser go to a site
2. navigate (click) a few links on that site to get to a destination page
3. gather info from the destination page
4. submit the gathered information via http to my servers

simple huh

I do step 4 by spawning a new browser and constructing a simple form (containing the gathered information) that has its 'action' set to a receiving page on my site.  

Why do this you ask?  Simple, because the screen scaping can only be done from a client-side browser that accepts cookies.--The site being scrapped is password protected.
I wonder if there isn't any way to use something like this for scraping:

Function GetHTML(strURL)
      Dim objXMLHTTP, strReturn
      Set objXMLHTTP = Server.CreateObject("MSXML2.ServerXMLHTTP")
      objXMLHTTP.Open "GET", strURL, False
      objXMLHTTP.Send
      strReturn = objXMLHTTP.responseText
      Set objXMLHTTP = Nothing
      GetHTML = strReturn
End Function

FtB
fritz, yes your code will work.  However, it doesn't work very well with cookies because some pages will check to see if you have a cookie (password protected site).  Consequently, it is better to just click links using a internetexplorer object when scraping pwd protected sites.

Also, your script only works server side and that will put a drag on the server.  Better to distribute something like this to the client.
Anyway, we've gotten a little off track here.  Remember, the original question is rather simple-- How can you get a client side vbscript to sleep while browsing with an internetexplorer activex object ?

So far the answers seem to be you can't unless you convert it to javascript, but I'll need an example of that (that doesn't pin the cpu) to accept that answer.

BTW, if you can remove the internetexplorer object from the equation (and still scape contents) I'll accept that too.
Still going with my original answer: don't do it--program around it instead.

FtB
ASKER CERTIFIED SOLUTION
Avatar of BChan
BChan

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>>Anyway, we've gotten a little off track here.  Remember, the original question is rather simple-- How can you get a client side vbscript to sleep while browsing with an internetexplorer activex object ?

I agree - not a good idea, and will be unreliable regardless.
>>Set oBrowser = CreateObject("InternetExplorer.Application")<<

Oh, please don't do that--Microsoft warns against it:

http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/Q257/7/57.ASP&NoWebContent=1

FtB
bChan!  You rock.  I used your suggestion.  Try the code below.  It works and it doesn't pin the cpu.  


<html>
<head>
<SCRIPT LANGUAGE="vbscript" > 
      dim oBrowser
     function bUpdateAll()
          document.all.whatsup.innerHTML = "starting"
          sUrl = "http://www.aspfree.com"

          const READYSTATE_COMPLETE = 4
          on error resume next

          Set oBrowser = CreateObject("InternetExplorer.Application")

          if err.number <> 0 then          
               document.all.whatsup.innerHTML = "set your ie default tools-options-security-default level to 'low'"
               exit function
          end if

          on error goto 0

          oBrowser.Width = 600
          oBrowser.Height = 400
          oBrowser.Left = 50
          oBrowser.Top = 50
          oBrowser.Visible = true    
          oBrowser.Silent = true

          oBrowser.Navigate(sUrl)
         bSleep(1) 'Call js function that sleeps
         
          document.All.whatsup.innerHTML = "done"
     end function

      function FWake(linkcase)
            document.all.whatsup.innerHTML = "Im awake: " '& oBrowser.readyState
            EndTime = Now() + 5.0 / (3600.0 * 24.0)
            Do While Now() < EndTime and Not (oBrowser.readyState = READYSTATE_COMPLETE)
                  ' Empty loop forces script to wait.                  
            Loop
            if linkcase = 1 then
                  bTemp = bClickLink("utilize")
                  bSleep(2)
            else
                  document.all.whatsup.innerHTML = oBrowser.Document.body.innerHTML
            end if
      end function


      Function bClickLink(sHrefFrag)
            bComplete = true
            bClickLink = false
            Dim x , i
            x = oBrowser.Document.links.Length
            Dim s , sTheLink
            For Each oLink In oBrowser.Document.links
                  sTemp = sTemp & "<br/>link: " & oLink.getAttribute("href")
                  If InStr(1, oLink.getAttribute("href"), sHrefFrag, vbTextCompare) > 0 Then
                        document.All.whatsup.innerHTML = "<p>clicked: " & oLink.getAttribute("href")
                        oLink.Click
                        bClickLink = True
                        Exit For
                  End If
            Next
      End Function
</script>
<SCRIPT LANGUAGE="javascript" > 
      function bSleep(theCase){
            sFunc = "FWake(" + theCase + ")";
            document.all.whatsup.innerHTML = "Sleeping";
            window.setTimeout( sFunc, 5000);
      }
</SCRIPT>
</head>
<body onload="call bUpdateAll()">
     <div id="whatsup">Nothing</div>
</body>
</html>
Fritz, the article says you shouldn't do it serverside.  The code above is client side.
hmm, I think I found a way to do it all within vbscript here:

http://www.codeproject.com/asp/webtimer.asp
Here is the code for the timer.  I think I'm going to use this code as it is a little cleaner, but BChan you were a big help and deserve the points.

Thanks

<HTML>
<HEAD>
<title>Demonstration</title>
<SCRIPT LANGUAGE="VBScript">
<!--
      Dim intTimerID
      hr=0            'change hours
      min=2            'change minutes
      sec=0            'change seconds
      
      Sub HandleTime
      if hr=0 and min=0 and sec=0 then
            endtime
      elseif min>=0 and sec>0 then
            sec=sec-1
            status=hr & ":" & min & ":" & sec
            intTimerID=setTimeOut("HandleTime",950, "VBScript")
      elseif min>0 and sec=0  then
            min=min-1
            sec=59
            status=hr & ":" & min & ":" & sec
            intTimerID=setTimeOut("HandleTime",950, "VBScript")
      elseif hr>=0 and min=0 then
            hr=hr-1
            min=59
            sec=59
            status=hr & ":" & min & ":" & sec
            intTimerID=setTimeOut("HandleTime",950, "VBScript")
      end if
      End Sub
      
      Sub endtime
            cleartimeout intTimerID
              status = "Your Time Ended"
            msgbox "Time Up"
      end sub

      status=hr & ":" & min & ":" & sec
      intTimerID=setTimeOut("HandleTime",950, "VBScript")
-->
</SCRIPT>
</HEAD>

<BODY>
      <h3>You’ll see a message box when the time is up.</h3>
      <hr>
      <br><input type="button" value="Click before time is up" onclick="call endtime">
</BODY>
</HTML>
This has been an informative thread for my research on sleeping in ASP. Kudos to the experts for their comments.

A few comments:

Other workarounds to sleeping in ASP
http://classicasp.aspfaq.com/general/how-do-i-make-my-asp-page-pause-or-sleep.html
http://www.ehow.com/how_2001270_sleep-asp-using-ado.html
http://www7b.biglobe.ne.jp/~lunlumo/prog/sample/javascript_sleep.html

Alternative method to do web scraping with XmlHttp and still support cookies
http://www.codeproject.com/KB/library/httpautomationlibs.aspx
http://blog.netnerds.net/2006/04/asp-sustain-remote-cookie-sessions-in-an-asp-script-using-vbscript/