Invalid Use of Null Access VBA - ms-access

I'm attempting to write the code for a login system for an Access database I'm working on, and everything is running smoothly apart from this one error.
I'm getting an
Invalid Use of Null
error after I put the login details into the login form I've created, which works fine. The problem is with the code that is supposed to restrict the forms viewable to "Read-Only" if a user only has read permissions. I've done a bit of looking into the issue, and it would seem that the error is caused by VBA attempting to read an integer from a field with a NULL value, but VBA won't tell me exactly where the error is, only the line.
I'm posting the code I have for the actual Navigation form in the hopes that someone can point out where my error is so I can set about fixing it. This is the only issue my login system has, it's just a case of identifying where the problem actually is so I can implement any changes needed, as I have a feeling it's having problems identifying where the actual Userlevel value is coming from.
Option Compare Database
Option Explicit
Private Sub Form_Load()
Dim UserLogin As String
Dim UserLevel As Integer
UserLogin = Environ("UserName")
Me.TxtLogin = UserLogin
UserLevel = DLookup("[UserType]", "TblUser", "[UserLogin] = '" & Me.TxtLogin
& "'")
If UserLevel = 3 Then
Me.AllowAdditions = False
Me.AllowDeletions = False
Me.AllowEdits = False
End If
End Sub

You did not mention where the error happened. I suppose it is on line
UserLevel = DLookup("[UserType]", "TblUser", "[UserLogin] = '" & Me.TxtLogin & "'")
You should Dim UserLevel as Variant since Dlookup may return a Null.
Alternatively, you can leave UserLevel as Integer and use:
UserLevel = Nz(DLookup("[UserType]", "TblUser", "[UserLogin] = " & Me.TxtLogin & "'"),0)
to turn a possible Null into a 0.

Use the NZ() function to escape nulls.
Nz(Value, ValueIfNull )
UserLevel = DLookup("[UserType]", "TblUser", "[UserLogin] = '" & NZ(Me.TxtLogin,"") & "'")
Reference:Application.Nz Method (Access)
#PatrickHonorez brings up a good point. But you can also use the NZ function to wrap the DLookup.
UserLevel = NZ(DLookup("[UserType]", "TblUser", "[UserLogin] = '" & NZ(Me.TxtLogin,"") & "'"),"")

Related

Unwanted Scientific Notation in MS Access

I'm encountering a very strange problem with MS Access. I have some VBA code used on a password reset form. The code hashes the input password and then saves the hash to a table of users. Here's a relevant snippit:
If newPW1 = newPW2 Then
MsgBox ("Passwords Match!")
hashPW = Encrypt(newPW1)
MsgBox ("HashedPW is " & hashPW)
updatePW = "UPDATE Users SET Password = " & hashPW & " WHERE Username = pwChangeUsrnm"
DoCmd.RunSQL (updatePW)
the MSGboxes are my debugging notes. I know the hash generates properly as a long string of numbers, all well and good. When I go into the datasheet for the Users table though, the number has always been converted into scientific notation.
Here's a screenshot of the data sheet. bob.smith is an example of what I end up with after the code runs, the other two are gibberish I entered manually. The field is formatted as a string, so I'm not sure why it would even try to convert the number into SN when as far as I can tell the item is always a string.
I'm thinking the error must creep in around the SQL query? If there's a better way of doing this then I'm all ears.
Thanks in advance for your help!
datasheet
design view
Complete code, just in case:
Option Compare Database
Private Sub Command84_Click()
Dim hashPW As String
Dim updatePW As String
Dim checkName As String
checkName = Nz(DLookup("Username", "Users", "Username = pwChangeUsrnm"), "aaa")
MsgBox ("checkName set to " & checkName)
If pwChangeUsrnm = checkName Then
MsgBox ("Username Found")
If newPW1 = newPW2 Then
MsgBox ("Passwords Match!")
hashPW = Encrypt(newPW1)
MsgBox ("HashedPW is " & hashPW)
updatePW = "UPDATE Users SET Password = " & hashPW & " WHERE Username = pwChangeUsrnm"
DoCmd.RunSQL (updatePW)
Else
MsgBox ("Passwords Do Not Match!")
End If
Else
MsgBox ("Username not found")
End If
End Sub
I think Andre has the right of it. I tried adjusting the hashing code to add a letter character and this worked, but then I needed to go back and add the single quote around the hashed PW value- which probably would have made the code work even without adding the letter:
If newPW1 = newPW2 Then
MsgBox ("Passwords Match!")
hashPW = Encrypt(newPW1)
MsgBox ("HashedPW is " & hashPW)
updatePW = "UPDATE Users SET Password = '" & hashPW & "' WHERE Username = pwChangeUsrnm"
DoCmd.RunSQL (updatePW)
A thanks to Zaph's second comment on security as well, I'll take that all into account. For the purposes of this database security isn't too much of a concern as it will be sitting behind existing security measures. The hashing of passwords is more just to avoid ever displaying the passwords in plain text. Nevertheless it's useful to know about these extra functions.

Warning for Dynamic Combobox list

I have a combobox that builds it's list upon first usage. I know that the way I want "NotInList" to behave isn't conventional - I don't want to waste adding the item to a table separate from the needed entry, but I'd like to still warn about an item that hasn't been used yet, so that the user has to think twice before accepting the entry.
Once the user adds the item, it will automatically appear in the list next time because the data source for the combo box is as follows:
SELECT tbl_SP.PROGRAM
FROM tbl_SP
GROUP BY tbl_SP.PROGRAM
HAVING (((tbl_SP.PROGRAM) Is Not Null And (tbl_SP.PROGRAM)<>""));
I tried this:
Private Sub cmbPROGRAM_NotInList(NewData As String, Response As Integer)
If MsgBox("'" & Chr(34) & NewData & Chr(34) & " hasn't been used yet. Add to list? ", vbQuestion + vbYesNo, "Add - " & NewData & "?") = vbYes Then
Response = acDataErrAdded
End If
End Sub
but of course, Access wants the item to actually exist before it will release the error. And...if I set LimitToList to "No" then the user doesn't get a warning.
How can I achieve this behavior?
Ok, I tried this which works fine if the user selects YES, but becomes more complicated when the user selects "NO"
Public Function ReturnsRecords(strSQL As String) As Boolean
Dim d As DAO.Database
Dim arr(1 To 3) As DAO.Recordset
'Dim rs As DAO.Recordset
'assume 3 items in array above
Set d = CurrentDb
Set arr(1) = d.OpenRecordset(strSQL)
' MsgBox "Record Count is " & arr(1).RecordCount
If arr(1).RecordCount > 0 Then
ReturnsRecords = True
Else
ReturnsRecords = False
End If
Set d = Nothing
End Function
Private Sub cmbPROGRAM_BeforeUpdate(Cancel As Integer)
Dim strSQL As String
strSQL = "Select * from LU_PROGRAM where PROGRAM ='" & Me.cmbPROGRAM & "'"
If ReturnsRecords(strSQL) = False Then
If MsgBox("'" & Chr(34) & Me.cmbPROGRAM & Chr(34) & " hasn't been used yet. Add to list? ", vbQuestion + vbYesNo, "Add - " & Me.cmbPROGRAM & "?") = vbNo Then
Cancel = True
' how do I reset this? Me.cmbPROGRAM.Text = Null
End If
End If
End Sub
How do I clear the combobox if the user selects NO? If I select me.undo, that will undo all of the entries, but I just want to clear the combobox.
Incidentally, the form is totally unbound and doesn't accept an entry until the user selects "Save"
First, I'm not quite sure what you wish to achieve ...
Then, educate the users to press Escape to cancel. This is mandatory wisdom when operating an Access application.
For your code to work, you can't change the content of a control in the BeforeUpdate event. So try the AfterUpdate event with either:
Me!cmbPROGRAM.Text = ""
or:
Me!cmbPROGRAM.Value = Null

Why is my DLOOKUP returning only a partially correct record?

Alright. This is my first post ever so I'll try to be as detailed as I can. I have a Person_AfterUpdate() event on a Form named frm_Contact_Info, that is supposed to check a table, named "tbl_Contact_Info," for an existing record. If the record exists, then a message pops up stating that the record already exists, and to check the name. Then it asks if I am creating a new record with the existing name, or if the record that is returned is the same person. The problem I am having is that the DLookup shows the correct name, but does not return the correct phone number or address to my form.
Here is my code. I'm not super skilled at programming, but I tried to make it as understandable as possible. If you want screen shots, let me know. This is the first time I've actually tried to build a database, and I know my skills are not as great as some of yours. I've tried to research as much as I could to find the answer to this, but everything I've tried so far brings me back to this problem where the DLOOKUP is returning the correct NewPerson, but not the correct phone number or e-mail address. Please help!
Private Sub Person_AfterUpdate()
Dim NewPerson As String
Dim stLinkCriteria As String
Dim PersID As Integer
On Error GoTo E:
NewPerson = Me.Person.Value
stLinkCriteria = "[Person] = " & "'" & NewPerson & "'"
If Me.Person = DLookup("[Person]", "tbl_Contact_Info", stLinkCriteria) Then
MsgBox "The name, " & NewPerson & ", has already been added to the database." _
& vbCr & vbCr & "Please check the name and try again.", vbInformation, "Duplicate Information"
Me.Undo
End If
PersID = DLookup("[ID]", "tbl_Contact_Info", stLinkCriteria)
Me.DataEntry = False
DoCmd.FindRecord PersID, , , , , acCurrent
Response = MsgBox("Are you adding a new record with the same name?", vbYesNo, "New or Existing Record")
If Response = vbYes Then
DoCmd.GoToRecord , "", acNewRec, 1
Me!Person.Value = NewPerson
Else
Me.DataEntry = True
DoCmd.GoToRecord , "", acNewRec, 1
End If
Exit Sub
E:
Me!Person.Value = NewPerson
End Sub`
Perhaps you have multiple records with the same value in the attribute you are using as your lookup value?

Is this kind of login possible in VBA?

I work on Access Project, but I think there is nothing specific to Access in this question.
I have a form and it's possible to open it only if you are in the table of authenticated users (and I authenticate user by his windows username) - I know it is lame authentication.
Here's the code I've put into form open event:
Private Sub Form_Open(Cancel As Integer)
If DCount("User_Id", "Users", "[username]='" & (Environ$("Username")) & "'") Then
Else
MsgBox "Access Denied!"
DoCmd.Quit
End If
End Sub
What I want to accomplish is that when MsgBox "Access Denied!" is displayed, if I type certain word (something as password) before clicking on OK button, that DoCmd.Quit is not executed. I don't want to display anything, just type in the password.
I don't need this desperately, I just want to make this for fun. And I think it would be really cool if it's possible with VBA.
I tested this in Access 2007 and I think the logic is what you want, or at least it's close. Please consider using something like the WindowsUser() function below to get the Windows user name. I get that this is just for fun, so you don't care now. However, keep this point in mind for anything you do care about in the future. Environ("USERNAME") as a security measure is trivially easy to defeat.
Const cstrYourPassword As String = "let me in"
Dim blnGoodbye As Boolean
Dim lngButtons As Long
Dim strPrompt As String
Dim strPassword As String
strPrompt = "Access Denied!" & vbCrLf & vbCrLf & _
"Click Retry to try with password" & vbCrLf & _
"or Cancel to quit."
lngButtons = vbCritical + vbRetryCancel
If MsgBox(strPrompt, lngButtons) = vbRetry Then
strPassword = InputBox("Password:")
If strPassword = cstrYourPassword Then
MsgBox "Welcome " & WindowsUser
Else
blnGoodbye = True
End If
Else
blnGoodbye = True
End If
If blnGoodbye = True Then
MsgBox "That's all folks."
'DoCmd.Quit ' <- enable this when ready.
End If
Use this instead of Environ("USERNAME").
Public Function WindowsUser() As String
Static strUserName As String
If Len(strUserName) = 0 Then
strUserName = CreateObject("WScript.Network").Username
End If
WindowsUser = strUserName
End Function
The following should work, but you may want to modify it to set the password to something better or if you want more than one password. Anyone who knows how to read the code will be able to find out the password as well, so maybe it would be better to put it in the database somewhere?
Const sPassword As String = "PASSWORD"
Const sMESSAGE As String = "Please enter your password"
Const sTITLE As String = "Enter Password"
Dim sInput As String
sInput = InputBox(sMESSAGE, sTITLE)
If sInput <> Password Then
MsgBox "Access Denied!"
DoCmd.Quit
End If

How to use Access' OpenRecordset to get a record using its numeric key field?

I have a problem in Access 2010 VBA trying to read a record from table to write it into TextBoxes.
My table is "Products" and its ProductID field is numeric. I used this method before, but it just works for text fields, not for numeric fields (ProductID is autonumber).
Private Sub GetProduct(ID As TextBox, Name As TextBox, Price As TextBox)
If ID <> "" Then
Set db = CurrentDb
Set rs = db.OpenRecordset("Productos", dbOpenDynaset)
'PROBLEM IS HERE
rs.FindFirst "ProductID=" & "'" & ID & "'"
If rs.NoMatch Then
MsgBox "The producto doesn't exist."
Price = ""
Name = ""
Else
Name = rs!ProductName
Price = rs!Price
End If
rs.Close
Set rs = Nothing
Set db = Nothing
End If
End Sub
Please, help me. This is for a Final Proyect and I don't know other, but this method. Please help me.
Good to see you figured it out.
The problem is that ProductID is numeric and your code specifically tests for a text field
rs.FindFirst "ProductID=" & "'" & ID & "'"
putting a single quote each side of the parameter makes Access parse the parameter as a string.
If ID is 123, this will read
rs.FindFirst "ProductID='123'"
and you get a type error
I found a simple solution!
rs.FindFirst "ProductoID=" & ID