Can't unprotect an excel worksheet in Workbook_BeforeSave - excel

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

Related

Message box with if condition

I want to save as an excel file as .csv from Sheet2 (Sheet name changes) so I want excel to pop up a message if I try to save as the file from Sheet1. I've a code to pop up the message but I'm not sure how to apply if condition for this scenario. Thank you for your help!!
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean)
If SaveAsUI Then
MsgBox "Make sure you are on correct sheet"
End If
End Sub
This Should Work for you:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If SaveAsUI Then
If ActiveSheet.Name = "Sheet1" Then
MsgBox "Make sure you are on correct sheet"
SaveAsUI = False
End If
End If
End Sub
If you are on Sheet1, the Msgbox will pop and sheet won't be saved.

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

Call a sub in Workbook_BeforeSave event [duplicate]

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

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.

Excel VBA close current workbook Error 1004

I have some VBA code in an Excel workbook.
I have a cell which I would like to use to close the workbook without saving (instead of using the usual (X) close button on the top right corner of excel.
If I close the workbook using the (X) button, it works great the following code.
However if I press the "CLOSE" button cell which is on the worksheet, it gives a 1004 error.
Can anyone help?
ON WORKSHEET WHERE BUTTON IS
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Cells(ActiveCell.Row, ActiveCell.Column) = "CLOSE" Then
CloseNoSave
End If
End Sub
IN THISWORKBOOK
Private Sub Workbook_BeforeClose(Cancel As Boolean)
CloseNoSave
End Sub
IN MODULE
Sub CloseNoSave()
ThisWorkbook.Close savechanges:=False
End Sub
Why don't you just use a single piece of code on your Selection Event
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If ActiveCell.Value = "CLOSE" Then
ThisWorkbook.Saved = True
ThisWorkbook.Close
End If
End Sub

Resources