VBA Compile Error on Function Call - sql

so I'm trying to run this SQL script within a function I call and it's giving me a "Compile Error: Object Required" when I try to run it!
Code calling the function
Private Sub cmdLogin_Click()
Call Load_Username(Username)
End Sub
Function being called
Private Sub Load_Username(Text As String)
Dim SQL As String
Set SQL = "UPDATE tbleUsername " & _
"SET Username = '" & Text & "' " & _
"WHERE ID = 1"
DoCmd.RunSQL SQL
End Sub

Dim SQL As String
Set SQL = "string literal"
You can't use Set to assign a string literal. Use Set to assign object references. That assignment is illegal, because an object is required. Hence, Object required.
Two possible fixes:
Remove the Set keyword and use the wonderful implicit value assignment syntax.
Replace the Set keyword with the obsolete Let keyword for a long-deprecated explicit value assignment syntax. Only suggesting because I'm seeing you use the long-deprecated Call keyword too.

I think that you should define variable Username before call function LoadUsername(UserName)

Related

Parse enum values by name in VBA

I want to write some VBA code that should parse MSForms-constant names (given as a string, like "fmTextAlignLeft") into their actual value. Since there is no native way to do so I was considering to put the name of the constant into a powershell code that will then be executed and return the result.
Private Sub ParseEnumByName(EnumConst As String)
Dim WScript As New WshShell
Dim PSCode As String
Dim Result
PSCode = "(some code)" & EnumConst & "(more code with exit $Value statement)"
Result = WScript.Run("Powershell -command """ & PSCode & """", 0, True)
ParseEnumByName = Result
End Sub
This should be feasible by iterating through all enums in the MSForms library and get the values out of them with something like
[System.Enum]::GetNames( [System.Windows.Forms.FormBorderStyle] ) or maybe something like explained here: How to convert a string to a enum?
The problem is that the System.Windows.Forms library contains totally different enums and typenames than the MSForms library available in VBA.
I tried to Add-Type -Path "C:\Windows\SysWOW64\FM20.DLL" where the MSForms library is stored but it returns an error saying the file or assembly or some related file could not be found.
How may I get a reference to MSForms in Powershell?
Edit: I have actually found a demi-native way in VBA (Excel VBA only) to solve this issue without passing values to external script hosts. Please see below.
Here's the function I figured out. So far it seems to work with all pre-defined enums and constants and also self defined enums in Excel. The function must be placed in a module!
Static Function ParseValue(StringValue) As Variant
Dim ParseValueBuffer As Variant
If IsEmpty(ParseValueBuffer) Then
ParseValueBuffer = 1
Application.Run ("'ParseValue " & StringValue & "'")
ParseValue = ParseValueBuffer
ParseValueBuffer = Empty
Else
ParseValueBuffer = StringValue
End If
End Function
Sub TestMe()
MsgBox "First line" & ParseValue("vbcrlf") & "Second line"
MsgBox ParseValue("fmTextAlignCenter") 'Should return "2" (if MSForms is referenced)
MsgBox ParseValue("rgbblue") 'Should return 16711680
End Sub

Constructor in VBA - Runtime error 91 "Object variable not set"

I am trying to write some code in excel VBA using the Object Oriented Concept. Therefore I wanted to initialize my objects with constructors, like we usually do in Java. However I discovered that the default Class_Initialize() Sub that is offered in VBA does not take arguments. After searching a bit, I found that the answer for this Question proposed a pretty good alternative.
Here is a sample of my Factory Module (I Named it Creator):
Public Function CreateTool(ToolID As Integer) As cTool
Set CreateTool = New cTool
CreateTool.InitiateProperties (ToolID) '<= runtime error 91 here
End Function
The class cTool:
Private pToolID As Integer
Private pAttributes As ADODB.Recordset
Private pCnn As ADODB.Connection
Public Sub InitiateProperties(ToolID As Integer)
Dim sSQL As String
Set pCnn = connectToDB() 'A function that returns a connection to the main DB
pToolID = ToolID
sSQL = "SELECT Tool_ID, Status, Type, Tool_Number " _
& "FROM Tool WHERE Tool_ID = " & pToolID
pAttributes.Open sSQL, pCnn, adOpenKeyset, adLockOptimistic, adCmdText
End Sub
This is how I call the constructor:
Dim tool As cTool
Set tool = Creator.CreateTool(id)
My issue is that when I run the code, I get the following error:
Run-Time error '91' : Object Variable or With Block Variable not Set
The debug highlights the CreateTool.InitiateProperties (ToolID) line of my CreateTool Function.
I know that this usually happens when someone is setting a value to an object without using the keyword Set but it does not seem to be my case.
Any help, advice to resolve this issue would be greatly appreciated!
Thanks.
Might not be the cause of your error, but this:
Public Function CreateTool(ToolID As Integer) As cTool
Set CreateTool = New cTool
CreateTool.InitiateProperties (ToolID) '<= runtime error 91 here
End Function
Is problematic for a number of reasons. Consider:
Public Function CreateTool(ByVal ToolID As Integer) As cTool
Dim result As cTool
Set result = New cTool
result.InitiateProperties ToolID
Set CreateTool = result
End Function
Now, looking at the rest of your code, you're doing the VBA equivalent of doing work in the constructor, i.e. accessing database and other side-effects to constructing your object.
As #Jules correctly identified, you're accessing the unitialized object pAttributes inside InitiateProperties - that's very likely the cause of your problem.
I'd strongly recommend another approach - if you come from Java you know doing work inside a constructor is bad design... the same applies to VBA.
Get your code working, and post it all up on Code Review Stack Exchange for a full peer review.

VBA Error in sql function call escapes error trap

When an sql query makes a call to a vba function and that function raises an error, the error handling code fails to handle the error.
See example below. The call to GetId() in the strSql generates an error when the Set rst = db.OpenRecordset(strSql) is executed.
This error is not handled by the On Error GoTo Err_Test error handler!
Public Function GetId() As Long
Err.Raise 11 'Divide by zero error
End Function
Public Function Test() As String
On Error GoTo Err_Test
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim strSql As String
Set db = CurrentDb()
strSql = "Select * FROM MyTable WHERE MyTable.Id = GetId()"
Set rst = db.OpenRecordset(strSql)
Test = rst!name
Exit_Test:
If Not rst Is Nothing Then
rst.Close
Set rst = Nothing
End If
Set db = Nothing
Exit Function
Err_Test:
MsgBox Error$
Resume Exit_Test
End Function
Why does the error escape the error handler and is there some way to handle it gracefully when the sql makes a call to a vba function that generates an exception?
I know that removing the function call from the sql string as shown below, will enable the error handler to trap the error.
Dim id as Long
id = GetId()
strSql = "Select * FROM MyTable WHERE MyTable.Id = " & id
Is this the only way? If so, should one avoid using function calls in sql query strings to avoid unhandled exceptions?
My take on the observed behavior is this:
When you run "Select * FROM MyTable WHERE MyTable.Id = GetId()", GetId() is evaluated by the query engine, not by Test(), so the error handler in Test() cannot catch the runtime error. It's the same as if you would put the SQL into a query and run that.
When you do "Select * FROM MyTable WHERE MyTable.Id = " & GetId(), GetId() is evaluated by Test().
This would be the "normal" way to run your example (open a recordset in a VBA function), IMO.
But you can also use VBA functions like GetId() in queries. You only need to make sure that either the function is simple enough that it can't trigger a runtime error, or that the function has its own error handler.
If the function is run only once (in the WHERE clause), a MsgBox is acceptable as error handler. If the function is run for every row (i.e. it's in the SELECT clause), this can make for a truly horrible user experience. :p
So make sure that in this case the function returns an error code or NULL or whatever is applicable, like vacip wrote.

OPTION STRICT OFF - NULL Exception

Please see the code below:
Dim strHideReason As String = strHideReason & " " & objDBDR.GetName(intHideCheck) & " is " & objDBDR(intHideCheck)
objDBDR(intHideCheck) is null. objDBDR is a datareader.
The code above compiles, however I am trying to set option strict to on, so I now have to do this:
Dim strHideReason As String = strHideReason & " " & objDBDR.GetName(intHideCheck) & " is " & cstr(objDBDR(intHideCheck))
It now throws an exception. I can refactor the code to resolve this, however I am confused why the first compiles. Does the compiler ignore objects that are null in string concatenations when option strict is off?
When you have OPTION STRICT OFF:
On runtime your object objDBDR(intHideCheck) will be automatically converted(if it possible) to type string.
From MSDN
For strings in Visual Basic, the empty string equals Nothing
objDBDR(intHideCheck) return Nothing which will be converted to string as empty string.
When you have OPTION STRICT ON:
This option restrict implicit conversions, and you must convert objects to string by your self.
For function Cstr if parameter is null, then runtime error will be throw
This answer will explain why runtime error will be thrown:
https://stackoverflow.com/a/979911/1565525

Defined Error in Visual Basic

When i using this const statement,my coding work fine.
Const strFullName As String = "C:\Sample\Haha.txt"
After i change the Search.text (Textbox Name),it keep on come out the error.
Const strFullName As String = "C:\Sample\" & Search.Text & ".txt"
Compile error:
Constant expression required
Then i try create a textbox1.text = Searchbox.Text. The textbox1 shows C:\Sample\Haha.txt
Please Help,Thanks~
Search.Text is not a constant value - it's a run-time property and its value is not known until run-time so it cannot be assigned to a constant. You can just define your strFullName as a variable instead of a constant:
Dim strFullName As String
...
' Set strFullName at run-time
strFullName = "C:\Sample\" & Search.Text & ".txt"
If Search is a textbox, you may also want to check if it has valid input to make sure that you're not trying to form an invalid file name; for example, you can use Len(Search.Text) to determine the length of the text in the textbox.