Open a workbook (mode automatic) by VBA command without recalculating it - vba

In my VBA addin.xlam, I use workbooks.Open("C:\f.xlsm") to open workbook f.xlsm. The workbook calculation mode of f.xlsm is Automatic, thus I realize that everything in f.xlsm is recalculated automatically, after calling workbooks.Open("C:\f.xlsm"). But this is not what I want.
Is it possible to open a workbook by VBA command without refreshing it, even though the mode of the workbook is Automatic?
Edit 1:
I tried the idea #Ripster suggested:
1) I created a class model CExcelEvents in addin.xlam:
Private WithEvents App As Application
Private Sub App_WorkbookOpen(ByVal Wb As Workbook)
Application.Calculation = xlCalculationManual
End Sub
Private Sub Class_Initialize()
Set App = Application
End Sub
2) I linked CExcelEvents to the code in addin.xlam which opens f.xlsm:
Private XLApp As CExcelEvents
Sub try()
Set XLApp = New CExcelEvents
workbooks.Open ("C:\f.xlsm")
End Sub
Then, what try() does turns out to be first opening f.xlsm (which triggers automatic recalculation), then changing its calculation mode to manual. The workbook has been already re-calculated before changing the mode --- it is too late! Does anyone have any idea?

Try setting XLCalculation to Manual immediately before you open the workbook:
Sub try()
Application.Calculation = xlCalculationManual
workbooks.Open ("C:\f.xlsm")
End Sub

Related

VBA: Running Workbook_BeforeClose from general module and not ThisWorkbook of Active Workbook

So I have a macro I wrote that I want to run on close of the workbook.
Unfortunately, the only way to apparently do this is to place the macro in the ThisWorkbook module of the actual file as opposed to having it sit in the PERSONAL.XLSB.
This is not desirable for a few reasons:
The macro would have to be put into every workbook it needs to be run on--I have hundreds.
The workbooks would need to be saved as macro enabled which, in my experience, many email servers won't accept emails with macro enabled workbooks attached.
So ideally I would like to be able to run the macro from the PERSONAL.XLSB in just a general module.
Any suggestions about how this might be possible?
EDIT:
Per instructions at:
http://www.cpearson.com/excel/AppEvent.aspx
PERSONAL.XLSB
CExcelEvents class module
Private WithEvents App As Application
Private Sub Class_Initialize()
Set App = Application
End Sub
Private Sub App_WorkbookOpen(ByVal Wb As Workbook)
MsgBox "New Workbook: " & Wb.Name
End Sub
PERSONAL.XLSB
ThisWorkbook
Private XLApp As CExcelEvents
Private Sub Workbook_Open()
Set XLApp = New CExcelEvents
End Sub
Doesn't work if you try to open a different workbook. If you click on PERSONAL.XLSB in recent documents it will trigger the message.
Move this into another ThisWorkbook object for a specific workbook and it still only works on that workbook:
Private XLApp As CExcelEvents
Private Sub Workbook_Open()
Set XLApp = New CExcelEvents
End Sub
So even though the class module is in PERSONAL.XLSB, it appears you still have to put the above into the workbook you want it to run on it, which I think I would still require saving it as an .XLSM and would run into email filter issues.
For some reason this did start working with everything in PERSONAL.XLSB although I didn't change anything. Exciting, but would like to know why.
However, now that I am trying to change the example to actually work how I need it with BeforeClose. So I updated to the following:
PERSONAL.XLSB
CExcelEvents class module
Private WithEvents App As Application
Private Sub Class_Initialize()
Set App = Application
End Sub
Private Sub App_WorkbookBeforeClose(ByVal Wb As Workbook, Cancel As Boolean)
MsgBox "Closing the workbook."
End Sub
PERSONAL.XLSB
ThisWorkbook
Private XLApp As CExcelEvents
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Set XLApp = New CExcelEvents
End Sub
Back to what happened yesterday... will only trigger when you go to close PERSONAL.XLSB. One would think that since the PERSONAL.XLSB opens with all workbooks, it would trigger regardless, but it isn't. Again, saving in the ThisWorkbook object of the target workbook works, but isn't a solution due to having to save as an .XLSM and email filters.
You can look at Application Events, which allow you to hook into events at the Application level, using code which can be in your Personal.xlsb
Here's a good starting point: http://www.cpearson.com/excel/AppEvent.aspx

Running vba code whenever a workbook is opened

I'm writing vba which manipulates data within a worksheet however I'm trying to make it run whenever a workbook is opened.
The problem I'm having is that due to the workbook (that the code needs to run on) is different/new every time, I need the auto_open code to be within a personal macro workbook.
Sub Auto_Open()
Dim bookname As String
Dim checkbook As String
Dim Workbook As Workbook
For Each Workbook In Application.Workbooks
bookname = Workbook.Name
checkbook = Left(bookname, 3)
If checkbook = "EDN" Then
Data_generator
Application.DisplayAlerts = False
ThisWorkbook.Save
Application.DisplayAlerts = True
Application.Quit
Else
End If
Next Workbook
End Sub
When this code runs it checks all open workbooks and sees if the first 3 letters of it are 'EDN', if it is then run the public sub called 'Data_generator', save it and quit. If it isn't check the next open workbook, etc.
When a file is opened from windows explorer, excel launches (with both the desired workbook and the personal macro workbook) however because excel opens the personal macro workbook first and runs the code before opening the desired workbook it doesn't find a workbook called 'EDN'.
If the above code is ran after both workbooks have opened then the code works as intended and cycles through each open workbook to see if there's one called 'EDN' (this was proved by putting a messagebox after the 'then' and running the code), if so run the sub.
I've proved this by putting a messagebox after the 'else', when this is done it displays the messagebox with the workbook I want, not open. After the message box is cleared, the workbook then opens.
Is there any way to make the desired workbook open first or any other work around for this?
You can create an Add-in that runs whenever a workbook is open
https://msdn.microsoft.com/en-us/library/office/gg597509(v=office.14).aspx
this tool may help to create the Add in http://www.andypope.info/vba/ribboneditor.htm
You should be able to use the Application.OnWindow event to trigger a macro when a file is opened or closed.
In ThisWorkbook
Private Sub Workbook_Open()
Call StartTracking
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Call StopTracking
End Sub
In a Module
Function StartTracking()
Application.OnWindow = "AutoRunOnWindowChange"
End Function
Function StopTracking()
Application.OnWindow = ""
End Function
Function AutoRunOnWindowChange()
If Left(ActiveWorkbook.Name, 3) = "EDN" Then
Call Data_generator
Application.DisplayAlerts = False
ThisWorkbook.Save
Application.DisplayAlerts = True
Application.Quit
End If
End Function

Re-using a VBA macro with "Worksheet_Change" event in all open workbooks in a single file

The following VBA code snippet should be executed in all open workbooks within a single Excel file (*.xlsm):
Private Sub Worksheet_Change(ByVal Target As Range)
...
End Sub
We do not want to copy the code in each workbook to reduce code duplication.
When trying to create a new Macro via the Excel "Macro" dialog it offers the possibility to locate the Macro in:
all open workbooks
this/current workbook
current file
When choosing (1) in combination with a Macro name, e.g. "MultiSelect" Excel jumps in the VBA editor and scaffolds a basic method according to the given name:
Sub MultiSelect()
...
End Sub
Our question: how to guarantee reacting on "Worksheet_Change" events within this macro?
With the help of "Robin Mackenzie" I found a solution :) Especially, reading section Application Events In A New Class Module helped. So, I created a new class named "CExcelEvents":
Private WithEvents App As Application
Private Sub App_SheetChange(ByVal Sh As Object, ByVal Target As Range)
'gets the code more robust when the SheetChange event is called twice
If Me.EnableEvents = False Then
Exit Sub
End If
Application.EnableEvents = False
...//code to centralize
Application.EnableEvents = True
Me.EnableEvents = False
End Sub
Private Sub Class_Initialize()
'setting a variable for this object
Me.EnableEvents = True
Set App = Application
End Sub
and added in each worksheet - where the central code located in CExcelEvents has to be executed - the following object creation scaffold:
Private XLApp As CExcelEvents
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Set XLApp = New CExcelEvents
Application.EnableEvents = True
End Sub
To prevent eventloops, see: Run a macro when certain cells change in Excel but from my Personal workbook

Workbook_BeforeSave with every active workbook ActiveWorkbook

As I very often have to problem, that the tick vanishes in the settings: Calculate before save. (I don't know the exact term as my office version is in German).
That's why I tried to use VBA to solve the problem. I used the following code in my Excel file:
Option Explicit
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, _
Cancel As Boolean)
If Application.CalculateBeforeSave = False Then
If MsgBox("Caution! Should >calculatebeforesave< be activated?", vbYesNo) = vbYes Then
Application.CalculateBeforeSave = True
Else
End If
Else
End If
End Sub
I put this into "Thisworkbook". But I would like this code to be ran in every workbook I work with (at least all these which allow for macros).
My suggestion was to write ActiveWorkbook_BeforeSave... instead of Workbook_BeforeSave and then put the code in a module in the PERSONAL Macro file. But this doesn't work.
I think you need to use the Excel Applications events rather than workbook events to achieve this, such as in this example
In your PERSONAL workbook right click and insert a a Class Module (Class 1)
Add something similar to below to Class 1:
Public WithEvents appevent As Application
Private Sub appevent_WorkbookBeforeClose(ByVal Wb As Workbook, Cancel As Boolean)
'Add what you would like to happen before a workbook closes
End Sub
Next open ThisWorksheet and add code along these lines (I think the PERSONAL workbook opens automatically when Excel starts):
Dim myobject As New Class1
Private Sub Workbook_Open()
Set myobject = Application
End Sub

Make a sheet act like a button

I want the sheet Administrator to act like a button but I don't want to go to the actual sheet.
It should open up an UserForm and stay on the active sheet if click on Administrator.
You can create a public variable CurrentSheet, initialize it to ActiveSheet in the Workbook_Open event and then in the workbook's SheetActivate event either update the value of CurrentSheet or switch back to the previous current sheet and show the user form. Something like (in the Workbook code sheet):
Public CurrentSheet As Worksheet
Private Sub Workbook_Open()
Set CurrentSheet = ActiveSheet
End Sub
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
If Sh.Name = "Administrator" Then
CurrentSheet.Activate
UserForm1.Show
Else
Set CurrentSheet = Sh
End If
End Sub
On Edit: To be safe you can also add the following code. This adds a layer of protection if something causes your project to reset after the Workbook_Open event. In the original code I was able to generate a crash when I purposely reset the project before activating Administrator.
Private Sub Workbook_SheetDeactivate(ByVal Sh As Object)
Set CurrentSheet = Sh
End Sub
This might render the code in Workbook_Open redundant, but personally I would keep it in since I don't like the idea of having uninitialized global variables, even if they will be initialized before I use them. Also -- if the workbook opens in Administrator (which might be some error condition) this will guarantee that CurrentSheet has a value.