Excel gets corrupt and goes into read only mode - excel

So I have an excel document that will just randomly break on me when opening it. I do have Code 1 in the VBA ThisWorkbook section but it doesn't start until I enable macros after opening it.
The images attached are in the order that they appear to me. One note is that I do have hidden files revealed and I only see the "Ownership file" when I have it open. I am on a shared network but I do not have the privileges to view where it all is open.
My current work around is to save the file under a different name and then delete the old file and rename it.
After researching a bit, someone stated it might have had to do with sorting. But I added Code 2 and I am still having the issue.
Code 1
Dim Result
Result = MsgBox("The Data in this document might be outdated. Would you like to refresh the Data Queries? This process could take a few minutes...", vbYesNo, "Data Query OutDated")
If Result = vbNo Then
Exit Sub
End If
MsgBox "Queries Will Refresh Upon Closing this window. Please wait"
ActiveWorkbook.Worksheets("SQLData").EnableCalculation = False
ActiveWorkbook.Worksheets("FlowBreakDown").EnableCalculation = False
Application.ScreenUpdating = False
Change_Background_Refresh False
ActiveWorkbook.RefreshAll
Application.ScreenUpdating = True
ActiveWorkbook.Worksheets("SQLData").EnableCalculation = True
ActiveWorkbook.Worksheets("SQLData").EnableCalculation = False
ActiveWorkbook.Worksheets("FlowBreakDown").EnableCalculation = False
MsgBox "Refresh Complete"
Call ResizeData
End Sub
Code 2
Dim Sht As Worksheet
' Clear all Sort Fields prior to Save & Exit
For Each Sht In Application.Worksheets
Sht.Sort.SortFields.Clear
Next Sht
End Sub

Related

Sheet.activate not activating specified sheet

So I have officially run into a brick wall. I have written a macro that will allow the user, upon password entry, to unlock and unhide all sheets except for the one containing the password. At the end of the macro, I want to go to a specific sheet.
I have tried every reference to that sheet known to mankind, including both sheet code names and indexes, but the "sheet.activate" event just will not trigger. I have tried setting screen updating to true, both before and after the sheet.activate command. Events are enabled. I have disabled all Excel addins. I have tried everything I can possibly think of and everything I've found in forums all over the web. As you'll see from the code, I've even added basic time delays to the code at each step of the activating sequence, all to no avail. I've tried the activate sequence at different parts of the code. At the completion of the code, the best I get is activate the first sheet in my workbook. I even have Option Explicit enabled, and it sheds no light.
Now, the weird thing is, if I take everything out of the code except for the activate events, it works perfectly. If I step through the code line by line, the activate lines work. But if I compile the code and run the whole sub - nada. What the heck am I missing here?
Here is my complete code for this sub:
Option Explicit
Sub UnProtectAll()
Application.ScreenUpdating = False
Dim pPrompt As String
Dim bkPswrd As String
inputPass_box.Show
pPrompt = inputPass_box.passInput.Value
bkPswrd = Worksheets("Password List").Cells(3, 2)
If pPrompt = "" Then
MsgBox "You didn't enter anything...", vbInformation, "No password"
UnProtectAll
ElseIf pPrompt = bkPswrd Then
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
ws.Unprotect bkPswrd
Next ws
ThisWorkbook.Worksheets("Folder History").Visible = xlSheetVisible
ThisWorkbook.Worksheets("Master List").Visible = xlSheetVisible
ThisWorkbook.Worksheets("File Formats").Visible = xlSheetVisible
Unload inputPass_box
Worksheets("Change Sheet").Shapes("Button 1").Visible = False
Application.ScreenUpdating = True
Application.Wait (Now + TimeValue("0:00:03"))
ThisWorkbook.Worksheets("Folder History").Select
ThisWorkbook.Worksheets("Folder History").Activate
Application.Wait (Now + TimeValue("0:00:03"))
ThisWorkbook.Worksheets("Change Sheet").Select
ThisWorkbook.Worksheets("Change Sheet").Activate
Else
MsgBox "You have entered an incorrect password. Please check your password and try again.", vbCritical, "Wrong Password!"
UnProtectAll
End If
End Sub
Nevermind. I just figured it out, but here's my answer in case someone else needs help with the same issue. The line
Unload inputPass_box
was throwing it off for some reason ("inputPass_box" is a UserForm used as an input box). If someone would be so kind as to set me straight on this, I would be much obliged, but to my very limited knowledge, it seems that this line triggers the UserForm_QueryClose event, as in my project this event contains and "End" command to prevent the userform from passing any data back to the sub, as this would trigger several other events when I want closing or cancelling the user form to stop rather than displaying any of the error messages contained in the code block above.
pPrompt = InputBox("please input password")
bkPswrd = Worksheets("Password List").Cells(3, 2)
If pPrompt = "" Then
MsgBox "You didn't enter anything...", vbInformation, "No password"
UnProtectAll
ElseIf pPrompt = bkPswrd Then
use "InputBox" no problem,There may be a problem with the inputPass box

VBA MsgBox After Background Query Completion?

I have created a VBA code to import data from CSV convert it into a table and refresh the query that is already setup.
I want the user to be informed when the background query is completed by displaying a VBA msgbox.
I tried below code but it doesn't work because if condition would be nothing by the the time query is completed. So no msgbox will be display.
Do I need to setup some delay like 15 sec and display msgbox anyway but then it wouldn't be a good idea.
How to sync background query completion with VBA msgbox?
ThisWorkbook.RefreshAll
Sheets(2).Select
If Sheets(2).Range("AG3").Value <> "" Then MsgBox "Completed"
The Delay is tricky. Sometimes it could be 2 seconds or 10 to update the whole data, and also when the data gets bigger, the system will need more time to update the Data Model. This means that the "MsgBox" could appear when the data still updating.
I understand the perks of the Background Update, but it is important to know that it stops when you save the workbook. Instead, I would block any activity in the workbook until the Data Model is complete updated. For this, I use the following code that I found here long time ago:
Sub Aktualisieren()
On Error Resume Next
Application.DisplayAlerts = False
Application.ScreenUpdating = False
With ThisWorkbook
For Each objConnection In .Connections
'Get current background-refresh value
bBackground = objConnection.OLEDBConnection.BackgroundQuery
'Temporarily disable background-refresh
objConnection.OLEDBConnection.BackgroundQuery = False
'Refresh this connection
objConnection.Refresh
'Set background-refresh value back to original value
objConnection.OLEDBConnection.BackgroundQuery = bBackground
Next
'Save the updated Data
.Save
End With
Application.DisplayAlerts = True
Application.ScreenUpdating = True
MsgBox "Data Model Updated"
End Sub
Now, as you ask, if you want to update one specific Query, first you need to know the specific name of it (it is not always the same as you have written). For this run the following code:
Sub Get_Conection_Names()
With ThisWorkbook
'Check if there is any conection
If .Connections.Count = 0 Then Exit Sub
'Print the numer of conection (item number) and its name
For X = 1 To .Connections.Count
Debug.Print X & ": " & .Connections.Item(X).Name
Next X
End With
End Sub
With the information of the Query, you can add to a bottom the following code:
Sub UpdateConectionbyName()
Dim ConectionName As String
ConectionName = "Query - Name of Query"
With ThisWorkbook
'Check if there is any conection
If .Connections.Count = 0 Then Exit Sub
'Check the connections names if one macht with the one we want.
For X = 1 To .Connections.Count
If .Connections.Item(X).Name = ConectionName Then .Connections.Item(X).Refresh
Next X
End With
End Sub
And now, if you want to Refresh a specific Query unabeliing the Background Update, this code will help. Item 1 is the number of the query. You can get it with the code above.
With ThisWorkbook.Connections
bBackground = .Item(1).OLEDBConnection.BackgroundQuery
.Item(1).OLEDBConnection.BackgroundQuery = False
.Item(1).Refresh
.Item(1).OLEDBConnection.BackgroundQuery = bBackground
End With

How to keep a userform open when closing other instances of Excel

Hope someone can help - I have a Userform that opens on launch of the excel file (Test.xlsm) and hides the workbook from prying eyes. The workbook can become visible for editing by a button click and password entry from the userform. Everything is working fine - UNTIL - you open another instance of excel. Once you finish with it and close any secondary instance of excel, it also either
1. closes the userform, or
2. shows the excel workbook behind the userform. Neither of these is what I want. I need the userform to remain open and I need the workbook associated with it to remain hidden until called.
Question - is there some code that will prevent other instances of excel from doing what it is doing, or am I dreaming.
I found some code (below) that the writer said done exactly what i am after, but all I got was global errors.
Private Sub WorkBook_Open()
If Workbooks.Count = 1 Then Application.Visible = False
Workbooks("test.xlsm").Windows(1).Visible = False
UserForm1.Show vbModeless
End Sub
Any help greatly appreciated.
BTW - the code for the workbook open is
Private Sub Workbook_Open()
Set Thiswb = Me.Application
Application.Visible = False
Staff_Contacts.Show vbModeless
End Sub
For usecase you described, I would propose you something similar to this solution:
Sub Workbook_open()
Dim wrong_attempts As Integer
wrong_attempts = 0
Dim sheet As Worksheet
Set sheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
ActiveWorkbook.Sheets("Sheet2").Visible = xlSheetVeryHidden
Start1:
If wrong_attempts > 4 Then
MsgBox "You've entered wrong password too many times. File will now be closed"
Application.DisplayAlerts = False
sheet.Delete
ActiveWorkbook.Close
Application.DisplayAlerts = True
End If
InputBoxVariable = InputBox(Prompt:="Please enter password to access this document", Title:="Authorization required", Default:="")
If InputBoxVariable = "12345" Then
ActiveWorkbook.Sheets("Sheet2").Visible = xlSheetVisible
Application.DisplayAlerts = False
sheet.Delete
Application.DisplayAlerts = True
Else
wrong_attempts = wrong_attempts + 1
GoTo Start1
End If
End Sub
In this example it is assumed that sheet2 should be protected. On the very load of the document, phantom sheet will be created, and after successful login, it will be deleted and sheet2 should be visible again. In addition, if someone enters wrong password 5 times, file closes automatically.
Fair notice, I've used InputBox out here, so password is not masked, if you want to mask password as well, you will have to make brand new form with button and textbox.

Restrict viewing access to an Excel worksheet

I thought this would be a readily used function in Excel but it's surprisingly difficult to implement a simple process of restricting access to specific worksheets within a larger workbook.
There's a few methods that prompt an initial password to open various versions of the same workbook. But I want to keep the workbook identical for all users but restrict access to certain sheets. Surely there's a password protect function that requires the user to enter a password to view a sheet. Rather than create multiple versions of the same workbook based on different users.
I have tried the following but it doesnt prompt a password to access the sheet
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Dim MySheets As String, Response As String
Dim MySheet As Worksheet
MySheet = "COMMUNICATION"
If ActiveSheet.Name = MySheet Then
ActiveSheet.Visible = False
Response = InputBox("Enter password to view sheet")
If Response = "MyPass" Then
Sheets(MySheet).Visible = True
Application.EnableEvents = False
Sheets(MySheet).Select
Application.EnableEvents = True
End If
End If
Sheets(MySheet).Visible = True
End Sub
Am I doing this right?
It sounds like according to the comments that this isn't as much as a security issue as it is a convenience issue. So please bear in mind when considering implementing this into your project that this is easily breakable if there is any malicious intent to gain unauthorized access.
First, I would recommend a common landing zone. A main worksheet that is displayed immediately after opening a workbook. To do this, we would use the Workbook_Open() event and activate a sheet from there.
This can be a hidden sheet if desired, that will be up to you.
Option Explicit
Private lastUsedSheet As Worksheet
Private Sub Workbook_Open()
Set lastUsedSheet = Me.Worksheets("MainSheet")
Application.EnableEvents = False
lastUsedSheet.Activate
Application.EnableEvents = True
End Sub
Next, we should decide on what should occur when there's an attempt to access a new sheet. In the below method, once a sheet is activated it will automatically redirect the user back to the last used sheet until a successful password attempt has been made.
We can track the last used sheet in a module-scoped variable, which in this example will be named lastUsedSheet. Any time a worksheet is successfully changed, this variable will be set to that worksheet automatically - this way when when someone attempts to access another sheet, it will redirect them back to the prior sheet until the password is successfully entered.
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
On Error GoTo SafeExit
Application.EnableEvents = False
' Error protection in case lastUsedSheet is nothing
If lastUsedSheet Is Nothing Then
Set lastUsedSheet = Me.Worksheets("MainSheet")
End If
' Allow common sheets to be activated without PW
If Sh.Name = "MainSheet" Then
Set lastUsedSheet = Sh
Sh.Activate
GoTo SafeExit
Else
' Temporarily send the user back to last sheet until
' Password has been successfully entered
lastUsedSheet.Activate
End If
' Set each sheet's password
Dim sInputPW As String, sSheetPW As String
Select Case Sh.Name
Case "Sheet1"
sSheetPW = "123456"
Case "Sheet2"
sSheetPW = "987654"
End Select
' Create a loop that will keep prompting password
' until successful pw or empty string entered
Do
sInputPW = InputBox("Please enter password for the " & _
"worksheet: " & Sh.Name & ".")
If sInputPW = "" Then GoTo SafeExit
Loop While sInputPW <> sSheetPW
Set lastUsedSheet = Sh
Sh.Activate
SafeExit:
Application.EnableEvents = True
If Err.Number <> 0 Then
Debug.Print Time; Err.Description
MsgBox Err.Description, Title:="Error # " & Err.Number
End If
End Sub
Side note, disabling events is necessary due to the fact that your Workbook_SheetActivate event will continue to fire after a successful sheet change.
Preventing file type changes during SaveAs1
You can further protect the accidental removal of VBA code by restricting the file save type. This can be accomplished using the Workbook_BeforeSave() event. The reason this is a potential problem is that saving as a non-macro enabled workbook will erase the code, which will prevent the password protection features you just implemented above.
First, we need to check if this is a Save or SaveAs. You can accomplish this using the Boolean property SaveAsUI that is included with the event itself. If this value is True, then it's a SaveAs event - which means we need to perform additional checks to ensure that the file type isn't accidentally changed from the save dialog box. If the value is False, then this is a normal save, and we can bypass these checks because we know the workbook will be saved as type .xlsm.
After this initial check, we will display the dialog box using Application.FileDialog().Show.
Afterwards, we will check if the user canceled the operation .SelectedItems.Count = 0 or clicked Save. IF user clicked cancel, then we simply set Cancel = True and the workbook will not save.
We proceed to check the type of extension selected by the user using this line:
If Split(fileName, ".")(UBound(Split(fileName, "."))) <> "xlsm" Then
This will split the file path by a period ., and will grab the last instance of the period (UBound(Split(fileName, "."))) in the event a file name may contain additional periods. If the extension does not match xlsm, then we abort the save operation.
Finally, after all checks passed, you can save the document:
Me.SaveAs .SelectedItems(1), 52
Since we already saved it with the above line, we can go ahead and set Cancel = True and exit the routine.
The full code (to be placed in the Worksheet obj module):
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
On Error GoTo SafeExit
If SaveAsUI Then
With Application.FileDialog(msoFileDialogSaveAs)
.Show
If .SelectedItems.Count = 0 Then
Cancel = True
Else
Dim fileName$
fileName = .SelectedItems(1)
If Split(fileName, ".")(UBound(Split(fileName, "."))) <> "xlsm" Then
MsgBox "You must save this as an .xlsm document. Document has " & _
"NOT been saved", vbCritical
Cancel = True
Else
Application.EnableEvents = False
Application.DisplayAlerts = False
Me.SaveAs .SelectedItems(1), 52
Cancel = True
End If
End If
End With
Else
Exit Sub
End If
SafeExit:
Application.EnableEvents = True
Application.DisplayAlerts = True
If Err.Number <> 0 Then
Debug.Print Time; Err.Description
MsgBox Err.Description, Title:="Error # " & Err.Number
End If
End Sub
1 Shoutout to PatricK for the suggestion
If you want to restrict access to a worksheet, you can just hide it:
ActiveWorkbook.Sheets("YourWorkSheet").Visible = xlSheetVeryHidden
I concur with Mathieu Guindon that any VBA attempt to "Restrict viewing access to an Excel worksheet" will be flimsy as explained by Mathieu Guindon. Moreover, If the file is opened with Excel option Macro security level other than the lowest, any VBA code including this is bound to fail.
However just for shake of simplicity I prefer to use workbook open event and Sheet Activate of the restricted sheet. Using Workbook Sheet Activate event will trigger password prompt even during switching between sheets by user with viewing access.
Private Sub Workbook_Open()
Sheets("COMMUNICATION").Visible = xlSheetHidden
End Sub
Public ViewAccess As Boolean 'In restricted sheet's activate event
Private Sub Worksheet_Activate()
If ViewAccess = False Then
Me.Visible = xlSheetHidden
response = Application.InputBox("Password", xTitleId, "", Type:=2)
If response = "123" Then
Me.Visible = xlSheetVisible
ViewAccess = True
End If
End If
End Sub

How to automatically say yes to prompt window

I have a code that opens the book1.xlsm file as a read only file but I get the prompt window "Book1.xlsm is already open. Reopening will cause any changes you made to be discarded. Do you want to reopen Book.1" How do I have it say yes automatically so the user doesn't see it?
I have done this before but I cant seem to remember how.
I thought it was Application.ScreenUpdating = False but its not working so I am not sure...
Thanks
Code:
If MsgBox("Open as Read only?", vbYesNo) = vbYes Then
Application.ScreenUpdating = False
Workbooks.Open Filename:="C:\Users\aholiday\Desktop\Book1", ReadOnly:=True
MsgBox ("Complete")
Application.ScreenUpdating = True
Else
MsgBox ("Editing Avaliable")
Exit Sub
End If
You're looking for Application.DisplayAlerts = False.
It's worth nothing that Excel will set this property to true once the executing code has finished.

Resources