I want to create an excel template that will includes formulas for dating the columns. However, since those formulas will be based on TODAY(), I need to convert them to static strings (so the dates don't change everytime someone opens it). Is there a way to add a macro that will run automatically when someone creates a new spreadsheet based on the template? (Similarly to Auto_Open(), only on Create, rather than Open). If so, I could just create a macro that will replace the formulas with their results upon document creation. Can this be done?
[Note: I'm not married to this solution; it just seemed like the simplest way to protect my spreadsheet. If someone can suggest an alternative approach, I'd be obliged.]
I have a couple thoughts...
If you run a copy/paste values macro every time it really won't matter, right?
You could check if the file exists yet (has been saved), and if not
then this must be the template opened as a new workbook, maybe?
Code:
Private Sub Workbook_Open()
If Dir(ActiveWorkbook.Name) = "" Then
'run the macro?
MsgBox "I'm gonna run this macro"
End If
End Sub
You could have a cell on one of the sheets, that will never be used,
or is hidden, that will store whether or not to run the macro, and
change that when the file is opened or when the macro is ran. Then
have a macro run on open that checks that cell. (Or custom/document property)
You could populate the cells that have the today() formula only on
open and if they are already populated then don't run the macro?
I realized that there is no need for a Workbook_Create() function, as that behavior can be emulated by simply deleting the macro after it has run once (which happens when it is first created). Deleting macros is done automatically when the file is saved with a .xlsx extension. In addition, you need to prevent the macro from running when you open the template itself (while editing the it). You can hold the SHIFT key when opening it to prevent auto-run macros, but since that method isn't foolproof, I added this code at the top:
Private Sub Workbook_Open()
'If we're opening the template, don't run the macro
If Application.ActiveWorkbook.FileFormat = xlOpenXMLTemplateMacroEnabled Then
Exit Sub
End If
...
'add code here to SaveAs .xlsx, thus removing the macros, so it won't run every time.
End Sub
(Note: I didn't show my SaveAs code as it is rather messy: I wanted to suppress the default warning about losing macros, but wanted to also protect the user from inadvertantly overwriting previous file. If anyone is interested, I could post it)
Related
I run a lot of macros, and lately had to change to O365, which gave me the "wonderful" 64 bit Excel. One of its most maddening shenanigans is that when I run some macros (working with SAP GUI, creating SAP reports, naming them, saving and downloading to a specific folder where the next macro step opens them and incorporates into a relevant macro sheet), the new Excel opens these in a new instance (which I don't want but cannot prevent - can you help here?), which causes a dialog "File in Use" (which I don't want but cannot prevent - can anyone help me here?) because it tries to open my PERSONAL.XLSB (which I need and therefore don't want to get rid of just because of this) and qualifies it as "locked for editing" by another user, who is myself (which is absolutely stupid but I cannot change it - can anyone help me perhaps with this part?).
Sometimes the macro finishes fine when I don't answer that dialog; sometimes it seems to cause the Excel to hang up in trying to do next steps, sometimes the macro quits on me when I click "Read only" and so on.
All this is maddening also because these files that (possibly) SAP GUI opens, I have to waste my time by closing them after the macro finishes (has anyone a possible solution in stopping SAP opening these files? I was unable to find it anywhere so far.).
In some macros I fixed it by a specific part of code which waits till when these files open up and then it closes them - yet even that wait is wasting my time and it would be better without.
But with O365 and other instances it is even more colorful, because some files open in the same instance (this issue was there even before the O365 though) and I can manually close them after the macro finishes (although again, I have to wait till they open, which is again "vanity and torture of the soul"), but those opening in the new instance (specific to O365) show as blank sheets, I have to click into them, a warning sound follows but no dialog is visible, then I have to click into them again from the Excel icon in the bottom menu bar and then it tells me that I cannot close them because a dialog is open.
Then I need to close this dialog plus the one which appeared about the "File in Use", then I finally wait for the file (that I don't need) to open (because it is already saved inside the folder and already copied and pasted onto the relevant macro sheet) and only then I can close it.
So far I was unable to find anywhere on the internet an advice for how to stop SAP opening these files (when they are already saved where I need them), neither how to stop them opening in new Excel instances. So reluctantly, I think I should aim for at least a tiny little VBA code which will cause my macro to click on the "Read Only" button. Can anyone here help me with any part of this "Excel complaint"?
I do not know how/if SAP can be 'persuaded' to not open the workbooks in discussion... But, I think, you can handle that in a different way the "PERSONAL.XLSB" behavior, from the opening point of view. Of course, if SAP itself has this "bad habit" and not your code opens it in a new session, which have to be solved in a different way...
"PERSONAL.XLSB" is located in "...AppData\Roaming\Microsoft\Excel\XLSTART" folder. All workbooks located in this folder are automatically open when an Excel session starts;
You may change the "PERSONAL.XLSB" workbook path. If you want it to be open when a specific (necessary) workbook needs it, add a reference to it.
addRef. In order to do that, modify the (standard) VBAProject (of "PERSONAL.XLSB"), in, let us say, "VBPersProj", then (being in VBE) trough 'Tools - References...` tick its check box and press 'OK';
If the exported workbook is open in a new session and, even if it does not bother you any more because of the annoying dialogs and you need to identify that specific session, you can use the next function:
Function sameExSession(wbFullName As String, Optional boolClose As Boolean) As Boolean
Dim sessEx As Excel.Application, wb As Workbook
Set sessEx = GetObject(wbFullName).Application
If sessEx.hWnd = Application.hWnd Then
sameExSession = True
Else
sameExSession = False
If boolClose Then
sessEx.Workbooks(Right(wbFullName, Len(wbFullName) - InStrRev(wbFullName, "\"))).Close False
sessEx.Quit: Set sessEx = Nothing
End If
End If
End Function
It offers the possibility to close the workbook and the session itself if it is a different against the one where the code runs. It is an Optional parameter to be used, only if you need that. You can test it in the next way:
Sub testSameExSession()
Dim wbFullName As String
wbFullName = ThisWorkbook.fullName 'use here the full name of the SAP exported workbook
If sameExSession(wbFullName, True) Then
'process the workbook if this is what you need
End If
'if not open in the active session, the workbook could be closed and session quit, choosing the above way
'You can also simply call the function, without the closing parameter, as:
Debug.Print sameExSession(wbFullName)
End Sub
In case of False function retur, it can be closed and reopen in the existing session, if needed...
Edited:
If you need personal.xlsb being used/open when ribbon controls calls some of its Subs/functions, please adapt the code to call it in the next way:
Dim x as Long
x = Run("'C:\Users\your_UserName\AppData\Roaming\Microsoft\Excel\XLSTART\PERSONAL.XLSB'!GiveMeFive", 4, 3)
if calling a function (with parameters), which must return. Or
Run "'C:\Users\your_UserName\AppData\Roaming\Microsoft\Excel\XLSTART\PERSONAL.XLSB'!YourSubName"
when calling a Sub. In such a way, "Personal.xlsb" is opened if it is closed. And, in your specific case nothing will press the ribbon controls.
But, isn't the ribbon added when a specific workbook is open? Probably, the one you are using to make the above mentioned calls... If so, adding the suggested reference at "Personal.xlsb", will configure the new ribbon tab only when it is loaded. And your mentioned "problem" does not exist, in fact. Is it an add-in?
I am creating a "template" which our devs have to fill out, and I want when they save it to run some custom behavior before the file is actually saved. There are two cells that are formula determined. When they user in question is saving the populated file from the template into an xlsx, I want those cells to be the values not the formulas. (This also means, I don't want the macros saved with the XLSX file either.)
A perfect example is the =TODAY() formula, which if you save a an excel file with that formula in a cell on 1 Jan 2020, when it is reopened on 1 Feb 2020, that cell will read 1 Feb 2020, not 1 Jan 2020 when it was created and saved.
Since the original file they will be opening is an xltx, it will force them to save it as an xlsx or xlsm. I want the template (xltx) to have the formulas (and macros), but when they save it as the xlsx it should only have the values.
The VB for Copy & pasting values of cells instead of forumlas is basic and I've done that many times. The problem is, when I attempt to save the tempalte as the modified template (xltx) the BeforeSave event kicks off and changes the cells back to values instead of the formulas, defeating the entire purpose. (catch-22)
Is there a way to detect that I am saving the file as a xltx or is my only recourse to put a break point in the event macro and "skip" those lines when I'm saving the template?
If you put a breakpoint in the ThisWorkbook_BeforeSave handler, you'll find that this breakpoint will be hit before the "SaveAs" UI is even displayed, and the SaveAsUI parameter will be True, and since ThisWorkbook is already saved, then its Name will include the file name and its extension.
So you can easily get the .xltx file extension, but the problem is that at that point nobody knows what the user means to be doing - namely, whether you mean to be saving the template itself, or a working copy of it: BeforeSave is fired too early for what you're trying to do.
You need to somehow have the meta-information already at your disposal.
If you are only ever a developer and aren't going to ever be saving the template as anything other than as a template file, then you can leverage environment variables - are computers given a name in your organization?
If Environ$("COMPUTERNAME") = "Your computer's name" Then Exit Sub
'...rest of the BeforeSave handler...
That gives you a way to run logic conditional to the COMPUTERNAME or USERNAME OS environment variable values.
Use a class variable to record when the SaveAs dialog has been called and then use the Workbook_AfterSave event to make the adjustments.
Workbook.BeforeSave event (Excel)
SaveAsUI: True if the Save As dialog box is displayed due to changes made that need to be saved in the workbook.
Private hasSaveAsUI As Boolean
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
Rem Check to see if the file has been saved as
If hasSaveAsUI Then
hasSaveAsUI = False
Rem Do Something
End If
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
hasSaveAsUI = SaveAsUI
End Sub
I have a spreadsheet, with whatever in it. Now I want use one specific region (let's say C1:D10) to hold temporary data (in case I cannot remember clearly or mess them up).
However, I don't want keep the data for ever, and it is totally useless when this spreadsheet is used next time. Is there any way to erase this part when the spreadsheet is closed, no matter whether the user choose "save the change" or not, so that (C1:D10) is blank when I open the spreadsheet next time.
Instead of clearing the cells upon exit, use the Workbook_Open to clear the cells. This way you don't need to bother whether the user save the workbook on exit or not. This code will clear the cell the moment the workbook is opened.
Change Sheet1 below to the relevant sheet.
Private Sub Workbook_Open()
Sheets("Sheet1").Range("C1:D10").ClearContents
End Sub
I've got a Workbook_Open event macro (and it's in ThisWorkbook) that doesn't always run.
If Excel is closed and I double-click the .xls file from Windows Explorer, it does run.
If I launch Excel from Start/Programs (with no .xls file) and then open the file, it does run.
If I've already opened the file in Excel, but then close the file (leaving Excel open) and reopen it, then the macro does not run.
I've got security set to medium and I enable macros whenever it opens.
What do I need to do to get the macro to run whenever I open it, not just the first time for this Excel session?
(btw, this is Excel 2003)
I thought that this was the most cogent article on this problem (which is a long-standing never explained completely erratic bug that Excel exhibits). (dead link)
In short, in many cases it's a timing thing caused because the workbook is trying to calculate stuff when it opens and that gets in the way of the Workbook_Open event. The way to test on yours to see if that it for this situation, is to first rename any UDFs or Macros called by cells so that they won't get called and see if that changes anything.
I experienced the same problem.
I tested a workbook on my computer without any troubles. After destributing it to my customers I was told, that some combo-boxes stayed empty. These are usually filled from inside the workbook_open routine.
I tried different things to enable the workbook_open-Event - without success.
Finally, I found that disabling all userdefined Functions (UDF) lead to correct execution of workbook_open.
As my workbook is opened from another file, I will try to set calculation to manual first and then run the workbook_open manually. This may be done by defining it
public sub workbook_open
instead of
private sub workbook_open
Strange, that excel does not time this by itself...
A late answer (better than none).
I've had this problem now a few times (with Excel 2010).
The solution that has always worked (so far) was: remove conditional formatting, in particular if it contains UDF as conditions. As #LanceRoberts wrote in an above post, it's ultimately due to UDF calculations "overriding" the Open event, but I've found that those are particularly harmful if used in conditional formats.
I was experiencing almost identical behavior, and found that it is due to a bug that occurs if conditional formatting rules are erroring out. It turns out that if the conditional formatting rules are based on any setup by the macros, and that causes the conditional formatting to error, the Workbook_Open macro will not even attempt to run.
To test, make a copy of your file, and delete all conditional formatting from the workbook. Save and reopen. If it fixes your issue, then rework the conditional formatting rules to not depend on functions/values that will be broken before the Workbook_Open macro runs.
A few suggestions:
Try signing the workbook with a digital certificate. Add this certificate to the Trusted Certificates store then try again.
If this is machine-specific, try re-installing Office.
Make sure you have the latest service pack(s) applied.
I encountered the same problem, and I avoid it using the security settings.
I use the options settings then confidentiality center, then "params of confidentiality center" (sorry but its a translation of the french version :-p)
then "files approuved" or something like this.
And add the file containing the excel workbook in.
And its finnaly worked after that.
Looked everywhere and never find that solution.
Hope it'll help someone
This happens when a workbook is closed with an Application.EnableEvents set to false, and then you open another workbook within the same instance of excel opened. To avoid this, make sure that all of your processes that disable events, reenable them before terminating. Special attention to "End" commands, error handlers and "exit sub" sentences in the middle of your program.
What causes it is that your other archive, the one you openned first, have a Workbook_Open procedure; Excel doesn't excute it a second time.
This happened to me also and took me hours to figure out.
Turns out the TODAY() function in Excel was causing the problem.
Once deleted from my worksheet everything worked again. Very strange bug.
To add to the Arturo Llano post: The following code was used to monitor the Workbook_Open event and then run ProcessX whenever a workbook was opened.
ProcessX contained an End statement. The result was that it worked only the first time. The End wiped out AppX, so there was no further monitoring of events. Removing End fixed the problem. (Using End is bad practice anyway as it stops everything without any kind of cleanup or termination of other resources).
'Code in: Personal.xlsb ThisWorkbook
Public WithEvents AppX As Application
Private Sub Workbook_Open()
Set AppX = Application
End Sub
Private Sub AppX_WorkbookOpen(ByVal wb As Workbook)
'A 1-second delay to allow opening to complete before ProcessX starts.
Application.OnTime Now + TimeValue("00:00:01"), "ProcessX"
End Sub
I'm building an excel template (*.xlt) for a user here, and one of the things I want to do is have it insert the current date when a new document is created (ie, when they double-click the file in windows explorer). How do I do this?
Update: I should have added that I would prefer not to use any vba (macro). If that's the only option, then so be it, but I'd really like to avoid forcing my user to remember to click some 'allow macro content' button.
You could use the worksheet function =TODAY(), but obviously this would be updated to the current date whenever the workbook is recalculated.
The only other method I can think of is, as 1729 said, to code the Workbook_Open event:
Private Sub Workbook_Open()
ThisWorkbook.Worksheets("Sheet1").Range("A1").Value = Date
End Sub
You can reduce the problem of needing the user to accept macros each time by digitaly signing the template (in VBA IDE Tools | Digital Signature...) and select a digital certificate, however, you will need to get a certificate from a commercial certification authority (see http://msdn.microsoft.com/en-us/library/ms995347.aspx). The user will need to select to always trust this certificate the first time they run the template, but thereafter, they will not be prompted again.
You can edit the default template for excel -
There is a file called Book.xlt in the XLSTART directory, normally located at C:\Program Files\Microsoft Office\Office\XLStart\
You should be able to add a macro called Workbook_Open
Private Sub Workbook_Open()
If ActiveWorkBook.Sheets(1).Range("A1") = "" Then
ActiveWorkBook.Sheets(1).Range("A1") = Now
End If
End Sub
My VBA is a little rusty, but you might find something like this works.
To avoid VBA, and if you think your users might follow instructions, you could ask them to copy the date and then paste special->values to set the date so that it won't change in future.