Strange behavior when closing a workbook twice - excel

Strange issue when closing a workbook twice from VBA (Workbook_BeforeClose)
Hi. This problem appears to me in an extremely simple workbook: Workbook_BeforeClose only.
Option Explicit
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ThisWorkbook.Close SaveChanges:=False
End Sub
If I open and close the workbook twice, the main Excel screen looks like this, and it's impossible to do something, I can only close it from the status bar:

If all you are trying to do is to not prompt the user to save changes, just play with the appropriate flags to 'trick' Excel that changes have already been saved.
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Me.Saved = True
End Sub
This will allow the workbook to close, without prompting any changes to be saved, but this does not actually save them.
Notice the subtle difference between the words: Me.Saved and Me.Save.
Saved is a property that gets flipped to False when Excel detects changes were made as of the last save.
Save is a method - not a property as above - that actually will save the workbook.
Your workbook is already closing, which is what fired this event to begin with. No need to try to close it again within this event. Just tell Excel that no changes have been made since the last save, and it should close all on it's own - without the prompts.

It's possible you're re-triggering the event. Try something like this:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Static InProgress As Boolean
If InProgress Then Exit Sub
InProgress = True
ThisWorkbook.Close SaveChanges:=False
End Sub

Related

Why macros are disabled each time I re-start my Excel workbook, even after enabling content...?

Here the context : I'm working on a local workbook (c:) that directly opens a UserForm within the Workbook_Open() Sub. Then, when UserForm is closed, Excel is also automatically closed. Nothing special there.
The problem : Even with a correct setup in my Trust Center Settings (Disable all macros WITH notification), the warning security message pops up again each time I reload that workbook.
Here my code :
Private Sub Workbook_Open()
' modal display of my form
myUserForm.Show vbModal
' upon return from my form, save and close that workbook
Me.Close savechanges:=True
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
' also quit Excel app if no more workbook is opened
If Application.Workbooks.Count = 1 Then Application.Quit
End Sub
I'm pretty sure that's related to the fact that Excel is automatically closed by program, and not by user himself.
For example if I reduce the code to the strict minimum, like :
Private Sub Workbook_Open()
myUserForm.Show vbModal ' modal display of my form
End Sub
In that situation, so without any Close or Quit, I just fall into my main worksheet when the UserForm is closed, then I just manually close Excel, with or without saving, and that's it, warning popup will not appear next time I'll open that workbook.
I don't know if there is a solution without playing with Trust Locations or All macros enabled.
Any ideas ?
Thanks for your help

RefreshAll BeforeSave

I am using power query to combine several tables together and output some info to another table, all within the same workbook.
I would like to ensure the output table is always up-to-date when the file is saved and don't want to depend on ppl using the 'Refresh All' button. Ideally I would have the queries update when the file is being saved.
For each query I have disabled the 'Enable background refresh' option in the query properties. I then have added the following vba code to ThisWorkbook:
Option Explicit
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
ThisWorkbook.RefreshAll
End Sub
This does cause the queries to be updated before the file is saved. However if a user clicks on the save button (causing the queries to update & file saved), and then closes the file they are prompted to save the file again as if something has been edited... I have tried adding a wait command to the BeforeSave method after the refresh however the same behaviour occurs. We could of course just save it again or close without saving (since it was saved when we first hit the save button) however both are not ideal (file is on a network drive, so even though it is only a couple MB it takes several seconds to save, and not a fan of closing without saving).
Any tips for stopping Excel from asking us to save a workbook that we just saved?
Edit
From comments and suggested answers it seems that BeforeSave can be inconsistent. I did want to allow users to be able to close the workbook without saving so wanted to avoid using BeforeClose(for example a user made large changes to the workbook and wanted to undo everything). By manually setting the workbook saved state to true in Aftersave seems to have resolved the issue; atleast in my testing so far (even though it should already be true since it just saved?).
Option Explicit
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
If Success Then
ThisWorkbook.Saved = True
End If
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
ThisWorkbook.RefreshAll
End Sub
Workbook.RefreshAll
It seems like the BeforeSave isn't always working as expected so your feedback is most welcome.
Option Explicit
Private DoNotBeforeSave As Boolean
Private Sub Workbook_BeforeClose(Cancel As Boolean)
With Me
If Not .Saved Then
.RefreshAll
DoNotBeforeSave = True
.Save
Debug.Print "Just refreshed and saved via 'BeforeClose'. Closing!"
Else
Debug.Print "No action taken via 'BeforeClose'. Closing!"
End If
End With
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If Not DoNotBeforeSave Then
With Me
If Not .Saved Then
.RefreshAll
Debug.Print "Just refreshed and saved via 'BeforeSave'!"
Else
Cancel = True
Debug.Print "No action taken via 'BeforeSave'!"
End If
End With
End If
End Sub

Why does VBA Workbook.Close Statement Fail Inside Workbook_BeforeClose, If Close is Triggered Programmatically?

i'd like to intercept BeforeClose with my own process, and cancel the default process. Not working as expected. To replicate, create a new workbook, enter the following, and save:
ThisWorkbook module:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Cancel = True
Application.EnableEvents = False ' to prevent recursively calling this procedure
ThisWorkbook.Close
End Sub
On the Excel front-end, close the workbook manually by clicking the close-X. It will close, as expected, by the ThisWorkbook.Close statement. In Excel 2016 and 365, if other workbooks are open, they remain open.
Beware, EnableEvents will now be false. Close and reopen Excel to restore it, or enter in immediate pane:
Application.EnableEvents = True
Now reopen the same workbook. Put a breakpoint on Workbook_BeforeClose. Go to front end and again manually close the workbook. Step through the code, to confirm what it's doing. Still works fine.
Restore EnableEvents as described above.
Open the file once more. Go to immediate pane, and enter:
ThisWorkbook.Close
The file will not close. Step through the code to see what's happening. Still doesn't close. Why not?
Consider this code:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
MsgBox "Start"
ThisWorkbook.Close
ThisWorkbook.Close
MsgBox "End"
End Sub
This seems to confirm my comment.
If ThisWorkbook.Close could call ThisWorkbook.Close, this would indefinitely spam "Start" message boxes.
Closing the book normally gives you two "start" and one "end"
So it goes back to the start of BeforeClose on ThisWorkbook.Close the first time, then ignores it.
Closing it with ThisWorkbook.Close gives one "start and one "end"
Because it ignores both ThisWorkbook.Close
But
in this case, starting with ThisWorkbook.Close should have them always behave the same. And this isn't the case.
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ThisWorkbook.Close
ThisWorkbook.Close
Cancel = True
Application.EnableEvents = False ' to prevent recursively calling this procedure
ThisWorkbook.Close
End Sub
Take a look how this code executes when closed with ThisWorkbook.Close:
It doesn't close
And then from the menu:
It closes
If we don't disable the events, running it from ThisWorkbook.Closebehaves exactly the same. Steps through, doesn't close.
From the menu however, it's quite different:
And doesn't close.
So it seems that calling Workbook_BeforeCloseusing ThisWorkbook.Close will ignore all other ThisWorkbook.Close, but closing the document with the menu will try to run each ThisWorkbook.Close once.
On the Excel front-end, close the workbook manually. It will close, as expected, by the ThisWorkbook.Close statement.
well, not quite:
If you close from the UI by clicking the Top Right X, the the described behviour dose occur. On the other hand, if you close from the UI by going to File/Close then the behaviour mirrors the immediate window beviour described (doesn't close)
From the documentation
Cancel Required Boolean
False when the event occurs. If the event procedure sets this argument to True, the close operation stops and the workbook is left open.
This explains the observed behaviour.
If you set cancel = True just before ThisWorkbook.Close then it does close.
So, why does clicking the X close it?
I believe it's because that UI is also exiting the Excel Application. The workbook close as a side effect of the Application Quitting, as do all open workbooks.

Closing a workbook without stopping vba?

I keep running into an issue where the worksheet in question gets updated, and then doesn't reflect the changes until I close and re-open the book. It's not really a big deal, I just want to simplify it a bit into a single button click.
I was told that this is impossible to do because closing a workbook will immediately stop execution of code, so you can't reopen the book. But since, I have learned about the PERSONAL.xlsb, and figured since it's a persistent workbook, it could handle the code execution to save, close, and reopen the workbook.
Basically, here's what I've got in the main worksheet:
Public Sub Refresh()
ActiveWorkbook.Save
Application.Run "PERSONAL.xlsb!Module1.RefreshCurrentSheet",ThisWorkbook.Name,_
ThisWorkbook.FullName
End Sub
Which then calls the personal.xlsb macro "Refreshcurrentsheet":
Private Sub RefreshCurrentSheet(ByVal sheetname, Optional ByVal sheetfullname = 0)
Workbooks(sheetname).Close
MsgBox "So far so good!" 'I never see this box
Workbooks(sheetfullname).Open
MsgBox "No errors here..." 'I never see this box
End Sub
This successfully closes the workbook in question, but code execution stops and it doesn't reopen. Is there a way around this? Some way to run the second macro in the persistent sheet without code execution stopping?
We can reopen the workbook using this code inside it (there is no need to use other workbook):
Sub test()
Application.DisplayAlerts = False
Workbooks.Open ThisWorkbook.FullName
Application.DisplayAlerts = True
End Sub

Saving Personal.xls automatically

I use Excel 2003 on a Windows 7 Professional setup.
In my Personal.xls file, I have compiled snippets of code/formulae that I have picked up from different places, to be available for ready reference when I use Excel. These contain a number of volatile functions such as cell(), rand(), today() etc. As a result, when I close Excel, it asks me whether I would like to save Personal.xls.
I would like to keep my Personal.xls as it is, and yet disable the popup somehow. I am fine with saving, not saving, either way, as I won't be changing Personal.xls.
I have tried the following code in my personal.xls in the Workbook_BeforeClose section
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ThisWorkbook.Save
End Sub
But it doesn't seem to work. I have tried some variations, including .Save and .Saved=True, and also tried to alternatively use ThisWorkbook., Me. & Workbooks("PERSONAL.xls"). However, Excel still asks me save Personal.xls
I have also tried to disable calculations in my Personal.xls viz.
Private Sub Workbook_Open()
For Each ws In ThisWorkbook.Worksheets
ws.EnableCalculation = False
Next
End Sub
This doesn't solve the problem either. Finally I tried to do a 'ThisWorkbook.Save' after changing calculation mode to manual, but that doesn't change anything either.
Am I missing something here? Any advice would be appreciated. Thanks in advance!
You want:
Me.Save
In your workbook BeforeClose event.
Why not just force-shut the document?
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ThisWorkbook.Close savechanges:=True
End Sub
For what I was trying to do I am actually using savechanges:=False. Both ways worked.
I just remove the Cancel As Boolean
Private Sub Workbook_BeforeClose()
ThisWorkbook.Save
End Sub

Resources