Call a sub in Workbook_BeforeSave event [duplicate] - excel

This question already has answers here:
Making fields mandatory of a specific sheet on workbook save
(3 answers)
Closed 8 years ago.
I want to call this Sub in the Workbook_BeforeSave event:
Sub test()
If ActiveSheet.Range("A4") = "" Then
MsgBox ("Please fill in cell A4!")
Exit Sub
Else
End If
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
test
End Sub
When I click save the file is saved even if the cell A4 is blank.

You should set Cancel as the proper way to terminate the save event.
It would be better to have test as a function, so you can check the return value, and set cancel appropriately.
Function test() as Boolean
If ActiveSheet.Range("A4") = "" Then
Test = False
Else
Test = True
End If
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If test = False then Cancel=True
End Sub
Also, ActiveSheet is not appropriate, unless you have only one worksheet, and you have protected the workbook from having extra sheets added.
My suggested solution would be to check Sheets("MySheet").Range("A4").
Of course, the laziest way to do the test would be:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
cancel = (ActiveSheet.Range("A4") = "")
End Sub
where the test is done within the save procedure, and no sub tests are required.

Try:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Call test
End Sub
Sub test()
If ActiveSheet.Range("A4") = "" Then
MsgBox ("Please fill in cell A4!")
End
End If
End Sub
Exit Sub merely terminates sub test(), while End completely stops code execution, thus preventing Workbook_BeforeSave() from running further.

if cancel is true, the saving will be blocked :
Sub Test(byref cancel as boolean)
If ActiveSheet.Range("A4") = "" Then
MsgBox ("Please fill in cell A4!")
cancel = true
Exit Sub
'Else
End If
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Test Cancel
End Sub

Related

VBA - Event inside event (BeforeClose -> BeforeSave) not working

I've hijacked saving in an excel file for the purposes of preventing unintended overwrites of a file in an odd environment.
The Workbook_BeforeSave and the Workbook_BeforeClose events work perfectly on their own. Unfortunately, the way the code is currently structured, I would need to call the BeforeSave event from within the BeforeClose event.
In the most basic form, the following code will not do as I'd like. In the following example, wksHiddenWorksheet.Visible = True will not make wksHiddenWorksheet visible if the save is called from within the BeforeClose event.
Option Explicit
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ThisWorkbook.Save
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
wksHiddenWorksheet.Visible = True
End Sub
Is there any way around this? Is it poor practise (or even fundamentally incorrect) to call an event from inside another event in the way that I'm attempting?
Update:
I have played around with Application.EnableEvents in the workbook, but I've made sure it always reverts back to True in error handling.
I've opened a brand new workbook and entered the following code
Option Explicit
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Debug.Print Application.EnableEvents 'Prints TRUE
ThisWorkbook.Save
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
'The workbook consists of two sheets. Sheet1 and Sheet2
Sheet1.Visible = xlSheetHidden
Debug.Print Sheet1.Visible 'Prints -1 (xlSheetVisible)
End Sub
The Visible sheet does not become hidden, though the line is triggered if I go line by line through the code. If I enter code such as a MsgBox in the same space, the MsgBox will open as normal.
Update 2:
To answer everyone's questions and display exactly what happens, please see the below code:
Option Explicit
Private Sub Workbook_BeforeClose(Cancel As Boolean)
'The workbook consists of two sheets. Sheet1 and Sheet2
Debug.Print Application.EnableEvents 'Prints TRUE
Debug.Print Sheet1.Visible 'Prints -1 (xlSheetVisible)
Sheet1.Visible = xlSheetHidden
Sheet1.Visible = False 'Same thing
Debug.Print Sheet1.Visible 'Prints 0 (xlSheetHidden)
Sheet1.Visible = xlSheetVisible
Sheet1.Visible = True 'Same thing
Debug.Print Sheet1.Visible 'Prints -1 (xlSheetVisible)
ThisWorkbook.Save
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Debug.Print Sheet1.Visible 'Prints -1 (xlSheetVisible)
Sheet1.Visible = xlSheetHidden
Sheet1.Visible = False 'Same thing
'Sheet1 should now be hidden, but it's not
Debug.Print Sheet1.Visible 'Prints -1 (xlSheetVisible)
End Sub
Hiding and unhiding sheets works perfectly in the first event, but as soon as the second event is triggered, the sheet visibility does not change.
Update 3:
Another point. If I enter the Workbook_BeforeSave() event directly (by saving), rather than entering it from the Workbook_BeforeClose() event, then everything works as expected.
MUCH LATER UPDATE:
Although I marked this question as solved a while ago, I've come across an article that helps to explain the behaviour. An explanation can be found at:
http://www.cpearson.com/excel/events.aspx
edited after all clarifications
the following code worked for me
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Workbook_BeforeSave False, True
ThisWorkbook.Save
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If Cancel Then Sheet1.Visible = xlSheetHidden
End Sub
hard to tell why though...
In this example procedure HideSheet is called from BeforeSave and from BeforeClose event handler. So both handlers hide the sheet. HTH
Private Sub Workbook_BeforeClose(Cancel As Boolean)
HideSheet Sheet1
ThisWorkbook.Save
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
HideSheet Sheet1
End Sub
Private Sub HideSheet(wks As Worksheet)
wks.Visible = xlSheetHidden
End Sub

Refuse save if cell contains text

I have this code, that refuses and cancels to save a workbook if a cell contains a specific text. the code is working fine, but if i want it to refuse saving if some cells in a range contains specific text then it is not working. my code below that is working:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If Sheets("Sheet1").Range("A1").Value = "Fill in a comment" Then
Cancel = True
Response = MsgBox("Fill in a comment", vbCritical, "Error!")
End If
End Sub
the code that i tried to make it work but its not
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean
For Each c In Sheet1.Range("A1:A5000")
If c.Value = "Fill in a comment" Then
Cancel = True
Response = MsgBox("Fill in a comment", vbCritical, "Error!")
End If
Next
End Sub
do you guys have any ideas?
Try this instead rather than looping:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Cancel = Not Sheet1.Range("A1:A5000").Find("Fill in a comment") Is Nothing
If Cancel Then MsgBox "Fill in a comment", vbCritical, "Error!"
End Sub
It uses the .Find() method to look for "Fill in a comment" and if it isn't Nothing then Cancel is set to True
Then, we test the value of Cancel to see if we need to display the message box.
Doing it this way also makes sure that you don't get 500 message boxes if you have "Fill in a comment" written in 500 different cells in that range...

Close button : empty cell condition

I found this code and it works perfectly. But when I hit close button, dialog is shown "Do you weant to save changes", and if I choose Yes, an error comes up that I don't have a value in a cell A. And then my file is automatically closed.
How to prevent this, and to stay in the document?
My code is:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If ActiveSheet.Range("A1").Value = "" Then
Cancel = True
Response = MsgBox("Please enter a value in A1", vbCritical, "Error!")
End If
End Sub
Have you tried using BeforeClose instead of BeforeSave?
Private Sub Workbook_BeforeClose(Cancel As Boolean)
If ActiveSheet.Range("A1").Value = "" Then
Cancel = True
Response = MsgBox("Please enter a value in A1", vbCritical, "Error!")
End If
End Sub
Regards

Auto opening excel vba macro, beforeclose and beforesave

I have an .xlsm file which i want to run the macro automatically when i open it. The current file is saving the file as .xls in a different location with a different name before saving and before closing. However before closing is giving me error and so is the autorun of macro. Here is my code.
Private Sub Workbook_Open()
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Application.ScreenUpdating = False
Application.DisplayAlerts = False ' so you can overwrite without warning
ActiveWorkbook.SaveCopyAs "C:\Users\name\Desktop\testing.xls"
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Application.ScreenUpdating = False
Application.DisplayAlerts = False ' so you can overwrite without warning
ActiveWorkbook.SaveCopyAs "C:\Users\name\Desktop\testing.xls"
Application.DisplayAlerts = True
Application.ScreenUpdating = True
ActiveWorkbook.save
End Sub
End Sub
For starters, you can't have events inside another event like that. You have a Workbook_BeforeSave and Workbook_BeforeClose inside your Workbook_Open... That won't work, and in any case I'm not sure what it would even mean!
Private Sub Workbook_Open()
' This won't work:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
'...
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
'...
End Sub
End Sub
You need to set up your events separately, like this:
Private Sub Workbook_Open()
'Stuff to do when file opens...
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
'Stuff to do before user saves the file...
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
'Stuff to do before the user closes the file...
End Sub
Also, instead of ActiveWorkbook, consider using Me (or ThisWorkbook) to avoid any ambiguity.

Can't unprotect an excel worksheet in Workbook_BeforeSave

I am using Workbook_BeforeSave to update some cells on a locked sheet in excel 2010. The subroutine works as desired when using ctrl-s to save, but will not unlock the sheet when using .Save in vba.
ThisWorkbook(code)
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim MyPassword As String
MyPassword = "password"
ActiveWorkbook.Worksheets("Sheet1").Unprotect (MyPassword)
ActiveWorkbook.Worksheets("Sheet1").Range("A1").Value = Now
ActiveWorkbook.Worksheets("Sheet1").Range("A2").Value = ThisWorkbook.BuiltinDocumentProperties("Author")
ActiveWorkbook.Worksheets("Sheet1").Protect (MyPassword)
End Sub
Module1(Code)
Sub SaveMe()
ActiveWorkbook.Save
End Sub
I have a button that calls SaveMe(). SaveMe() saves the document, activating Workbook_BeforeSave. The Worsheet fails to unprotect, causing an error when writing to A1.
The error states:
Run-time error '1004':
Application-defined or object-defined error
This worked for me, but it is not very elegant. I did not find a separate module for both unprotecting and writing worked.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
UnlockWorksheets
With ThisWorkbook.Worksheets("Sheet1")
.Range("A1").Value = Now
.Range("A2").Value = ThisWorkbook.BuiltinDocumentProperties("Author")
End With
LockWorksheets
End Sub
Sub SaveMe()
UnlockWorksheets
ThisWorkbook.Save
LockWorksheets
End Sub
Sub UnlockWorksheets()
ThisWorkbook.Worksheets("Sheet1").Unprotect Password:="password"
End Sub
Sub LockWorksheets()
ThisWorkbook.Worksheets("Sheet1").Protect Password:="password"
End Sub
why not put the 'before save' module into a new sub routine and have the before close call that
EG.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Call SomeSub
End Sub
sub someSub()
'Code here
end sub
sub Button()
call SomeCub
activeworkbook.save
end sub

Resources