Application.ontime code isn't running - vba

I've done a fair bit of research on here to try and get this code to run, but I'm still having issues.
I am trying to run a macro at a set time. In fact it is a number of macros as different times. This macro then copies a block of cells, into a different area on the sheet.
I will not be able to use windows scheduler so I'm trying to do it this way. I gather without scheduler I will have to run the macro from a button. Therefore, my first sub is this (note button is on a separate sheet to the data)
Sub Call_save()
Call Sheets("Dashboard").8amsave
Application.OnTime TimeValue("08:10:00"), "Call_8amsave"
Call 9amsave
Application.OnTime TimeValue("09:10:00"), "Call_9amsave"
Call 10amsave
Application.OnTime TimeValue("10:10:00"), "Call_10amsave"
End Sub
This button is designed to then run the subs at the predetermined time. The subs it calls are these:
Sub 8amsave()
Dim current_data As Variant
current_data = Worksheets("Dashboard").Range("S6:V22").Value
Worksheets("Dashboard").Range("B33:E49").Value = current_data
End Sub
Sub 9amsave()
Dim current_data As Variant
current_data = Worksheets("Dashboard").Range("S6:V22").Value
Worksheets("Dashboard").Range("B54:E70").Value = current_data
End Sub
Sub 10amsave()
Dim current_data As Variant
current_data = Worksheets("Dashboard").Range("S6:V22").Value
Worksheets("Dashboard").Range("B75:E91").Value = current_data
End Sub
Now, when I run the initial button it runs all the subs at once and copies the sells into the correct places, straight away. This isnt really an issue for me. However, at the predetermined time I get an error saying unable to run the macro... can't find it or sheet unable to run macros... or something of that ilk.
Is there anything blindingly obvious that i am missing? I have kind of been working this out as I go along so my VBA knowledge is fairly limited. A point in the right direction would be great.

Your OnTime statements also appear to be referencing procedure names which don't exist, i.e., Call_8amSave as opposed to 8amsave. Note also that procedure names cannot begin with numeric (e.g., 8amsave) and this code should not even compile, let alone execute.
Rename your procedures so that they match the calls in the OnTime statement, and are legally permissible procedure names, like: Sub Call_8amSave, etc.
Also, the OnTime property can only have one procedure at a time, so you can't set 3 future times, you have to set them sequentially. So, set the OnTime for the 9am save during the 8am procedure, etc.
Option Explicit
Sub Call_save()
Application.OnTime TimeValue("08:10:00"), "Call_8amsave"
End Sub
Sub Call_8amsave()
With Worksheets("Dashboard")
.Range("B33:E49").Value = .Range("S6:V22").Value
End With
Application.OnTime TimeValue("09:10:00"), "Call_9amsave"
End Sub
Sub Call_9amsave()
With Worksheets("Dashboard")
.Range("B54:E70").Value = .Range("S6:V22").Value
End With
Application.OnTime TimeValue("10:10:00"), "Call_10amsave"
End Sub
Sub Call_10amsave()
With Worksheets("Dashboard")
.Range("B75:E91").Value = .Range("S6:V22").Value
End With
End Sub

Related

issue with concatenated subs

DISCLAIMER: I'm not a developer, just an average guy trying to use VBA on his own project. First time I post on stackoverflow so forgive me if I'm violating any unwritten community rule..
Hi all, I'm trying to have a bunch of subs running in sequence, so the next one starts only when the previous one has finished.
The problem is that excel keep on crashing during the execution, while if I run each sub manually they have no issue at all.
So far I have been using this method: First I have a mini sub that assigns value=1 to the global variable "oneclick", and then calls the first macro of the chain
then, in each sub there is a tiny piece just before the end:
sub macro1()
...macro code...
if oneclick=1 then
call macro2
end if
end sub
and so on for all the subs until the final sub resets the oneclick variable to zero.
I have no idea why this keeps on crashing. I can see that actually none of these subs is really closing until the very end of the last one, would this hit any sort of code limitation? I would be actually happier to have a single master sub that directs the process instead of relying on a kludge like this! any suggestion?
EDIT:
oh wow already so many answers.. now I'm gonna try some of those. Answering some of your questions:
1) the crash is really something sudden, not even an error message, simply excel quits and reopens, in the same state as it was when the macro chain first started.
2) I agree with you guys that there should be a master sub calling the smaller ones, however last time I tried I got a series of problems because one macro needs to work on the results of the previous one and so on. How do you tell to vba to wait until the previous sub has ended?
It is best if you don't chain the macros, but instead call them from another sub. This way you will have a clear way of understanding what you are doing, in what order.
Sub AllOfIt()
macro1
DoEvents
macro2
DoEvents
macro3
End Sub
Sub macro1
...
End Sub
Sub macro2
...
End Sub
Sub macro3
...
End Sub
There is generally no need to worry about if something starts before the previous macro ended. That does not happen unless you do something like using Application.OnTime
What probably is happening is that oneclick is not defined with a Dim statement, so by default its defined at procedure level, meaning if you set oneclick it to 0 in another Sub, your setting another local/procedure level variable, and your variable in macro1 is unchanged, so your chain of macros never stops, which leads to a stack overflow/crash as stated in one of the comments above.
So either define oneclick as public variable (I recommend to define it as Boolean as it seems to basically be a switch .... True/False) or you pass the variable as argument down your chain of macros ( Sub Macro2(ByRef oneclick as Boolean) ).
All that said, as one of comments above stated, you can have all your chained subs in the main sub ( macro1 ) as they will only get executed one after the other, e.g.
Sub macro1()
Dim oneclick As Boolean
oneclick = True 'Need to get set to true to start
If oneclick Then Call macro2(oneclick)
If oneclick Then Call macro3(oneclick)
........
End Sub
Sub macro2(ByRef oneclick As Boolean)
oneclick = False 'One of your macros has to set oneclick to false to stop the chain/execution, probably under acondition
End Sub

Macros not showing up in the run macro menu

I started learning VBA and I don't understand why some macros copy-pasted from the internet do not show up in the run macro menu (Alt-F8).
Below there are 2 macros, but only the second one is showing. Why? And how do I fix it?
Sub Test1(ByVal Target As Hyperlink)
'...
End Sub
Sub Test2()
'...
End Sub
Macros with arguments are not available in Macros list because they cannot be run alone instead they are called by another macro by passing the required arguments.
If a Sub declaration contains parameters it will not show there.
You cannot call macros that have parameters as you are describing. If you need to have a parameter, you can take it out and then have the user input the value.
Sub Test1()
Dim hyperLink As String
hyperLink = InputBox("Please input hyperlink", "My Parameter")
'...
End Sub
Alternatively, if the hyperlink is in your document, grab the value from your document instead.
Here are my 5 cents - if you give an optional parameter, you will be able to call the sub routine, even if it will not be shown among the ones which you can chose from.
Write aaaaTestMe and press Run.
Public Sub aaaaTestMe(Optional lngA As Long = 8)
Debug.Print lngA
End Sub
You can call an even private macro from any excel object you can assign a macro, calling it this way:
'MyWorkbook'!'MyModule.MyProcedure "MyParameter1"'
(be careful with single quotes: ' around procedure name with parameter)

Cannot run the macro

I have encountered a problem in the macro below
Sub RefreshAction()
Range("b7").Select
Application.Run "RefreshCurrentSelection"
Application.OnTime (Now() + TimeValue("00:00:05")), "thisworkbook.Action"
End Sub
The cell refreshes when I run the macro the first time but I get the error message immediately after
Message: Cannot run the macro "C\Desktop\XYZ.xlsm'!thisworkbook.Action'. The macro may not be available in this workbook or all macros may be disabled.
I have already gone through "Trust Center->Trust Center Settings->Macro Settings->Enable all macros and it didn't work.
The "Trust access to VBA project object model" box is also clicked.
First of all, here is a snapshot of the error you get when you attempt to run OnTime from a worksheet (not a module) as I will explain. I was getting this error too and trying to figure out why.
It looks like a security error, but in this case it isn't exactly a normal security error.
To run code on a timer you have to add it to a VBA module.
Go to the VisualBasic editor and right click the VBAProject (book).
In Excel it looks like the following:
Once the module is added you add your timer code there.
Since you want to call RefreshAction every 5 seconds you would do something like the following:
Sub StartProcess()
Debug.Print Now()
Application.OnTime Now() + TimeValue("00:00:05"), "RefreshAction", Schedule = True
End Sub
Sub RefreshAction()
Application.EnableEvents = True
Debug.Print Now() + TimeValue("00:00:05")
Application.OnTime Now() + TimeValue("00:00:05"), "RefreshAction", Schedule = True
End Sub
I'll let you add the code that you want it to do each time in the RefreshAction subroutine.
Here's what it will look like in the Module. Make sure yours shows that it is in a module as it does in the image:
Also, I found it to be quite flaky. If you have anything even slightly wrong in the OnTime call it will fail silently. Copy my code (I tested it) and try it first. Once it runs, just add your code to the RefreshAction sub.
StartProcess()
Run the StartProcess to start the thing going.
Additionally Odd Thing
After I added that Module, I still had my code in the Worksheet and I went back and attempted to run it to see the error again and the odd thing is that once the code is in the Module you won't get the error from the Worksheet any more. It's probably referencing the code in the Module now.
See the absolute reference for more details : CPearson OnTime
First issue, you need to store the time that you'll input in your OnTime method to be able to stop it. (Here I declared a Public TimeToRun As Date)
Second Point To use the OnTime method continuously, you need to reset the timer at the end of your timed procedure (here RefreshAllStaticData).
So your whole code should look like this :
Public TimeToRun As Date 'so that TimeToRun can be used in both the functions
Sub RefreshAction()
Range("b7").Select
Application.Run "RefreshCurrentSelection"
DoEvents
'Store the next date of execution in TimeToRun
TimeToRun = Now() + TimeValue("00:00:05")
'Launch the next OnTime
Application.OnTime TimeToRun, "RefreshAllStaticData"
End Sub
Sub RefreshAllStaticData()
'--++-- Place your code here, as it is now --++--
'----Call RefreshAction to reset the OnTime method
'---------to another 5 seconds and keep "looping"
RefreshAction
End Sub
Sub Kill_OnTime()
'Launch this to stop the OnTime method
Application.OnTime _
earliesttime:=TimeToRun, _
procedure:="RefreshAllStaticData", _
schedule:=False
End Sub
A different but related cause of this error can be the string-length limitation of the OnTime method's Procedure parameter's argument. See my post at: Getting around the Max String size in a vba function?

How to get VBA Macro to run continuously in the background?

I want to monitor a value and get an email notifications when certain conditions are met. I have a macro like so:
Do While True
Worksheet.Calculate
If Value > 10 Then
SendEmail
End If
Sleep 60*CLng(1000)
Loop
However, when I run this, it clogs up the entire program and will turn unresponsive if I try to do anything.
Is there anyway to accomplish this but have it run in the background or at least not crash the program?
What I was doing before was using VBScript to open a not-visible spreadsheet and the VBScript ran continuously in the background monitoring the condition and worked fine, but my client really wants a GUI and for it to be in the program itself.
Any thoughts?
Use the Application.OnTime method to schedule code that will run in one minute.
Your code will look something like this (Untested):
Sub CreateNewSchedule()
Application.OnTime EarliestTime:=DateAdd("n", 1, Now), Procedure:="macro_name", Schedule:=True
End Sub
Sub macro_name()
If Value > 10 Then
SendEmail
Else
CreateNewSchedule
End If
End Sub
You might want to store the time of the next schedule in a global variable so that the Workbook_BeforeClose event can cancel the next schedule. Otherwise Excel will re-open the workbook.
Public nextScheduledTime As Date
Sub CreateNewSchedule()
nextScheduledTime = DateAdd("n", 1, Now)
Application.OnTime EarliestTime:=nextScheduledTime , Procedure:="macro_name", Schedule:=True
End Sub
Sub macro_name()
If Value > 10 Then
SendEmail
Else
CreateNewSchedule
End If
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
On Error Resume Next
Application.OnTime EarliestTime:=nextScheduledTime, Procedure:="macro_name", Schedule:=False
End Sub
You can then continue to use Excel between the scheduled times.
I think you need to specifically process the application event stack with a DoEvents call. This allows user interactions with the spreadsheet to occur, where normally the macro would take precedence. You code would look something like:
Do While True
If Value > 10 Then
SendEmail
End If
Sleep 60*CLng(1000)
DoEvents
Loop
You could also construct a GUI with HTA if you wanted to remain with VBScript.

Macro to start at a particular time

I have found sources that say to use
Application.OnTime TimeValue("18:00:00"), "MyMacro"
But I can't seem to get it to work. This is what I have entered
Sub TimeStamp()
'
' TimeStamp Macro
'
' Keyboard Shortcut: Ctrl+Shift+T
'
Application.OnTime TimeValue("13:25:00"), "TimeStamp"
' Following refreshes the data
Application.CalculateFullRebuild
Then the rest of the code followed by End Sub
For whatever unknown reason, when I start the Macro, it does not wait until that given time. What syntax rules am I breaking here?
The macro is triggered when the macro is triggered. OnTime schedules it to be run automatically, but why should that prevent you from running it manually? Think of it like a virus scan. Many people have their computers configured to do automatic scans at certain set times, but are perfectly able to run nonscheduled scans at any time. If you want to make sure that your macro doesn't have any effect before a certain time, use an if - then statement involving Now (if it is too early exit sub) -- although it makes more sense to not run it at all when you don't want to.
Another method that I've used for years successfully is by just creating a small vb script that is scheduled to call the macro. My other answer to a very similar question show this example script
Dim xlApp
Dim xlWkb
Set xlApp = CreateObject("excel.application")
Set xlWkb = xlApp.Workbooks.Open("PATH TO YOUR FILE")
xlApp.Visible = True
xlWkb.RunAutoMacros 1 'enables macros to be run on open
xlApp.Run ("YOUR PROCEDURE")
xlApp.Workbooks("YOUR WORKBOOK NAME").Save 'Save the workbook
xlApp.Quit 'quits excel
Schedule this through Tasks Scheduler. My other answer can be found here
This is what I ended up with thanks to the help of several of you. I used:
Private Sub Workbook_Open()
Application.Wait "6:45:00"
Call TimeStamp
End Sub
and placed this in "ThisWorkbook". This made it so that when I open up my workbook, the macro is automatically started but it waits until 3:03 pm to perform the rest of the task.
Next, I needed it to refresh every 15 minutes so I used Chip's solution suggested by User: Findwindow. The code goes as follows
Public RunWhen As Double
Public Const cRunIntervalSeconds = 900 ' 15 minutes
Public Const cRunWhat = "TimeStamp" ' the name of the procedure to run
Sub StartTimer()
If Time < TimeSerial(13, 15, 0) Then
RunWhen = Now + TimeSerial(0, 0, cRunIntervalSeconds)
Application.OnTime EarliestTime:=RunWhen, Procedure:=cRunWhat, _
Schedule:=True
End If
End Sub
at the end of the TimeStamp macro, I put Call StartTimer so that every time the macro is ran, the timer will schedule a new run time for 15 minutes from the current time. The If Time < TimeSerial(13, 15, 0) Then allows for the macro to stop running at 1:15pm, the time that I wanted it to stop.