How do I disable and enable macros on the fly? - vba

I would like to test an Excel VBA app I made.
However the VBA code messes around with the visibility of cells and that's a pest when editing the sheet.
Is there an option is enable and disable macro's on the fly without having to
Close the sheet
Change the macro settings
Reopen the sheet
Close the sheet
Change the macro settings.
etc.

As far as I know, you can't enable / disable macros from an opened workbook on the fly.
Yet, you shouldn't have to because macros are only triggered thanks to a user click.
The only case I would see is for the Event Procedures (Worksheet_Change or else).
You could then create procedures to activate / deactivate events and call them from buttons in your worksbook:
Sub enableEvents()
Application.EnableEvents = True
End Sub
Sub disableEvents()
Application.EnableEvents = False
End Sub
You can also try these tips from Chris Pearson website using global vars you would change depending on your needs:
Public AbortChangeEvent As Boolean
And check if afterwards:
Private Sub Worksheet_Change(ByVal Target As Range)
If AbortChangeEvent = True Then
Exit Sub
End If
'
' rest of code here
'
End Sub

To disable macros on the fly, use "Application.EnableEvents = False" via the Immediate window in the VBA editor (and "Application.EnableEvents = True" to turn them back on).

You can also hold down SHIFT when you open a document to disable macros.

As of Excel 2010* there's actually an option on the "Developer" tab which allows you to disable macros as easy as ABC. Design Mode lets you do just that!
*Maybe even earlier versions.

I often fire Macros when opening a workbook but sometimes I don't want the Macro to fire so I can work on the code. So what I put a Macro in a separate workbook that does the following:
Disables macros
Opens the workbook in question
Enables macros
Then closes the original workbook
Leaves the second workbook open
Here's the code:
Sub OpenClose()
'Opens Workbook below with Macors disabled
'After it is open Macros are enabled
'This Workbook then closes without saving changes, leaving only the workbook below open
'************************************************************
'User only needs to change the workbook name on the next line
WorkbookToOpenNoMacros = "Gaby.xlsm"
'************************************************************
Dim wb As Workbook
Set wb = Application.ThisWorkbook
Application.EnableEvents = False
Application.Workbooks.Open (ActiveWorkbook.Path & "\" & WorkbookToOpenNoMacros)
Application.EnableEvents = True
wb.Saved = True
wb.Close SaveChanges:=False
End Sub

I have Office 2013 and I found a button on the VBA window that did this for me very easily.
There's a play, pause and stop button on the toolbar. In Excel, they are actually called, Run Macro, Break and Reset.
Click the Break button (pause) and any running macros should stop running. I only tested it on one macro but seems reasonable to presume that this will work in general.
Also, I believe those buttons were there for many versions of Excel, so it's worth checking earlier versions.

Related

How to make vba code to run auto-close only on active workbook?

Here's the scenario. I have multiple excel workbooks that copy and paste data among each other. So the macro works to open.copy.close from one workbook then open.paste.close to another. I am working on creating a function to auto run macro when file is closed.
Here's the issue, when I click macro button in workbook 1, it is supposed to open.copy.close from workbook 2. However, because of the auto run when file is closed function in workbook 2, an error will occur (2 macros cannot run at the same time)Any solution for this? I am looking for a solution to only auto run macro when file is closed IF IT IS AN ACTIVE WORKBOOK. Here is what I have now:
Workbook 1
Sub workbook_beforeclose(cancel As Boolean)
Application.Run "Sheet1.UpdateYellowTabs_Click"
End Sub
Workbook 2
Sub Workbook_BeforeClose(Cancel As Boolean)
Workbook.BeforeClose
Application.Run "Sheet12.UpdateGreen_Click"
End Sub
How do I code it in the workbook code to only make this run only when it's active/closed by a human user and not when open/close by macro?
Thanks!
Well I am not sure to understand your final goal from this, but I can answer the "technical" question. Technically, if you want to check if a given workbook is active: If Application.ActiveWorkbook Is Me,
Private Sub Workbook_BeforeClose(Cancel As Boolean)
If Not Application.ActiveWorkbook Is Me Then Exit Sub ' <-- add this test
''''''''''''''''''''''''''
' Whatever code goes here
''''''''''''''''''''''''''
End Sub
EDIT
But problem is that invoking wb2.close will make the workbook wb2 the "active" one during the execution of the macro. So this method won't work. Another method is to disable events before closing the workbook; so that the event Workbook_BeforeClose will not fire. After that, you can enable events back if needed. The code looks like this:
' ... open wb2 and do the work with it
Application.EnableEvents = False
wb2.Close False
Application.EnableEvents = True
notice, if you had already disabled events at the beginning of the current macro, which is usually recommended, then this additional code wouldn't be needed.

Cannot close workbook after running sub with userform

I have a macro that opens a userform to capture a start and end date. After clicking OK on the userform, a file dialog box opens to select an Excel Workbook to open.
Immediately after I run the below sub, I can't close the workbook that is opened by using the 'X' in the top-right corner. I also can't save the workbook by clicking the save icon.
However, if I click on another workbook or switch to a different sheet in the workbook that was opened, and then click back to the one opened by the sub everything works as it's supposed to.
Also, I replace the userform with two input boxes, to capture each of the two dates, I am able to close the workbook that is opened with no issue.
Maybe there's something funny with the userform code?
This is all that is in the userform.
Private Sub Ok_button_Click()
call module1.forecast
unload userform1
end Sub
And this is the main sub.
Sub forecast()
dim start_SFY as long
dim end_SFY as long
dim filesToOpen as object
dim wb as workbook
Application.ScreenUpdating= False
start_SFY = userform1.textbox1.value
end_SFY = userform1.textbox2.value
set filesToOpen = application.fileDialog(msoFileDialogOpen)
filesToOpen.show
set wb = application.workbooks.open(filesToOpen.selecteditems(1),false)
Application.ScreenUpdating= True
End Sub
Here's the sub showing userform1
Sub run_userform()
userform1.show
End Sub
Also, here is the Excel version:
Excel 2013 64-bit (15.04753.1003) Part of Microsoft Office 365 ProPlus
Can someone maybe try to replicate the issue that I'm having? I'm wondering if this is an issue related to my employer's version of Excel or something?
This sort of thing has never happened to me before.
Also, I can close the program with VBA. It's just when trying to click the 'X' that it won't close.
Update:
I was able to get the code, with no changes, to work fine at home on Excel 2016. I'm going to get a coworker to test on their system today.
When I was home, I didn't put a button to call the sub on a worksheet. I called it from the VBA editor. After some testing this morning, it seems that the button is the issue. If I call the sub from the VBA editor, I can close the opened workbook. However, if I use a command button (form control, not ActiveX as I get an error saying, "Cannot draw object" whenever I try to add any kind of ActiveX object to a worksheet) the opened workbook will not close.
I think I have found the problem
This issue seems to be with the 'form control command button'. ActiveX was disabled in the Trust Center. When I enabled it and created a command button, I was able to close the opened workbook. I then tried the command form button again, and could not close the opened workbook. I was also successfully able to close the opened workbook when I ran the sub from the sub listbox in the developer tab, and when I place the sub in the Excel Ribbon and ran it from there.
Any idea as to why the control form command button would cause this issue?
The root of the problem is the change to using multiple excel interfaces in 2013. Microsoft addresses the issue in the Solutions for SDI Issues section of this page.
A workbook cannot be closed by clicking the red "X" Close button when
that workbook is programmatically opened via a modal user form. To
work around this issue, it is suggested that you add the following
code to the user form Layout event procedure and then open the user
form as modeless
Private Sub UserForm_Layout()
Static fSetModal As Boolean
If fSetModal = False Then
fSetModal = True
Me.Hide
Me.Show 1
End If
End Sub
Another option is to open the workbook window, activate any other
window, and then reactivate the workbook window. You should now be
able to close the workbook using the Close button.
So these are the two options they present and one I came up with.
Option 1) You can switch your dialog to modeless using their code, or by setting the ShowModel property to false in your userform.
Option 2) As you discovered, manually switching between workbooks after opening via modal userform resyncs everything. Not a good solution for the users of my code, and I don't recommend relying on it.
Option 3) It's worth mentioning, if you don't open the file via the userform then there's no issue. So if last thing the userform needs to do is open the file, you can easily save the file path in a string, unload the troublesome userform and move the workbooks.open call after closing. Here's an example of what I mean
Public EDIT_FILE_DIRECTORY As String
Public Sub Main()
fileOpenerForm.Show
If EDIT_FILE_DIRECTORY <> "" Then
Call Workbooks.Open(EDIT_FILE_DIRECTORY)
End If
End Sub
And in the userform something along these lines, where the filename is created based on userform parameters and a listbox selection:
Private Sub OpenSelectedWorkbooks_Button_Click()
Dim workbookName As String
workbookName = selectionList.Item(Me.FileSelection_ListBox.ListIndex + 1)
EDIT_FILE_DIRECTORY = ROOT_DIR & GetSelectedSubfolder & "\" & workbookName
Unload Me
End Sub
Try fileOpenerForm Show 0 to open open it with Modal = False (Makes the macro run while the Userform is visible)
Do not forget to add fileOpenerForm.Hide later on.
Also Load fileOpenerForm and Unload fileOpenerForm may be useful

unable to close opened excel workbook

I am building a excel file with commandbuttons, userforms etc. that contain links to other workbooks.
For the commandbuttons on my sheet I use the same code as for the commandbuttons in my userforms:
workbooks.open "path"
with the userform commandbuttons ater this the following is added
unload me
When I open a workbook via a userform I am unable to close it afterwards. I must activate my workbook first, then activate the opened one and then can I close it
I have tried putting "unload me" befor and after the "workbooks.open" but this doesn't change anything.
I also tried the followin, also didn't work:
unload me
dim wb as workbook
set wb = workbooks.open"pathname"
wb.activate
anyone any ideas?
Example of how it is now:
Someone needs to make a price calculation. they open the prices userform in my file. they click on the button "calculationfile". The calculationfile opens. they make there calculation and now they are finished in the calculationfile. So they want to close it by clicking on the cross. But they can't click the cross. then they switch to my file on the taskbar and then switch back to the calculation file. now they are able of clicking the cross
I dont understand why they can't click it the first time but they can click it after switching between mine and the openend workbook.
I suspect this is due to improper form handling and the "default instance" recreating itself after you unload it. If you don't create your own instance of the form before you show it, VBA will do all kinds of squirrelly things when you use it after it's unloaded.
If all you need to do is open a workbook and unload the form, *don't increment the workbook's reference count before you unload the form. Also, don't attempt to run any other code after you call Unload Me from the form. The code you posted should simply be:
Workbooks.Open "pathname"
Unload Me
Of course the calling code for the form isn't in the question, but it can likely be solved there as well.
Unload only affects a UserForm.
Try adding a reference to the open workbook and then closing it like so:
dim wb as Workbook
set wb = Workbooks.Open "pathname"
wb.activate
' do whatever with it while it's open
wb.Close
If whatever you are doing is not automated, you will need a button on your form that will set the reference to the workbook and close it once the user has completed editing.
If you define the workbooks that you open as a variable - you will be able to close them easily. Keep in mind this does not save the workbook.
Dim DataBook As Workbook
Set DataBook = Workbooks.open ("pathname")
' Do something useful with the file
DataBook.Close
It is not completely clear what you are trying to ask here, but I'll give it my best in providing you a full answer. If you are having no success with the Unload Me statement when it comes to closing a user form, try specifying the full form name in VBA. That is:
Unload UserFormName
If you are trying to close the workbook you have opened (via the user form), you can use the Workbooks.Close method:
Dim wb as Workbook
Set wb = Workbooks.Open(Filename:="C:\example.xls")
wb.Activate
'Close workbook
wb.Close
'Unload form
Unload ExampleForm
More on the use of the Unload statement can be found here:- https://msdn.microsoft.com/en-us/library/aa445829(v=vs.60).aspx
And more on the use of the Workbooks.Close statement can be found here:- https://msdn.microsoft.com/en-us/library/office/ff838613.aspx
I'm not sure what's causing the behavior you describe (inability to click the "Close" X button in the active Excel window). However your current workflow is:
User interacts with form to review/access a file
User clicks a button on the form which unloads the form
User is then expected to manually close out of the file opened in (1)
A better solution would be to remove the third step, and close the workbook from one of the form's event-handlers (UserForm_QueryClose or UserForm_Terminate). Alternatively you could add this to a CommandButton's Click event, but that's not very different than requiring the user to manually close the file.
This could be as simple as:
Private Sub UserForm_Terminate()
' should be called when form Unloads
On Error Resume Next
Workbooks.Close "filename.xlsx"
End Sub
In this manner, the file will be closed any time the user closes or otherwise unloads the userform.
OK I think I found a way around it.
Let's say I have a workbook1 which has a form called ControlPage with command button that opens up workbook2.
Private Sub CommandButton1_Click()
Dim workbook2 As Workbook
Dim workbook1name As String
workbook1name = ThisWorkbook.name
Set workbook2 = Workbooks.Open("workbook2.xlsx")
ControlPage.Hide
Workbooks(workbook1name).Activate
Workbooks("workbook2.xlsx").Activate
End Sub
So basically because 'activate' bit doesn't seem to work properly when I try to activate workbook 2 straight away, I just activate the first, and then the second one ane after another. Twisted but did the trick for me.

VBA - Workbook Macro Pass Error

I have created an Excel file containing about 5 pages of vba code. All was good until,I choosen to create a macro for the workbook for its protection. Something like.
Dim pass as string/
if pass <> "PAR> or pass<>"par" then activeworkbook.close.
I think that the OR messes the things up. Now I can't access my workbook. Whatever pass I introduced it closes the workbook. I may mention here that pass is an inputbox.
Can someone help me in resolving this problem. I've lost my entire work.
LE: i've made it! Thank you for your support! :)
Try this way:
Sub main()
Dim secAutomation As MsoAutomationSecurity
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Remember the macro security settings and disable macros in target workbook. '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
secAutomation = Application.AutomationSecurity
Application.AutomationSecurity = msoAutomationSecurityForceDisable
Workbooks.Open "<path to your workbook>"
''''''''''''''''''''''''''''''''''''''''''''''
'Reinstate previous macro security settings. '
''''''''''''''''''''''''''''''''''''''''''''''
Application.AutomationSecurity = secAutomation
End Sub
or manually change your Macro settings to 'Disable all macros with notification'
open any other workbook and get to the VBA IDE (ALT+F11)
type in Immediate Window
application.EnableEvents=False
then you can open your "impossible" workbook
as soon as you need things back regular type in the Immediate Window
application.EnableEvents=True
Try to open another workbook, and use statement application.enableEvents = false then before close this workbook, open workbook you wish

Application.Calculation depending on workbook

I'm managing a workbook with more than 200 000 formulas (some really complicated array formulas) which means that I can't let Excel automatically calculate all the cells every time I click somewhere (it takes around 8 hours to calculate everything).
Instead of that, the calculation is set to manual and I have the following VBA code executed when Calculation.xlsm is opened:
With Application
.CalculateBeforeSave = False
.Calculation = xlCalculationManual
End With
I use custom buttons to calculate only some parts of the 200k cells when needed.
I noticed that Excel does keep track of that setting in each workbooks, which means that if I open my Calculation.xlsm, Excel remembers that the calculation is set to manual. If I open my Values.xlsx, Excel does remember that the calculation is set to automatic. This was before I tried to copy values from Calculation.xlsm to Values.xlsx.
Now, because I'm using VBA in Calculation.xlsm to copy values to Values.xlsx, Excel does apply the Application.Calculation setting to that workbook too, which means that if I open it with a new instance of Excel, the calculation will still be set to manually.
If I add a Application.Calculation = xlCalculationAutomatic before closing the Values.xlsx with VBA in my Calculation.xlsm workbook, it will work, but Excel will also start to compute the 200k cells in my Calculation.xlsm workbook, which I obviously don't want.
So my question is about how to actually set the calculation of Excel based on a specific workbook instead of with the Application object. This is based on the fact that Excel does keep track of that setting depending on which workbook is opened (you can just do the test and create 2 different .xlsx files, one with the calculation enabled and the other with the calculation disabled and Excel will remember these settings).
I know I could use the Worksheets.Range.Calculate method to calculate my Values.xlsx workbook before closing it, but the calculation will still be set to manual if I open it in a new instance of Excel after that.
EDIT 3:20pm: Not sure if I was clear enough, English isn't my native language. In short, I have Calculation.xlsm with VBA and Calculation set to manual. I have Values.xlsx with no VBA and Calculation set to automatic. If I open Values.xlsx with the following VBA code in Calculation.xlsm, Excel will automatically convert my Values.xlsx workbook to manual calculations.
Calculation.xlsm code:
Private Sub Workbook_Open()
With Application
.CalculateBeforeSave = False
.Calculation = xlCalculationManual
End With
End Sub
Sub someFunction()
Set WB = Application.Workbooks.Open("Values.xlsx")
Set WBws = WB.Sheets("mySheet")
DoEvents
wb.Save
WB.Close
End Sub
After the execution of someFunction(), Values.xlsx calculation is set to manual. That's the problem. I would like it to stay on automatic (and I can't add VBA to that file, it must be all done from Calculation.xlsm like above).
EDIT 3:40pm: Could I just have my big workbook with Application.Calculation set to manual, put all the data I need in the clipboard (I only need the values, not the formulas), close it (will the VBA still continue to execute even if I close the workbook from which it is executed?), set Application.Calculation to Auto (since there is no open workbook), then open the destination workbook to paste the values (will Excel still keep the data in the clipboard since the other workbook is closed?), then save and close that workbook, set back the calculation to manual (no workbook opened) and reopen the original workbook from which the code was executed?
One way to do this would be to create a new instance of Excel. While this is probably slower, and might be more difficult to work with in cases where you don't close the book/application within the function, but for simple case like your example, it may be easiest to implement:
Sub someFunction()
Dim newExcel as Excel.Application
Set newExcel = CreateObject("Excel.Application")
Set WB = newExcel.Workbooks.Open("Values.xlsx")
Set WBws = WB.Sheets("mySheet")
DoEvents
wb.Save
WB.Close
newExcel.Quit
Set newExcel = Nothing
End Sub
The Application.Calculation property is relative to that instance of the application, not other instances.
Alternatively, you can use an application-level event handler. I suspect this might be faster but I have not tested it for speed.
Modified slightly from this very similar question (which also asks about conditionally disabling an Application-level property).
If:
I was just worrying about if the code would still be executed if I close the workbook from which it is launched
Then just use the normal Workbook_BeforeClose event handler to restore the desired Application.Calculation property (for the entire application/all other open workbooks).
The rest of the answer:
Create an application-level event handler, create a class module named cEventClass and put this code in it:
Public WithEvents appevent As Application
Dim ret
Private Sub appevent_WorkbookActivate(ByVal wb As Workbook)
Call ToggleCalculation(wb, ret)
End Sub
Use the following in a standard module named mod_Caclulate:
Option Explicit
Public XLEvents As New cEventClass
Sub SetEventHandler()
If XLEvents.appevent Is Nothing Then
Set XLEvents.appevent = Application
End If
End Sub
Sub ToggleCalculation(wb As Workbook, Optional ret)
If wb.Name = ThisWorkbook.Name Then
ret = xlCalculationManual
Else
ret = xlCalculationAutomatic
End If
Application.Calculation = ret
End Sub
Put this in the Workbook_Open event handler of the workbook which you always want to be manual calculation:
Option Explicit
Private Sub Workbook_Open()
'Create the event handler when the workbook opens
Call mod_Caclulate.SetEventHandler
Call mod_Caclulate.ToggleCalculation(Me)
End Sub
This will create the event handler only when the specific workbook is opened, and the handler will toggle the Calculation property whenever you switch views to a different workbook.
Note: If you "end" run-time or do anything while debugging which would cause state loss, you will lose the event handler. This can always be restored by calling the Workbook_Open procedure, so an additional safeguard might be to add this also in the ThisWorkbook code module:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
' Additional safeguard in case state loss has killed the event handler:
' use some workbook-level events to re-instantiate the event handler
Call Workbook_Open
End Sub