I have a simple script that hunts for popup boxes that are generated for website and Excel.
It works most of the time but errors out occasionlly and seemingly randomly.
The error is
line: 6
Char: 3
Error: Invalid window handle
Code: 80070578
I can't figuer out why it'll work for hours then error seemingly at random.
Also the script uses a lot of CPU if anyone could advise how to make it more efficent.
Thanks For your time
Set WshShell = CreateObject("WScript.Shell")
Do
Do
ret = WshShell.AppActivate("Message from webpage")
ret2 = WshShell.AppActivate("Microsoft Excel")
Loop Until ret = True or ret2 = True
WScript.sleep 500
ret = WshShell.AppActivate("Message from webpage")
ret2 = WshShell.AppActivate("Microsoft Excel")
If ret = True or ret2 = True Then
WScript.Sleep 200
WshShell.SendKeys("{ENTER}")
End If
WScript.sleep 500
Loop
The simple answer is VBScript is not designed to run scripts continuously.
As for what you can do the improve it, let's dissect it a little.
The outer loop is running every 500 milliseconds, which means that every half a second the script is triggered forever this is heavy for what it is doing and will likely cause heavy CPU usage the longer it runs.
Does the outer loop need to run so often, could you not increase the Sleep() from 500 to say 1000 or even 5000 to reduce the load on the CPU?
Better yet you could drop the outer loop completely and run the task using Windows own Task Scheduler which will allow you to create a scheduled task that will execute the script however often you wish. That way the script runs to completion closes releases the memory and is then run again at the next interval.
Related
I am writing a Windows service in VB.Net that will go out to some devices and data log points of information. I am using a Background Worker to do that so the service itself is still responsive. I have a timer that runs every second and checks the minute component of the current time. Each time the minute component changes I check which devices need to be checked, some are every minute, some every 5, some every 10, etc. These processes can take a few seconds or over a minute (I only rerun the worker if it's not already running and log a error if the last process took longer then the data retrieval interval).
In my OnStop event for the service I want to make sure the workers all close down. I call CancelAsync on the worker and the worker checks for cancellation to hopefully exit cleanly (i.e., check cancelation, if false retrieve data, save data into database, loop).
My problem is I don't want to use a sleep statement as it will lock everything but I also don't want the service to never shut down. So for example I have this currently:
Protected Overrides Sub OnStop()
' Add code here to perform any tear-down necessary to stop your service.
My.Application.Log.WriteEntry("ServiceABC shutting down for device " & DeviceID)
ServiceTimer.enable = false
If DataRetrievalBackgroundWorker.IsBusy Then
DataRetrievalBackgroundWorker.CancelAsync()
Dim x As Integer = 0
While ((DataRetrievalBackgroundWorker.IsBusy) Or (x < 15))
Threading.Thread.Sleep(1000)
x += 1
End While
End If
End Sub
This should work since the background worker is on another thread correct? Is there a better way to handle this?
You're close, if you don't want to Sleep(1000) and lock things up, do a Sleep(1).
'Dim x As Integer = 0
'While ((DataRetrievalBackgroundWorker.IsBusy) Or (x < 15))
' Threading.Thread.Sleep(1000)
' x += 1
'End While
Dim T As Date = Now.AddSeconds(15)
While DataRetrievalBackgroundWorker.IsBusy Or Now() < T
Threading.Thread.Sleep(1)
Application.DoEvents()
End While
i want to introduce a 3 hour delay between two consecutive lines in my VB script code.
I am using the following code snippet for this:
WScript.Sleep 10800000
But I think the code is stopping for a long time, much more than 3 hours. I used 10800000 as i read time is given in milliseconds.
Please let me know my mistake and the correct way to achieve this.
Thank You!
Try something like this:
timeout = DateAdd("h", 3, Now)
Do Until Now > timeout
WScript.Sleep 200
Loop
Important This solution was provided because question was tagged excel-vba at the beginning.
I will give you different option. I imagine you have something like this at the moment:
Sub MyCurrentSub()
Dim A
A = 10
'wait 3 hour here and...
'...after 3 hours do other part of the sub
MsbBox A
End Sub
During waiting time, even if you use different option to wait (like Do...Loop) your Excel application will be limited, at least partially will not work as usually.
I would do it in this way, by creating and calling different Sub at the right moment:
Public A
Sub MyNewSub_1()
A = 10
Appication.OnTime Now + TimeValue("03:00:00"), "MyNewSub_2"
End Sub
'now you can use your Excel as usually...
Sub MyNewSub_2()
MsgBox A
End Sub
You will get the same result, Excell will be free for you to use for 3 hours during waiting time. The only think you need to remember is to- DO NOT QUIT APPLICATION. If you Quit Excel it will 'forget' to call MyNewSub_2.
Is it possible to create a vbs script that call itself when a certain pc action is activated,lets say opening up a browser?A replica would be someone opens up a browser,then the vbs listens to this activity and runs itself or calls another vbs script?
Jimmy, if you want the code to be executed when a browser window is opened, consider this code :
Set obj0 = createobject("wscript.shell")
Dim Count
Count = 0
Do while count = 0
If obj0.appactivate("browserwindowtitle") then
-------do something----
----
----
Count = 1
Else
Wscript.sleep(10000)
Count = 0
End if
Loop
Set obj0 = nothing
The above code will check if the window having the title "browserwindowtitle" is open or not. If it is open, it will execute the desired action. If the window is not open, script will wait for 10 seconds and try again.
After writing the script go to control panel-> scheduled tasks and add the script as scheduled on startup. When you do this, the script will start executing when your PC turns on and will keep on checking if the browser window is open or not.
There will be easier ways to do this, others might be able to help.
You may want to give System Scheduler a try.
http://www.splinterware.com/products/wincron.htm
Good day!
I'm experiencing an issue with an ASP classic application we have. We were working on the SQL connection management and everything was perfect, so we deployed on another environment for the users to test and one of the ASP page hungs for 90 sec and results in:
Active Server Pages error 'ASP 0113'
Script timed out
So, I tried adding some debug code. What I used is:
Response.End
To check where it was hanging. I finally discovered that it was the new function we developed that was hanging, obviously! Here's a little extract:
Dim sqlConn
Set sqlConn = SessionConnection("SQLConnection")
set rsIDXMDL = SQLQuery(sqlConn, sQuery)
If I put a Response.End just before the call to SessionConnection(), the process stops. If I put the Response.End after the call to SessionConnection(), the page hangs for 90 sec. That made me think: "Bingo! Something inside fails!" So, just for fun, I put a Response.End at the first line of the function, like:
Function SessionConnection(SessVarName)
Response.End
[...]
I'm sure you can guess what happened!!! THE PAGE STILL HANGS!!! How is this possible?
Ideally you need to improve the code's efficiency so that it does't time out at all however if that's somehow not possible as a band aid you can try to increase the timeout:
Server.ScriptTimeout = 180
This value indicates how long, in seconds, the server will let an ASP script run until it is stopped by the server. The default value is 90 seconds.
Set conn = CreateObject("ADODB.Connection")
conn.ConnectionTimeout = 120
conn.Open <connectionString>
Where conn is an ADODB.Connection object that is not yet open, the connectionTimeout property will indicate the amount of time, in seconds, to wait for an ASP application to initially connect to the data source. The default is 15 seconds
Set conn = CreateObject("ADODB.Connection")
conn.Open <connectionString>
conn.CommandTimeout = 120
CommandTimeout tells the server how long to wait, in seconds, for completion of any command sent to the data source. This value is editable before and after the connection has been opened. The default is 30 seconds
Hope this helps.
I wrote a VB.NET Windows Service, which works fine. I have only one issue with it. I want the service to execute on the half hour and top of the hour marks (e.g. 9:00, 9:30, 10:00, 10:30, 11:00, etc etc etc). I am using the following code:
Protected Overrides Sub OnStart(ByVal args() As String)
' Add code here to start your service. This method should set things
' in motion so your service can do its work.
Dim oCallBack As New TimerCallback(AddressOf TimedEvent)
oTimer = New System.Threading.Timer(oCallBack, Nothing, 300000, 300000)
EventLog.WriteEntry("CCFinalizeService has begun successfully." , _
System.Diagnostics.EventLogEntryType.Information)
End Sub
This code works, however, if the service starts at, say, 10:15, then it executes at 10:15, 10:45, 11:15, 11:45. How do I make it so it always executes on the 30 minute and top of the hour marks?
You could change it so that, at startup, it figures out the time required to go to a half hour increment based off the current time. Basically, your first timer would be <300000, then switch to every 300000.
Alternatively, you might want to consider using the Windows Task Scheduler instead of doing this as a service. The task scheduler lets you specify specific times to run an application.
You just need to modify the dueTime parameter in the Timer creation method
Dim now As Date = DateTime.Now
Dim dueTime As Integer ' milliseconds to the next half-hour
dueTime = 1800000 - (now.Minute Mod 30) * 60000 - now.Second * 1000 - now.Millisecond
oTimer = New System.Threading.Timer(oCallBack, Nothing, dueTime, 1800000)
Probably the easiest solution would be to test, at service startup, the current time, via the Date.Now property. You can then use a second timer to start the first timer, but set the Interval on the second timer to fire only at the next 1/2 hr or full hour mark.
Alternately, in your startup routine, have an infinite while loop that tests to see if the current time is on your mark. If not, System.Threading.Thread.Sleep(1000) and test again.
Good luck!
Maybe something like this??
If Now.Minute <> 0 Or Now.Minute <> 30 Then
Thread.Sleep((30 - Now.Minute) * 60 * 1000)
End If