I have a workbook ("CodeBook.xlsm") that runs code using a BeforeSave event. When a user has multiple workbooks open and chooses to quit excel via File/Exit, the user is prompted whether to save workbooks, and if yes to CodeBook.xlsm, then the BeforeSave code is run. The problem is, at that point the ActiveWorkbook may not be CodeBook.xlsm, unless that happens to be the workbook that the user was in when he/she selected Exit Excel. If the user quit excel from another workbook, the BeforeSave code is running but the activeworkbook is some random file of the user, so all the references to specific worksheets and ranges in the BeforeSave code do not work.
I have tried various ways using a Static declaration to retain the name of CodeBook and workbook().activate to activate it when the application is quitting, but when BeforeSave runs, it can't pick up the name CodeBook anywhere, short of hard-coding the name into the code.
Any suggestions? How to retain a variable name in memory when there is no code running, but is there when a user initiates a quit excel, OR how to activate a specific workbook when Excel is quitting from a user command and not from application.quit. Using excel 2010.
I overcame this by including a reference to the specific workbook.
For example, this code simply saves the date/time stamp in cell A1 of Sheet1 before closing the document. By adding ThisWorkbook, it works on the specific workbook that the code resides in. If you don't add ThisWorkbook then it will work on the active workbook when the user quits.
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ThisWorkbook.Worksheets("Sheet1").Range("A1").Value = Now()
End Sub
Place this code in the ThisWorkbook module.
Related
I work with a a group of six interlinked Excel workbooks that all feed into one summary/reporting workbook (let's call it "Main Report.xlsm").
Since the various workbooks are updated with new information throughout the day as it comes to hand, they need to be saved regularly throughout the day. I have therefore created a simple VBA macro that saves all open workbooks at the press of a button, which I have located as on object on Sheet1 of MainReport.xlsm. The macro works OK and saves all open workbooks as expected, however two aspects of the code are not working as expected:
No matter where I insert ScrenUpdating = FALSE, Excel still displays each workbook on the screen as it saves it. I don't want that because it slows down the save process, plus it looks weird as the macro toggels through each open workbook and the workbooks flash up momentarily on the screen. Since I activate the save macro from Main Report.xlsm, I want the screen to freeze on that workbook whilst Excel saves all open workbooks as a 'background' process. Can anyone tell me how I can make ScreenUpdating work properly with this code?
At the end the macro is supposed to select the 'Main Report.xlsm' workbook, but instead of activating that workbook, Excel seems to get stuck on displaying the second-last workbook in the group of six open workbooks. If I test the code by stepping through it, it seems to work OK, but when I run it from the assigned button on Main Report.xlsm, it does not work. Why would this be happening?
Here is my simple 'SaveAll' macro VBA code:
Sub SaveAll()
Application.ScreenUpdating = False
Dim Wkb As Workbook
Application.Calculate
For Each Wkb In Workbooks
If Not Wkb.ReadOnly And Windows(Wkb.Name).Visible Then
Wkb.Save
End If
Next
Application.Workbooks("Main Report.xlsm").Activate
ActiveWorkbook.Worksheets("Sheet1").Select
ActiveSheet.Range("C4").Select
Application.ScreenUpdating = True
End Sub
Can anyone spot what I am doing wrong?
I am new to VBA!
I have a workbook A that I use as a template for spinoff workbooks B, C, D, etc.
I made an error in formulas range A36:E37. I need to correct it in all the subsequently created workbooks, which can have any random name
I want to open the corrected master workbook A, and copy range from A to whateverworkbookname
Every time I use thisworkbook refrerence, it pastes the data to my personal macro workbook, same thing with activeworkbook.
I'm sure there's a simple solution, (like assigning a variable to the freshly opened workbook that needs fixing?) but I don't know how to do that.
Help is much appreciated!
Also of note, I am planning on manually opening the whaverworkbookname, then VBA unprotecting the sheet, copy paste function, protecting the sheet, saving, and closing the whateverworkbookname book when the macro completes, to be repeated with the rest of the incorrect workbooks.
If there is a smarter way to do this (which is probably way over my head) like applying a macro to all workbooks in a folder for instance, I would be interested in a point in the right direction to learn about it.
First a note:
ThisWorkbook always refers to the workbook the code is written in. This never changes.
ActiveWorkbook is the workbook that has focus (is on top). This changes easily with a mouse click on any workbook.
The issue is probably that you run the code from VBA editor. But if it is in your personal workbook and you run from the editor, then as soon as you are in the code your active workbook is the personal one because that is where your code is and if you click there to run the code it has focus.
You can check if the active workbook is the personal one
If ActiveWorkbook.Name = ThisWorkbook.Name Then
MsgBox "The active workbook is the personal one. Make sure to focus on the correct workbook."
Exit Sub
End If
'rest of your code
Create a button or link a ribbon button to launch your macro and use ActiveWorkbook in your code.
What is the best way of protecting a specific Excel workbook?
I have an inherited script that includes the following common lines at the end:
ActiveSheet.Protect "my-password"
ActiveWorkbook.Protect "my-password"
However, I've noticed that as the script can take a few minutes to run users often switch to a new unrelated workbook whilst it solves - whatever else they are working on. The password protection is then inherited by the unrelated workbook upon the completion of the macro - since whatever other Excel file the user is working within is now "Active" (presumably? this is my reading of the problem).
The above script is in a workbook that can be renamed to whatever the user chooses, and be saved in any number of directories. How can I ensure that only the original excel file is locked/unlocked by the Macro, when other workbooks are in use?
I am sure there are many ways to do this, but which is the most foolproof method?
NOTE: using office 365
Thanks Dean's answers in the comments:
Early in the code (and in Worksheet_Change if appropriate) enter the following to define your sheet as an object (named default_ws in my case):
Set default_ws = ActiveSheet
When you are ready to lock your sheet or workbook you can then use:
default_ws.Protect "password-here" 'protect your sheet
ThisWorkbook.Protect "password-here" 'protect your workbook
Also note:
You could also define your workbook as an object as follows if desired:
Set default_wb = ActiveWorkbook
Excel 2016 (or 365) does not seem to fire the Workbook_Open() sub reliably or more precisely, not at all!
The simple event sub
Private Sub Workbook_Open()
MsgBox "Work book is open"
End Sub
does not seem to work. However, if a workbook is already open and then the workbook containing the above Sub is then opened, it does run as expected.
I notice that unlike Excel 2010, 2016 (365) opens each workbook in its own window, not a workbook window in the Excel application window. Is this a bug in 2016 and is there a workaround?
I have produced a work around for my own applications and that is call the activation of a worksheet and call my initialization routines from there. But a bit "rough" and it would be good to have the Workbook_Open() sub working correctly.
It is a simple single Sub in the ThisWorkbook module. Macros are enabled. In Excel 2010 it works perfectly, as do two other macros in other workbooks for which I have written macros. It is just this one thing with Excel 2016. Given that the Workbook_Open() sub is the gateway to a workbook it seems a little strange that we have to go to a workaround to make it function.
Try encapsulating the call with a new instance of Excel. Example below:
Sub OpenInNewExcel()
Dim Background_Excel As Excel.Application
Dim pathName As String
Dim fileName As String
Let pathName = "Enter your path here" 'include "\" at the end
Let fileName = "Enter your file name here"
Background_Excel.Workbooks.Open fileName:=pathName & fileName
Background_Excel.Parent.Quit ' This is how you close the file completely using VBA otherwise the file will close and the Excel Shell will remain.
End Sub
Also make sure that enable macros is turned on in the Options-Trust Center.
You have to add the file/folder location of your workbook as a "Trusted Location".
You can see more info about that in Designate trusted locations for files in Office 2016.
I have same problem then I found solution after google it:
https://www.myonlinetraininghub.com/excel-forum/vba-macros/excel-2016-workbook_open-event-doesnt-trigger
Then I also use "Private Sub Workbook_Open()" and "Public Sub Auto_Open()" open in excel 2016 that work fine:
Private Sub Workbook_Open()
CustomStartUp
End Sub
Public Sub Auto_Open()
CustomStartUp
End Sub
Private Sub CustomStartUp()
MsgBox "Work book is open"
End Sub
I've had this problem (I'm using Microsoft 365), and I found this thread.
It happens for me sometimes when I have another workbook already open, then, on trying to open my macro-enabled workbook, before any sheet is displayed I get the Microsoft warning message about macros. Then, although I click its 'Enable' button, the Workbook opens, macros do get enabled, but Workbook_Open doesn't run.
I've never known the problem to occur if no other workbook is open. (Of course, the user might still get the yellow-backed messages at the top of the workbook, asking them to click the Enable Editing and/or Enable Macros buttons.)
Note that my Workbook_Open just calls another 'workbook-opening' sub in a module to do all the opening processing.
My solution: When my workbook-opening sub is called, it sets a global variable to True to indicate it has run.
I've made it obvious to the user that the problem has occurred, by means of a 'Welcome' sheet with all its cells locked, so the user can do nothing; at this point all other sheets are very hidden. The workbook-opening sub, when it runs, deactivates this sheet and makes it very hidden, so the user never normally sees it, and makes the other sheets visible. But if this screen remains, it instructs the user to select the other workbook, then select this one again. My Workbook_Activate code then runs, and because the global variable isn't True, it calls the workbook-opening sub. If this global variable is True, it does nothing.
To make this work, the Workbook_Close sub makes the other sheets very hidden and the Welcome sheet visible, ready for the next time the Workbook is opened.
Hey presto, the problem is solved.
The Welcome sheet actually has a dual purpose, in that if either of the yellow-backed warning messages are displayed, it will remain and force the user, with suitable instructions, to click Enable Editing and/or Enable macros. If the users aren't au fait with macro-enabled Excel, they will just ignore these and try to carry on regardless.
All this is much easier to implement than to explain. I hope it's clear.
And I hope this might be of help to someone.
I had this issue with one of my files as well. I managed to fix this issue by running Workbook_Open manually in the VBA editor once open and saving the file in another location. The file in the new location should have no issue with auto-running Workbook_Open. If this doesn't work, copy the original file to a new location before manually running & saving.
If the newly saved file does not run Workbook_Open, repair your version of Office.
I have a VBA program that asks for the user to enter a desired range, which is in another opened workbook. If there is an error, i.e. the other workbook is manually activated, but no range is selected, or there is an error, I want the program to display the original macro workbook sheet with an error message. The code below works in Debug mode, but when the VBA program is run, it displays the error correctly but does not display the original macro worksheet. It remains on the sheet that was manually activated by the user. What am I missing?
In the code below, "HMArea" is a Range variable returned by the routine getting user input.
"Macro_Fname" is a string variable for the file name of the original VBA program.
HM_file = FileName(HMArea)
If HM_file = "Macro_Fname" Then
Windows("Macro_Fname").Activate
Sheets("[name of the sheet in Macro_Fname]").Select
Range("D4").Select
MsgBox "ERROR: No data selected"
Exit Sub
End If
Try changing
Windows("Macro_Fname").Activate
to
Workbooks("Macro_Fname").Activate
However, the exact nature of your question is vague. Assuming you are in Workbook A, do you want to select a range in Workbook B (which is open at the same time)?
To refer to macro workbook use ThisWorkbook
When another workbook is opened always assign it to variable so that you can have control over it.
Set wbk = Workbooks.Open("D:\test.xlsx")
When working with multiple workbook always prefix the workbook object. If its ignored it will take active workbook.
`Sheets("[name of the sheet in Macro_Fname]").Select`
Avoid using Select/Acitvate. See here
Range("D4").Select
Once the above issues are fixed your code will run as expected.