Why is the workbook protected upon Workbook_Open Event? - vba

I adapted some code found here http://www.vbaexpress.com/kb/getarticle.php?kb_id=379 for a neat solution that forces users to enable macros. This method is a really good way of getting around this problem. However, my additional requirements are: one particular user needs a more sensitive version of 2 sheets within the workbook. Depending on the answer to a MsgBox an InputBox requires password verification and then shows the sensitive versions of these sheets.
I believe the answer lies in how the workbook is saved and then how all sheets are unhidden upon re-opening the workbook (since two of the sheets are effectively password locked) but somehow now when I open this workbook the password used for unhiding the two sensitive versions of the sheets is required to open the workbook.
So I changed the password required for verification of the said sheets but the Original password is still required to open the workbook:
Any assistance in diagnosing this problem would be a help: Creating a spread-sheet and testing the code on your system shouldn't be too difficult and a good place to start!
Option Explicit
Const WelcomePage = "Macros"
Private Sub Workbook_BeforeClose(Cancel As Boolean)
'Turn off events to prevent unwanted loops
Application.EnableEvents = False
'Evaluate if workbook is saved and emulate default propmts
With ThisWorkbook
If Not .Saved Then
Select Case MsgBox("Do you want to save the changes you made to '" & .Name & "'?", _
vbYesNoCancel + vbExclamation)
Case Is = vbYes
'Call customized save routine
Call CustomSave
Case Is = vbNo
'Do not save
Case Is = vbCancel
'Set up procedure to cancel close
Cancel = True
End Select
End If
'If Cancel was clicked, turn events back on and cancel close,
'otherwise close the workbook without saving further changes
If Not Cancel = True Then
.Saved = True
Application.EnableEvents = True
.Close savechanges:=False
Else
Application.EnableEvents = True
End If
End With
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
'Turn off events to prevent unwanted loops
Application.EnableEvents = False
'Call customized save routine and set workbook's saved property to true
'(To cancel regular saving)
Call CustomSave(SaveAsUI)
Cancel = True
'Turn events back on an set saved property to true
Application.EnableEvents = True
ThisWorkbook.Saved = True
End Sub
Private Sub Workbook_Open()
'Unhide all worksheets
Application.ScreenUpdating = False
Call ShowAllSheets
Application.ScreenUpdating = True
Dim msg1, msg2, Pwd As String
Pwd = "5555"
Do
msg1 = MsgBox("Are you the Master User?", vbYesNo)
Loop Until msg1 = vbNo Or msg1 = vbYes
If msg1 = vbNo Then
Worksheets("Sensitive Sheet 1").Visible = xlVeryHidden
Worksheets("Sensitive Sheet 2").Visible = xlVeryHidden
ThisWorkbook.Unprotect Password:=Pwd
ElseIf msg1 = vbYes Then
Do
msg2 = InputBox("Please Enter the Password", "Password Checker", vbOKOnly)
Loop Until msg2 = Pwd
Worksheets("Sensitive Sheet 1").Visible = True
Worksheets("Sensitive Sheet 2").Visible = True
Worksheets("Standard Sheet 1").Visible = xlVeryHidden
Worksheets("Standard Sheet 2").Visible = xlVeryHidden
End If
End Sub
Private Sub CustomSave(Optional SaveAs As Boolean)
Dim WS As Worksheet, aWs As Worksheet, newFname As String
'Turn off screen flashing
Application.ScreenUpdating = False
'Record active worksheet
Set aWs = ActiveSheet
'Hide all sheets
Call HideAllSheets
'Save workbook directly or prompt for saveas filename
If SaveAs = True Then
newFname = Application.GetSaveAsFilename( _
fileFilter:="Macro Enabled Excel Files (*.xlsm), *.xlsm")
If Not newFname = "False" Then ThisWorkbook.SaveAs newFname
Else
ThisWorkbook.Save
End If
'Restore file to where user was
Call ShowAllSheets
aWs.Activate
'Restore screen updates
Application.ScreenUpdating = True
End Sub
Private Sub HideAllSheets()
'Hide all worksheets except the macro welcome page
Dim WS As Worksheet
Worksheets(WelcomePage).Visible = xlSheetVisible
For Each WS In ThisWorkbook.Worksheets
If Not WS.Name = WelcomePage Then WS.Visible = xlSheetVeryHidden
Next WS
Worksheets(WelcomePage).Activate
End Sub
Private Sub ShowAllSheets()
'Show all worksheets except the macro welcome page
Dim WS As Worksheet
For Each WS In ThisWorkbook.Worksheets
If WS.Name <> "Sensitive Sheet 1" And WS.Name <> "Sensitive Sheet 2" Then
If Not WS.Name = WelcomePage Then WS.Visible = xlSheetVisible
End If
Next WS
Worksheets(WelcomePage).Visible = xlSheetVeryHidden
End Sub

You don't need to protect the whole workbook to hide the sheets. xlVeryHidden will hide the sheet and prevent it from being shown on the Hide/Unhide list.
First, unprotect the workbook. You can do this by the Review tab, and then clicking on the Protect Workbook and clear any protection you have checked. I'd also click on the Protect Sheet button for each sheet and clear any protection set there.
Then, modify your Workbook_Open subroutine to do something like this:
Private Sub Workbook_Open()
Dim msg1, msg2, Pwd As String
Pwd = "5555"
Do
msg1 = MsgBox("Are you the Master User?", vbYesNo)
Loop Until msg1 = vbNo Or msg1 = vbYes
If msg1 = vbNo Then
Worksheets("Sensitive Sheet 1").Visible = xlVeryHidden
Worksheets("Sensitive Sheet 2").Visible = xlVeryHidden
ElseIf msg1 = vbYes Then
Do
msg2 = InputBox("Please Enter the Password", "Password Checker", vbOKOnly)
Loop Until msg2 = Pwd
Worksheets("Sensitive Sheet 1").Visible = True
Worksheets("Sensitive Sheet 2").Visible = True
Worksheets("Standard Sheet 1").Visible = xlVeryHidden
Worksheets("Standard Sheet 2").Visible = xlVeryHidden
End If
End Sub
Basically, the workbook is unprotected when opened. If the user is not the special user, then it hides the two special sheets. If they are the special user, then it hides the two special sheets and they can't be unhidden.
Additional Suggestion
You'll run into a problem with the sheet visibility when the user saves - if it's the special user, once the save is complete they won't be able to see the sensitive sheets, because your ShowAllSheets subroutine will hide them.
To get around this, set a global variable to record whether the user is the special user or not, and use that to determine what sheets to show in ShowAllSheets, like this:
Option Explicit
Public IsMasterUser As String
Private Sub Workbook_Open()
Dim msg1, msg2, Pwd As String
Pwd = "5555"
IsMasterUser = "N"
Application.ScreenUpdating = False
Call ShowAllSheets
Application.ScreenUpdating = True
Do
msg1 = MsgBox("Are you the Master User?", vbYesNo)
Loop Until msg1 = vbNo Or msg1 = vbYes
If msg1 = vbNo Then
IsMasterUser = "N"
Worksheets("Sensitive Sheet 1").Visible = xlVeryHidden
Worksheets("Sensitive Sheet 2").Visible = xlVeryHidden
ElseIf msg1 = vbYes Then
Do
msg2 = InputBox("Please Enter the Password", "Password Checker", vbOKOnly)
Loop Until msg2 = Pwd
IsMasterUser = "Y"
Worksheets("Sensitive Sheet 1").Visible = True
Worksheets("Sensitive Sheet 2").Visible = True
Worksheets("Standard Sheet 1").Visible = xlVeryHidden
Worksheets("Standard Sheet 2").Visible = xlVeryHidden
End If
End Sub
Private Sub ShowAllSheets()
'Show all worksheets except the macro welcome page
Dim WS As Worksheet
For Each WS In ThisWorkbook.Worksheets
If Not WS.Name = WelcomePage Then
If IsMasterUser = "N" _
And WS.Name <> "Sensitive Sheet 1" _
And WS.Name <> "Sensitive Sheet 2" Then
WS.Visible = xlSheetVisible
ElseIf IsMasterUser = "Y" _
And WS.Name <> "Standard Sheet 1" _
And WS.Name <> "Standard Sheet 2" Then
WS.Visible = True
End If
End If
Next WS
Worksheets(WelcomePage).Visible = xlSheetVeryHidden
End Sub
This code will set a flag (IsMasterUser) depending on the selection in Workbook_Open. Then when ShowAllSheets is called, it will determine whether to show the standard sheets or the special sheets based on IsMasterUser. Note that IsMasterUser is defaulted to "N" when its declared.
EDIT
A couple of minor problems with the code above. First, the global variable needs to be declared as Public IsMasterUser As String, and secondly it needs to be set to a value inside a function, so I set it to "N" at the start of the Workbook_Open subroutine.
I tested the posted code (the second set), along with the unaltered code from the original post in a Excel 2010 workbook with 6 sheets - Macros, User, Standard Sheet 1, Standard Sheet 2, Sensitive Sheet 1 and Sensitive Sheet 2, and it worked just fine.

Related

Combining code that forces user to enable macro and code that makes cells mandatory

Big thanks to A.S.H for helping me with out with this code earlier.
Right now, I'm attempting to show a splash sheet that tells users to enable macros in order to access the workbook. The plan is to save the file with the splash sheet visible and other sheets veryhidden during the BeforeClose event. During the Open event, the splash sheet will be made veryhidden and the other sheets will be made visible.
Hence, the user will only see the splash sheet when he/she opens the file with macros disabled. However with the below code, it doesn't seem as though the routine that makes the splash sheet visible and the rest veryhidden is running. Where have I gone wrong?
Option Explicit
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim rs As Object, ws As Object
Dim Ans As Integer
Dim target As Range, r As Range
Set rs = Sheets("Report")
If Me.Saved = False Then
Do
Ans = MsgBox("Do you want to save the changes you made to '" & _
Me.Name & "'?", vbQuestion + vbYesNoCancel)
Select Case Ans
Case vbYes
With rs
Set target = .Range("B5:R" & .Cells(.Rows.Count, 2).End(xlUp).Row)
End With
target.Value = Application.Trim(target.Value)
For Each r In target.Rows
If Not IsEmpty(r.Cells(1)) And Application.CountIf(r, "") > 0 Then
Cancel = True
r.Parent.Activate: r.Activate
MsgBox ("Please confirm all required fields have been completed")
Exit Sub
End If
Next
Application.ScreenUpdating = False
Sheets("Reminder").Visible = xlSheetVisible
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "Reminder" Then
ws.Visible = xlSheetVeryHidden
End If
Next ws
ActiveWorkbook.Save
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "Reminder" Then
ws.Visible = xlSheetVisible
End If
Next ws
Sheets("Reminder").Visible = xlSheetVeryHidden
ThisWorkbook.Saved = True
Application.ScreenUpdating = True
Case vbNo
Me.Saved = True
Case vbCancel
Cancel = True
Exit Sub
End Select
Loop Until ThisWorkbook.Saved = True
End If
End Sub
If you are experiencing screen trouble, it is likely due to some erroneous manipulation of Application.ScreenUpdating here and in other macros. In this one, the error is that you first set it to False and then Exit Sub without restoring it to True.
Moreover, since your routine only does calculation (checking) and does not change cell values, there's no point in disabling Application.ScreenUpdating.
On a side note, I think your routine that checks for empty cells can be much simplified.
Function dataIsValid() As Boolean
Dim target As Range, r As Range
With ActiveSheet ' <-- May be better change to some explicit sheet name
Set target = .Range("B5:R" & .Cells(.Rows.Count, 2).End(xlUp).Row)
End With
target.value = Application.Trim(target.value) ' <-- trim the whole range
For Each r In target.Rows
If Not IsEmpty(r.Cells(1)) And Application.CountIf(r, "") Then
r.Parent.Activate: r.Activate ' <-- Show erroneous row
MsgBox ("Please confirm all required fields have been completed")
Exit Function
End If
Next
dataIsValid = True
End Function
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Cancel = Not dataIsValid
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Cancel = Not dataIsValid
End Sub

Subscript out of range - Most computers work fine (mine included)

I am a new user of vba.
There is recently a vba problem that has left me rather clueless and helpless - subscript out of range - on a particular user's computer when every other user seems to have no issue with using the macro (myself included) hence I can't simply trial and error to troubleshoot.
Hence really need expert help from all of you! Really really appreciated!!
I have used a series of vba, which will run one after another and have pasted them in chronological order as follows.
VBA 1
Sub VBA_1()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
ws.Outline.ShowLevels 1, 1
Next ws
End Sub
VBA 2
Sub VBA_2()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
ws.Protect ("Password")
Next ws
End Sub
VBA 3
Sub VBA_3()
Dim iRet As Integer
Dim strPrompt As String
'Prompt
strPrompt = "This will take about 2 minutes. Click 'OK' to proceed."
'Show msgbox
iRet = MsgBox(strPrompt, vbOKCancel)
'When user clicked 'OK'..
If iRet = vbOK Then
'SaveAs Function
Dim fName As String
fName = Application.GetSaveAsFilename(, "Excel Binary Workbook (*.xlsb), *.xlsb")
If fName = "False" Then
MsgBox "File not saved.", vbOKOnly
Cancel = True
End If
Application.EnableEvents = False
ThisWorkbook.SaveAs Filename:=fName, FileFormat:=xlExcel12
Application.EnableEvents = True
' Calculate
Application.Calculate
Application.ScreenUpdating = True
' Outlet
Worksheets("Total Outlets").Activate
'Copy and Paste this portion to each worksheet
For Each cell In Range("A1")
If cell.Value = "Not Applicable" Then
ActiveSheet.Visible = xlSheetHidden
Else
Call HypMenuVRefresh
End If
Next
'End Outlet & Copy and Paste
Worksheets("D11101").Activate
For Each cell In Range("A1")
If cell.Value = "Not Applicable" Then
ActiveSheet.Visible = xlSheetHidden
Else
Call HypMenuVRefresh
End If
Next
Worksheets("D11102").Activate
For Each cell In Range("A1")
If cell.Value = "Not Applicable" Then
ActiveSheet.Visible = xlSheetHidden
Else
Call HypMenuVRefresh
End If
Next
'Hide sheets accordingly
Worksheets("Restaurant List").Visible = xlSheetVeryHidden
Worksheets("Hotel List").Visible = xlSheetVeryHidden
'Recalculate
Application.Calculate
Application.ScreenUpdating = True
'Renaming of tabs
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
If ws.Range("A2").Value = 1 Then
If ws.Visible = xlSheetVisible Then
On Error Resume Next
ws.Name = ws.Range("A10").Value
End If
End If
Next ws
'Save Workbook
ActiveWorkbook.Save
'Enable finishing screen to be 'Input'
Sheets("Input").Select
'Show msgbox
MsgBox ("Retrieval Completed!")
Else
MsgBox ("Retrieval of Data Cancelled")
End If
End Sub
I can think of the following possible causes but do not say any of them is the actual cause:
"...on a particular user's computer..."
Then:
the version of Excel/VBA is different;
somehwere a global Option Base is set (but I believe this cannot be set global, i.e. applicable to all workbooks loaded);
somewhere a separator is "hard coded" that does not conform to the Windows global setings (Control Panel --> Region and Language --> Formats --> Additional Settings);
the language differs with a reflection in VBA (e.g. a keyword/function name in the native language or identifier names with non-US ASCII 7 bit characters).
To find in where the program encounters the error (and stops), make a function that writes a status message to a file after every major step. Make sure to close the file after every message so the message is actually written.

Copying existing password protected sheet to new workbook as an unprotected sheet does not make the new worksheet unprotected

Copying an existing password protected sheet to a new workbook as an unprotected sheet gives the following error when user tries to type in data in the new worksheet.
Error: "the cell or chart you're trying to change is on a protected sheet"
Click OK on the error message.
Please note that this error happens only once. click OK on the pop up error message and type again, then excel allows you to type data in the cells and save the sheet.
We have an excel (format .xls) file currently being used to create another excel spreadsheet when a button on a form in the same spreadsheet is clicked. It basically copies one password protected blank sheet (a template) to a new workbook as an unprotected sheet. The code below used to work with excel 2007(using .xls format). We recently upgraded from excel 2007 to excel 2013 and the problem appeared.
Private Sub cmd_Click()
Dim jBook As Workbook
Dim jsheet As Worksheet
CurrentWorkBook = ActiveWorkbook.Name
Workbooks(CurrentWorkBook).Unprotect jWorksheetPassword
'catch all for errors
On Error GoTo ErrEnd
Dim orginalScreenUpdating As Boolean
orginalScreenUpdating = Application.ScreenUpdating
Application.ScreenUpdating = False
If Range("Language").Value = "2" Then
'French
Set jsheet = TemplateFR
Else
'english
Set jsheet = TemplateEN
End If
jsheet.Visible = xlSheetHidden
'jSheet.Visible = xlSheetVisible
'Delete this line
jsheet.Unprotect jWorksheetPassword
Set jBook = Workbooks.Add(xlWBATWorksheet)
jsheet.Copy After:=jBook.Sheets(1)
jBook.Sheets(2).Visible = xlSheetVisible
Application.DisplayAlerts = False
jBook.Sheets(1).Delete
Application.DisplayAlerts = True
jsheet.Visible = xlSheetVeryHidden
'Delete this line
jBook.Sheets(1).Unprotect jWorksheetPassword
'Delete this line
'jsheet.Protect Password:=jWorksheetPassword
NoErrEnd:
Workbooks(CurrentWorkBook).Protect Password:=jWorksheetPassword, Structure:=True, Windows:=False
Application.ScreenUpdating = orginalScreenUpdating
Unload Me
Exit Sub
ErrEnd:
Workbooks(CurrentWorkBook).Protect Password:=jWorksheetPassword, Structure:=True, Windows:=False
Application.DisplayAlerts = True
Application.ScreenUpdating = True
MsgBox DataTable.Range("MSG4").Value, vbCritical, DataTable.Range("MSG4TITLE").Value
Unload Me
End Sub
The following lines of code activate the original workbook and this somehow clears the protection of the copied sheet with excel 2013 only. On Excel 2007 this causes the original workbook to be activated and confuses users, hence the check for 2013.
If Application.Version = "15.0" Then
Workbooks(CurrentWorkBook).Activate
'jBook.Activate
End If
This is a hack that happens to work. If some one finds a better solution please do post it here as well.
The full code listing is as follows:
Private Sub cmd_Click()
Dim jBook As Workbook
Dim jsheet As Worksheet
CurrentWorkBook = ActiveWorkbook.Name
Workbooks(CurrentWorkBook).Unprotect jWorksheetPassword
'catch all for errors
On Error GoTo ErrEnd
Dim orginalScreenUpdating As Boolean
orginalScreenUpdating = Application.ScreenUpdating
Application.ScreenUpdating = False
If Range("Language").Value = "2" Then
'French
Set jsheet = TemplateFR
Else
'english
Set jsheet = TemplateEN
End If
jsheet.Visible = xlSheetHidden
Set jBook = Workbooks.Add(xlWBATWorksheet)
jsheet.Copy After:=jBook.Sheets(1)
jBook.Sheets(2).Visible = xlSheetVisible
Application.DisplayAlerts = False
jBook.Sheets(1).Delete
Application.DisplayAlerts = True
If Application.Version = "15.0" Then
Workbooks(CurrentWorkBook).Activate
'jBook.Activate
End If
jsheet.Visible = xlSheetVeryHidden
NoErrEnd:
Workbooks(CurrentWorkBook).Protect Password:=jWorksheetPassword, Structure:=True, Windows:=False
Application.ScreenUpdating = orginalScreenUpdating
Unload Me
Exit Sub
ErrEnd:
Workbooks(CurrentWorkBook).Protect Password:=jWorksheetPassword, Structure:=True, Windows:=False
Application.DisplayAlerts = True
Application.ScreenUpdating = True
MsgBox DataTable.Range("MSG4").Value, vbCritical, DataTable.Range("MSG4TITLE").Value
Unload Me
End Sub

VBA Unwanted loop through worksheets

I have used this site quite a bit but this is the first question i have posted, hopefully I can give enough detail. I cannot find any relevant answers because no matter what i search, I get various answers relating to looping code.
Some background:
I have designed an excel document to track some items in my workplace (hereafter referred to as Master Document). As the previous tracker allowed users to edit anything at any time, I have used forms to ensure all information is entered correctly and stored securely. For each item in the Master Document there is a separate excel workbook (hereafter referred to as Item Document).
There are a number of sheets in the Master Document which run code everytime they are activated (because they need to update).
As there is some VBA code in every Item Document which is crucial in syncing data with the Master Document, I have added a Warning worksheet which is shown when the Item Document is opened without macros. This involved using the workbook open, before save and after save events to ensure only the Warning is shown without macros. Here is the code for each event (placed in ThisWorkbook Module obviously)
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Auto_Open
'This is for sync (Master Document checks for text file to see if any changes have been made to Item Document)
If booChange = True Then
Dim oFile As Object
Set oFile = fso.CreateTextFile(strTextFile)
SetAttr strTextFile, vbHidden
booChange = False
End If
'Turn off Screen Updating
Application.ScreenUpdating = False
'Show warning sheet
Sheets("Warning").Visible = xlSheetVisible
'Hide all sheets but Warning sheet
For Each sh In ThisWorkbook.Worksheets
If Not sh.Name = "Warning" Then sh.Visible = xlVeryHidden
Next sh
End Sub
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
'Show all sheets
For Each sh In ThisWorkbook.Worksheets
sh.Visible = xlSheetVisible
Next sh
'Hide the warning sheet
Sheets("Warning").Visible = xlVeryHidden
'Return focus to the main page
ThisWorkbook.Worksheets(1).Activate
'Turn on Screen Updating
Application.ScreenUpdating = True
ThisWorkbook.Saved = True
End Sub
Private Sub Workbook_Open()
'Turn off Screen Updating
Application.ScreenUpdating = False
'Show all sheets
For Each sh In ThisWorkbook.Worksheets
sh.Visible = xlSheetVisible
Next sh
'Hide the warning sheet
Sheets("Warning").Visible = xlVeryHidden
'Return focus to the main page
ThisWorkbook.Worksheets(1).Activate
'Turn on Screen Updating
Application.ScreenUpdating = True
ThisWorkbook.Saved = True
End Sub
And just for completeness, here is all code in Module1 of Item Document
'Declarations
'Strings
Public strSourceFolder As String
Public strTextFile As String
'Other
Public fso As FileSystemObject
Public booChange As Boolean
Public wsFlow As Worksheet
'Constants
Public Const strURNSheetName = "Part 1 Plant Flow Out Summ"
Sub Auto_Open()
Set fso = CreateObject("Scripting.FileSystemObject")
Set wsFlow = ThisWorkbook.Worksheets(strURNSheetName)
strSourceFolder = fso.Getfile(ThisWorkbook.FullName).ParentFolder.Path
strTextFile = fso.BuildPath(strSourceFolder, ThisWorkbook.Worksheets(strURNSheetName).Range("W2").Value & ".txt")
End Sub
When an item is created in the Master Document using the 'frmNewEntry' form the info is checked and entered into the Master Document then a template Item Document is opened and saved with a new unique filename. It is then unprotected, updated with the new information, protected, saved and closed. The Master Document is then saved. Code follows (edited to omit lengthy formatting and data entry):
Form Code:
Private Sub btnSave_Click()
'Values on form are verified
'Master Document sheet is unprotected, formatted and data entry occurs
'Clear Userform and close
For Each C In frmNewEntry.Controls
If TypeOf C Is MSForms.ComboBox Then
C.ListIndex = -1
ElseIf TypeOf C Is MSForms.TextBox Then
C.Text = ""
ElseIf TypeOf C Is MSForms.CheckBox Then
C.Value = False
End If
Next
frmNewEntry.Hide
'Create filepaths
Create_Filepath
'Some hyperlinks are added and the Master Document worksheet is protected again
'Create Flowout Summary
Create_Flowout_Summary
'Update Flowout Summary
Update_Flowout_Summary
'Turn on screen updating
Application.ScreenUpdating = True
'Update Activity Log
Update_Log ("New: " & strNewURN)
Debug.Print "Before Save Master"
'Save tracker
ThisWorkbook.Save
Debug.Print "After Save Master"
End Sub
Module1 Code:
Public Sub Create_Flowout_Summary()
'Create a new flowout summary from the template
'Turn off screen updating
Application.ScreenUpdating = False
'Check if workbook is already open
If Not Is_Book_Open(strTemplate) Then
Application.Workbooks.Open (strTemplatePath)
End If
Debug.Print "Before SaveAs Create"
'Save as new flowout summary
Application.Workbooks(strTemplate).SaveAs fileName:=strFilePath
Debug.Print "After SaveAs Create"
'Close Document Information Panel
ActiveWorkbook.Application.DisplayDocumentInformationPanel = False 'Doesn't seem to work
'Turn on screen updating
Application.ScreenUpdating = True
End Sub
Public Sub Update_Flowout_Summary()
'Update the flowout summary for current call
Dim wsURN As Worksheet
Set wsURN = Workbooks(strFileName).Worksheets(strWsURNName)
'Unprotect Flowout Summary worksheet
wsURN.Unprotect "Flowout Summary"
'Write values to flowout summary
'Protect Flowout Summary worksheet
wsURN.Protect "Flowout Summary", False, True, True, True, True
Debug.Print "Before Save Update"
'Save flowout summary
Application.Workbooks(strFileName).Save
Debug.Print "After Save Update"
'Close Document Information Panel
ActiveWorkbook.Application.DisplayDocumentInformationPanel = False
'Turn on screen updating
Application.ScreenUpdating = True
End Sub
Problem detail:
When I create a new entry it is taking a very long time, I accidentally discovered that the Master Document is running the code in every sheet activate event (mentioned above) (I had a diagnostic msgbox in one of the sheets which mysteriously appeared when i created a new entry)
I have therefore drawn the conclusion that the code is somehow activating every worksheet but have no idea why....
Any help will be much appreciated, and if i have missed anything out that may help in diagnosing just let me know.
EDIT: The other strange phenomenon is that this does not happen when I try to step through the code to find exactly where the activate events are being triggered.
EDIT: Code in the worksheet activate event
Private Sub Worksheet_Activate()
'Turn off Screen Updating
Application.ScreenUpdating = False
'Simply writes data to the sheet (excluded because it is lengthy)
'Turn on Screen Updating
Application.ScreenUpdating = True
wsMyCalls.Protect Password:=strPassword
Debug.Print "wsMyCalls"
MsgBox "This sheet uses your username to display any calls you own." & vbNewLine & _
"It relies on the correct CDSID being entered for owner." & vbNewLine & vbNewLine & _
"Regards" & vbNewLine & _
"Your friendly spreadsheet administrator", vbOKOnly, "Information"
End Sub
EDIT: I added some Debug.Prints to the code (above) and this is what i got.
Before SaveAs Create
After SaveAs Create
Before Save Update
After Save Update
Before Save Master
After Save Master
wsMyCalls
This shows that the code is executing between Debug.Print "After Save Master" and an End Sub. There is no code in there???
Thanks
I believe we aren't seeing your whole code on here. It is difficult to diagnose considering we don't have the workbook to debug ourselves. However I have a similar 'welcome' page that is displayed every time one of my workbooks opens to ask the user to activate macroes. I DO put EnableEvents to false and put my sheet in a certain state before saving, and placing it back after saving.
I will show you exactly how I do it because I have a feeling your problem is related to not disabling EnableEvents are the right timings. I am unsure how to time it based on how your workbook functions because of the mentioned incomplete code.
The sheet is called f_macros. Here is it's worksheet activate event that prevents further navigation:
Private Sub Worksheet_Activate()
ActiveWindow.DisplayHeadings = False
ActiveWindow.DisplayWorkbookTabs = False
End Sub
In my Workbook_BeforeSave:
I record the current state of DisplayHeadings and such at first:
Dim Displaytabs As Boolean
Dim DisplayHeadings As Boolean
Dim menu As CommandBar
Dim ligne As CommandBarControl
Displaytabs = ActiveWindow.DisplayWorkbookTabs
DisplayHeadings = ActiveWindow.DisplayHeadings
I then reset my custom right click, turn off EnableEvents and screen updating. I set DisplayWorkbookTabs to false for good measure.
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.CommandBars("Cell").reset
ActiveWindow.DisplayWorkbookTabs = False
Then I run Cacherdata (HideData, sub in another module that is annexed underneath) I save, and i run the sub macro_activees to put the workbook back in working order for the user. I turn EnableEvents back on, and put the headings back to how they were:
m_protection.Cacherdata
ThisWorkbook.Save
m_protection.macro_activees
Application.ScreenUpdating = True
Application.enableevents = True
ActiveWindow.DisplayWorkbookTabs = Displaytabs
ActiveWindow.DisplayHeadings = DisplayHeadings
I cancel the ordinary Save (important!) and indicate the workbook is saved so they can exit normally without being prompted to save.
Cancel = True
ThisWorkbook.Saved = True
In the BeforeClose, it checks whether or not the workbook state is Saved. if yes, it quits. If not, it does a similar procedure:
If Not (ThisWorkbook.Saved) Then
rep = MsgBox(Prompt:="Save changes before exiting?", _
Title:="---", _
Buttons:=vbYesNoCancel)
Select Case rep
Case vbYes
Application.ScreenUpdating = False
Application.enableevents = False
ActiveWindow.DisplayHeadings = True
m_protection.Cacherdata
ThisWorkbook.Save
Case vbCancel
Cancel = True
Exit Sub
End Select
End If
The workbook open event checks whether it is read-only mode, but that's all. I don't have a Workbook AfterSave.
Annex
CacherData makes every sheet VeryHidden so the user doesn't f*** up the data without activating macros. It records the current active sheet so the user goes back to where they were, unprotects the workbook, hides sheets, protects it back and that's all:
Sub Cacherdata()
Dim ws As Worksheet
f_param.Range("page_active") = ActiveSheet.Name
f_macros.Activate
ThisWorkbook.Unprotect "-----"
For Each ws In ThisWorkbook.Worksheets
If ws.CodeName <> "f_macros" Then ws.visible = xlSheetVeryHidden
Next
ThisWorkbook.Protect "-----"
Exit Sub
End Sub
macros_activees does the opposite:
Sub macro_activees()
Dim ws As Worksheet
ThisWorkbook.Unprotect "-----"
For Each ws In ThisWorkbook.Worksheets
ws.visible = xlSheetVisible
Next
ThisWorkbook.Sheets(f_param.Range("page_active").Value).Activate
ThisWorkbook.Unprotect "-----"
'it unportects twice because of the activate event of the worksheet, don't mind that
Exit Sub
End Sub
Error handling was removed because it was useless to show, but everything else should be there.
EDIT: If this doesn't help you at all, maybe your problem is because the workbooks you create have code in them 9from what i gather) that can affect how long it takes to run your code? If they have an Open procedure themselves, could that be it?

Using VBA to unprotect a sheet that has been protected with UserInterface Only = true

I have an issue with worksheet protection at the moment. I have read through this forum and found that UserInterfaceOnly = true is useful to avoid having to unprotect the sheet, enter the code and re-protect.
However, I have a requirement to unprotect some sheets by using a macro (there are people with additional access to amend some worksheets that I don't want to know the main password), but the macro doesn't unprotect the sheet.
I am using the following code in the workbook to protect and hide sheets on opening.
Private Sub Workbook_Open()
'unprotect workbook'
Application.ScreenUpdating = False
On Error Resume Next
ActiveWorkbook.Unprotect Password:="PASSWORD"
'Hide all worksheets except Project info and requisition. Protect all worksheets except template - but allowing macros to work while protected'
Dim sheet As Worksheet
For Each sheet In Worksheets
If sheet.Name <> "Project Info" And sheet.Name <> "Requisition" And sheet.Name <> "Template" Then sheet.Visible = xlSheetHidden
If sheet.Name <> "Template" And sheet.Name <> "Task Controls" Then sheet.Protect Password:="PASSWORD", DrawingObjects:=True, Contents:=True, Scenarios:=True _
, UserInterfaceOnly:=True, AllowFiltering:=True
If sheet.Name <> "Template" Then sheet.EnableSelection = xlUnlockedCells
Next
ActiveWorkbook.Protect Password:="PASSWORD", structure:=True, Windows:=False
Application.ScreenUpdating = True
End Sub
This works fine for the vast majority of the workbook (and for which I owe thanks to this forum), however when I use the following code to unprotect a sheet to allow it to be edited, the sheet does not unprotect. Note that this is used from the OK button of a Userform if that makes a difference
Private Sub OK_Button_Click()
Dim Supplier As String
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Supplier = Me.Supplier_ComboBox.Value
Set ws1 = Sheets("Buyer's Sheet")
Set ws2 = Sheets(Supplier)
On Error Resume Next
ActiveWorkbook.Unprotect Password:="PASSWORD"
ws2.Visible = xlSheetVisible
ActiveWorkbook.Protect Password:="PASSWORD", structure:=True, Windows:=False
ws2.Select
Set ws2 = ActiveSheet
ws2.Columns.Hidden = False
ws2.Unprotect Password:="PASSWORD"
MsgBox "Make the required amendments to the Price List and click the button to return to the home screen", vbOKOnly, "Amend Price List"
Dim ctl As Control
For Each ctl In Me.Controls
If TypeName(ctl) = "TextBox" Or TypeName(ctl) = "ComboBox" Then
ctl.Value = ""
ElseIf TypeName(ctl) = "CheckBox" Then
ctl.Value = False
End If
Next ctl
Unload Me
End Sub
Some of the code is probably fairly inefficient (particularly use of .select) but it appears to work and be pretty stable. The only function that does not work is the worksheet.unprotect function.
Looking more closely at your code after a night's sleep, I believe I see the issue. You're unprotecting the Workbook, then immediately re-protecting it, then trying to unprotect a Worksheet within the protected Workbook. Not 100% certain that's an issue, but try this:
Private Sub OK_Button_Click()
'Dim Supplier As String
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Set ws1 = Sheets("Buyer's Sheet")
Set ws2 = Sheets(Me.Supplier_ComboBox.Value)
On Error Resume Next
ActiveWorkbook.Unprotect Password:="PASSWORD"
ws2.Visible = xlSheetVisible
'remove this line to leave the workbook unptrotected while you're using it
'ActiveWorkbook.Protect Password:="PASSWORD", structure:=True, Windows:=False
'ws2.Select
'Set ws2 = ActiveSheet
'note switched order of next two lines - unprotect FIRST
ws2.Unprotect Password:="PASSWORD"
ws2.Columns.Hidden = False
MsgBox "Make the required amendments to the Price List and click the button to return to the home screen", vbOKOnly, "Amend Price List"
Dim ctl As Control
For Each ctl In Me.Controls
If TypeName(ctl) = "TextBox" Or TypeName(ctl) = "ComboBox" Then
ctl.Value = ""
ElseIf TypeName(ctl) = "CheckBox" Then
ctl.Value = False
End If
Next ctl
Unload Me
End Sub
Now, based on the text of your MsgBox, it looks like you need to leave the sheet unprotected for the user to make some changes, then (s)he clicks another button that re-protects and does some other processing. I believe that this is the issue - your worksheet is protected, but the workbook protection is overriding it. Again, I'm not 100% certain on this, and the Workbook protection documentation and Worksheet protection documentation aren't very clear (to me) about this.
My changes (cleaned up a couple of unnecessary lines near the top), leaves the workbook and the worksheet unprotected so the user can make changes. I'm assuming that the button click referred to in the MsgBox does, or will be modified to, re-protect everything.