I want to prevent the user from closing the form and editing the spreadsheet if they don't know the password. I can get the Userform to stay open but I cannot figure out how to initialize the form so all of the command buttons still function.
I have tried using an if statement as described below. The userform stays open but isn't initialized so the user is unable to enter a password or run the userform at all.
Private Sub UserForm_Terminate()
Password = InputBox("Enter Password")
If Password = "syntax" Then
UserForm1.Hide
ElseIf Password <> "syntax" Then
UserForm1.Show
End If
End
End Sub
There aren't any error messages, but if the VBA editor window isn't open the user has to close Excel completely. Any advice on what to try next is appreciated. Thanks in advance
You can use UserForm_QueryClose to intercept all 'close' actions on a userform. This code would go in the userform itself.
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Dim password As String
password = InputBox("Enter Password")
If password = "syntax" Then
Cancel = False 'If password is correct, allow close event to proceed
ElseIf password <> "syntax" Then
Cancel = True 'If password is incorrect, cancel the close event
End If
End Sub
Like K.Dᴀᴠɪs pointed out, this still won't prevent anyone from pausing the code execution and manually closing the form (Excel just doesn't provide that level of security).
I am working on a userform that inserts data into a DB. There is a modify button that allows to update data but I want allow confirmation of update with a password. Therefore, in the Code of the modify button, I am calling another userform that prompts the user to enter a password. The problem I am having is that I have created a boolean variable that is set to True when the password is correct and to False other. When the password is correct, the code for the modify button continues but the True info is not transmitted to the first userform
I have seen a lot of similar questions here but none of the answers that I have seen has helped me solve my problem. I have created some public variables in both codes but still does not work
Here is the code for the modify button (First userform)
Private Sub modify_Click()
On Error GoTo handler
Dim connec As Object
Dim rst As Object
Dim stringconn As String
Dim sqlupdt As String
Dim modifmat As String
Dim msg
--Some code here
if [condition] then
goto 1
end if
1 password.show
if pwcorr= True then
goto 2
else
msgbox "Incorrect password"
exit sub
end if
3 --Some code here
end sub
and here is the code for the password userform (2nd userform)
Public pwcorr
public sub OkBtn_Click()
Dim pw As String
Dim pwin As String
Dim pwcorr As Boolean
pw= "abcde"
pwin = Me.pwin.Text
If pwin = vbNullString Then
MsgBox "No password was entered", vbCritical
ElseIf pwin = pw Then
Me.pwcorr = True
Unload Me
Else
MsgBox "Password incorrect", vbCritical
End If
End Sub
Whenever I get to the point where I check If pwcorr = True in the first code, the pwcorr is always empty. Don't know why
I have a macro I am constructing and I would like to call out different procedures present in the same macro sheet. Please try to solve it providing me the code, the order and the specific definition of the macro.
Example:
Sub MyUserName()
dim UserName as String
UserName = "Alessio_110"
End Sub
Sub msgbox_1()
msgbox UserName
End Sub
In this example I would like to have a message box telling me the User Name I have set in a precedent procedure. How could I embed the two codes?
To call a procedure you can just use its name. You pass the data as an argument to the called procedure:
So
Sub MyUserName()
dim UserName as String
UserName = "Alessio_110"
MyCalledProc UserName 'calles MyCalledProc and passes UserName as a reference
End Sub
Sub MyCalledProc(UserName as String)
MsgBox UserName
End Sub
I've decided to create a pass-protected file which will self-destruct after three wrong password entries. The macro runs with the file open (UserForm with pass entry field pops up) but the weak point is that Ctrl-Break allows to stop the macro and get access to the code.
Is there any way to disable/prevent Break option in a particular workbook (via VBA, preferably)?
If you are interested, I can provide the macro upon request.
UPD: Here's the macro i'm using (Date based).
Private Sub Workbook_Open()
If Date > Cdate("30/03/2015") Then
WARNING.Show
End If
End Sub
This part of code is assigned to "Ok" and "Cancel" buttons of the UserForm "WARNING".
Public i As Integer
Public b As Integer
Sub setib()
i = 2 - b
b = b + 0
End Sub
Private Sub CnclBtn_Click()
WARNING.Hide
With ThisWorkbook
.Saved = True
.Close False
End With
End Sub
Private Sub OKBtn_Click()
Call setib
Dim Pass As String: Pass = "*your pass*"
Dim PassInput As String: PassInput = WARNING.PassField.Text
If PassInput = Pass Then
MsgBox "Password is correct"
GoTo Safe:
Else
If b < 2 Then
MsgBox "Password is incorrect. " & i & " attempts left."
Else
MsgBox "No More attempts"
End If
If b = 2 Then
WARNING.Hide
GoTo Destroy:
Else
WARNING.PassField.Value = vbNullString
WARNING.PassField.SetFocus
b = b + 1
GoTo EndSub:
End If
End If
Safe:
ActiveWorkbook.VBProject.VBComponents("ThisWorkbook").CodeModule.DeleteLines 1, _
ActiveWorkbook.VBProject.VBComponents("ThisWorkbook").CodeModule.CountOfLines
WARNING.Hide
GoTo EndSub:
Destroy:
With ThisWorkbook
.Saved = True
.ChangeFileAccess xlReadOnly
Kill .FullName
.Close False
End With
EndSub:
Sheet1.Activate
End Sub
You could simply password-protect the VBA project. That will avoid the need to worry about playing with the Application-level settings for EnableCancelKey.
While the user may be able to "break" with the cancel key, they will not be able to view the code without supplying the proper password for the VBA project.
With the VBAProject protected, the user can "break" execution of the code, the user should not be able to enter "break mode", and the Excel application will not be interactive (so the user will not be able to access the worksheets). At this point, the User Form will be frozen on the screen and the application unresponsive. The user then has two options that I can see:
If they know the name of the userform, they could conceivably Unload UserForm1 from the Immediate window in the VBE. So, you should pick some name for the UserForm which they will not likely guess. If they do this, they will be able to access the file itself, but if you give the UF a secure name, they'll never guess it correctly.
Otherwise, they're SOL, unless they Ctrl+AltDel, and kill the Excel application procdess.
NOTE: Excel passwords, whether on the worksheets or the VBAProject (or both) can be cracked by anyone intent on doing so, and are only a good measure to prevent inadvertent corruption or manipulation of the data.
I have been trying to fix a login problem but I cannot find a solution. When both login and pass fail, an error message starts a countdown without letting the user manifest another opinion.
QUESTION 1: Can anyone please make the necessary corrections without altering too much the given code structure and explain?
QUESTION 2: What code would turn the "User1" text into bold at the moment the access is granted?
QUESTION 3: What command would disable the "X" on the top right-hand corner of the msg form?
Thank you in advance
Here it is what I could do
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
Private Sub BtOK_Click()
Dim User1 As String
Dim count As Integer
count = 3
MM:
If EDBoxlogin.Value = "admin" And EDBoxpass.Value = "1234" Then
User1 = Application.UserName
MsgBox "welcome" & User1 & " !", vbExclamation, "Access Granted"
Sheets("Plan1").Visible = xlSheetVisible
Unload Me
Else
If EDBoxlogin.Value = "" Or EDBoxpass.Value = "" Then
MsgBox "Please, fill in the fiels 'login' and 'pass'", vbExclamation + vbOKOnly, "Access denied : incomplete information"
Else
If count >= 0 Then
MsgBox "Login and pass are incorrect! You have " & count & " more trial(s)", vbExclamation + vbOKOnly, "Access denied"
EDBoxlogin.Value = "" And EDBoxpass.Value = ""
' I want to delete previous text in the editbox fields
count = count - 1
GoTo MM
Else
ThisWorkbook.Close
End If
End If
End If
End Sub
If you don't really need to know which user is opening the workbook, consider using Excel's built-in password security function. Also, you should encrypt the contents of the file also using Excel's built-in functions, or anyone can open the file with a text editor and find the userID and password listed in your code.
If you must use a login form, and I've also had to do so in the past, the following code builds on what you did by adding a user list to a hidden worksheet Users. Column A in that sheet needs to be the user names, B contains the passwords. This worksheet also uses cell D1 to track failed login attempts. Using variables in code for this sort of thing is tough ... you have to make them Public and if there are any errors when running code, it will lose its value, then bad things can happen.
The code also references another sheet, SplashPage. This allows you to hide Project1 when the user exits the workbook. The code I wrote handles the hide/unhide process when the file is opened or closed.
I don't know a way to turn off the close box in a user form. I've added code to reject the login if a user does that.
Happy coding.
'Module: frmLogin
Private Sub BtOK_Click()
Dim User1 As String
Dim Passwd As Variant
Sheets("Users").Range("D2").Value = False
User1 = EDBoxlogin.Value
Passwd = getPassword(User1)
If User1 <> "" And Passwd <> "" And EDBoxpass.Value = Passwd Then
Sheets("Users").Range("D2").Value = True
MsgBox "Welcome " & User1 & "!", vbExclamation, "Access Granted"
With Sheets("Plan1")
.Visible = xlSheetVisible
.Activate
End With
Sheets("SplashPage").Visible = xlSheetVeryHidden
Unload Me
Exit Sub
Else
Sheets("Users").Range("D1").Value = Sheets("Users").Range("D1").Value - 1
If Sheets("Users").Range("D1").Value > 0 Then
MsgBox "Login and pass are incorrect! You have " & Sheets("Users").Range("D1").Value & _
" more trial(s)", vbExclamation + vbOKOnly, "Access denied"
EDBoxpass.Value = ""
With EDBoxlogin
.Value = ""
.SetFocus
End With
' I want to delete previous text in the editbox fields
Exit Sub
End If
End If
UserForm_Terminate
End Sub
Private Sub UserForm_Terminate()
If Sheets("Users").Range("D2").Value <> True Then
MsgBox "Login cancelled, goodbye!"
doWorkbookClose
End If
End Sub
'Module: ThisWorkbook
Private Sub Workbook_BeforeClose(Cancel As Boolean)
doWorkbookClose
End Sub
Private Sub Workbook_Open()
On Error Resume Next
Sheets("Users").Range("D1").Value = 3
With Sheets("SplashPage")
.Visible = xlSheetVisible
.Activate
End With
Sheets("Plan1").Visible = xlSheetVeryHidden
Sheets("Users").Visible = xlSheetVeryHidden
ThisWorkbook.Save
frmLogin.Show
End Sub
'Module: Module1
Function getPassword(strVarib As String) As Variant
Dim r As Long
Dim sht As Worksheet
Dim rng As Range
On Error GoTo ErrorHandler
Set sht = Sheets("Users")
Set rng = sht.Range("A:A")
r = WorksheetFunction.Match(strVarib, rng, 0)
getPassword = sht.Cells(r, 2).Value
Exit Function
ErrorHandler:
getPassword = Empty
End Function
Sub doWorkbookClose()
On Error Resume Next
With Sheets("SplashPage")
.Visible = xlSheetVisible
.Activate
End With
Sheets("Plan1").Visible = xlSheetVeryHidden
Sheets("Users").Visible = xlSheetVeryHidden
ThisWorkbook.Save
End Sub
[begin Q&A]
Luiz, I've answered your edits below.
'Q: What Passwd does?
'Module: frmLogin
....
Passwd = getPassword(User1)
A: It gets the password value matching the value of User1. Here's the whole function for context:
Function getPassword(strVarib As String) As Variant
Dim r As Long
Dim sht As Worksheet
Dim rng As Range
On Error GoTo ErrorHandler
Set sht = Sheets("Users")
Set rng = sht.Range("A:A")
r = WorksheetFunction.Match(strVarib, rng, 0)
getPassword = sht.Cells(r, 2).Value
Exit Function
ErrorHandler:
getPassword = Empty
If User1 does not exist then WorksheetFunction.Match throws an error and code execution will jump to ErrorHandler:.
'Q: Does Empty mean that the cell is not with zeros or spaces, but completely blank instead?
A: Empty refers to a Variant variable type that is set to its default value. getPassword could just as easily return the boolean False or integer 0 because those are the default values for those types. It's actually not strictly necessary to set getPassword to anything here ... it's just my personal practice to be explicit.
Since IsEmpty(celFoo) is a valid test for whether a cell is empty or not, you might want to return False instead of Empty to avoid ambiguity.
'Q: Can you explain these two lines below in detail?
Set sht = Sheets("Users")
Set rng = sht.Range("A:A")
A: It's just habit. The alternative would be to elminate those variable assignments and rewrite this line:
r = WorksheetFunction.Match(strVarib, rng, 0)
as:
r = WorksheetFunction.Match(strVarib, Sheets("Users").Range("A:A"), 0)
which is messier to type. Especially if we're going to be doing other things on that sheet with that range in the same routine. Which we are in the next block of code ...
'Q: Important to explain these three lines below in detail too [why 0?, To where (r,2) points to?]
r = WorksheetFunction.Match(strVarib, rng, 0)
getPassword = sht.Cells(r, 2).Value
Exit Function
A: To review, worksheet Users contains user IDs in column A, and their passwords in column B. There can be as many users as there are rows in a worksheet.
- rng is column A as set above.
- 0 means find an exact match for strVarib and throw an error if not match is found.
- If we find a match, r will be set to the row number where the value in column A is equal to our input parameter, strVarib.
- So, sht.Cells(r, 2).Value is the password value in column B (column 2) for the UserID.
'Q: Why the need to call a splashpage? What it contains?
A: You don't necessarily need one, but if you really want to secure your workbook it's good practice. Let's say that it contains sensitive information that you don't want unauthorized user to see. At the very least you would:
Encrypt the worbook using native Excel functionality.
Password protect your VBA project using native functionality. This keeps savvier users from reading your code and making the xlSheetVeryHidden sheets Users and Plan1 visible to their prying eyes.
Now, you can't hide all sheets in a workbook at the same time, at least one needs to be visible at any given time ...
... so I've created a third sheet called SplashPage that doesn't contain any sensitive information. And that means I can hide all of the other worksheets until the user enters a valid UserID and password in frmLogin.
SplashPage can contain whatever you want. You can call it whatever you want. Typically, mine says something like:
Welcome to the Enemies List Application!
Only authorized users may access this workbook.
If you're seeing this page and no login form is visible
it means you've disabled the macros in this workbook.
Please make sure macro security is set to "Medium"
then close Excel entirely, reopen this file
and select "Enable Macros" when prompted.
If you attempt to view or modify this file without proper
authorization you will be added to the list herein.
-[Signed] Richard M. Nixon
A really really secure workbook would not contain the users and passwords in a hidden sheet. In fact, I never do this. Most of my apps are database driven, and I authenticate users against both the domain and a custom table in the application database. This effectively keeps anyone from using it unless they're onsite and connected to the network. I also usually flush all the data from the relevant worksheets when the user closes the workbook to a) keep the file size smaller and b) keep sensitive data from being stored in it and taken offsite. But that's beyond the original scope of your question.
'Why is [the following] necessary? What is being saved? Purpose?
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ThisWorkbook.Save
A: There are two scenarios for closing the application: 1) a failed login attempt and 2) a successful login by a user who has finished making changes.
Take case (2) first. We want to hide all the sensitive information before closing so that the next person who opens the file only sees SplashPage and the login form. We know the user is closing the workbook because we have this code in the ThisWorkbook module BeforeClose event script:
'Module: ThisWorkbook
Private Sub Workbook_BeforeClose(Cancel As Boolean)
doWorkbookClose
End Sub
All it does is call this subroutine in Module1:
Sub doWorkbookClose()
On Error Resume Next
With Sheets("SplashPage")
.Visible = xlSheetVisible
.Activate
End With
Sheets("Plan1").Visible = xlSheetVeryHidden
Sheets("Users").Visible = xlSheetVeryHidden
ThisWorkbook.Save
End Sub
Since our close routine makes changes to the workbook to hide sensitive information, those changes need to be saved. If ThisWorkbook.Save wasn't there, Excel would prompt the user if they wanted to save "their" changes. Which is annoying at best, confusing at worst, because most users will have already pressed "Save" before closing. And if we give them the option here now to close without saving, then we run the risk of all those sensitive worksheets we've just made xlVeryHidden visible to the next user. And that next user could be a bad guy who knows how to disable macros (or anyuser who simply has macro security set above Medium) which means that the following code wouldn't run:
Private Sub Workbook_Open()
On Error Resume Next
Sheets("Users").Range("D1").Value = 3
With Sheets("SplashPage")
.Visible = xlSheetVisible
.Activate
End With
Sheets("Plan1").Visible = xlSheetVeryHidden
Sheets("Users").Visible = xlSheetVeryHidden
ThisWorkbook.Save
frmLogin.Show
End Sub
which is my semi-paranoid-self trying to make it as sure as possible that the next user opening this file doesn't see something I don't want them to.
Note that none of this secuity is bomb-proof. It will lock out most average Excel users that you don't want in it, but someone who knows more about VBA than I do could probably find a way in.
Yes, that was an invitation. :)