Byref vs Byval vba clarification - ms-access

I was writing some VBA to futher my understanding of Byref and Byval. This is what I am using:
Private Function Checkcase()
Dim i As Integer
i = 1
Debug.Print i
num(i)
Debug.Print i
End Function
Public Function num(ByRef i As Integer)
i = 5
End Function
Output
1
1
However, when I use the call keyword in front of num(i) like:
call num(i)
The output changes to
1
5
I was expecting the output to be 1 and 5 in both cases as I am changing the reference of the variable i

num(i) is the error here. When you call a sub or a function without getting the return value, you must not put parentheses around the arguments.
When you pass arguments with parentheses to a function expecting ByRef arguments, those are automatically cast to ByVal.
Either use Call num(i) or remove the parentheses num i
References: Call :
If you omit the Call keyword, you also must omit the parentheses around argumentlist.
As always, Cpearson site is a must read

Related

VBA - Compile error: Expected: If or Select or Sub or Function or Property or Type or With or Enum or end of statement

Forgive me for the noob question. Working in VBA is not my normal job.
I get the error listed in the title. The offending code is this:
While index <= 10
index = index + 1
End While
I can't imagine what could be wrong with that, seeing that it is copied directly from the documentation: https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/while-end-while-statement
Seeing that the code can't be the problem, I'm supposing the problem must be something in the context, but before I put this block in, it was working fine.
This block of code is part of a simple, private subroutine which declares a variable, assign a value to it, and then writes it into a file, like so:
Private Sub btnExpAll_Click()
Dim sFldr As String
sFldr = BrowseFolder("Where do you want to export the files?")
If sFldr = "" Then Exit Sub
DoCmd.Hourglass True
Dim sListLocal As String
Dim index As Integer
Dim strInputFileNameLocal As String
sListLocal = ""
index = 0
While index <= 10
index = index + 1
End While
strInputFileNameLocal = sFldr & "\list-local.html"
Open strInputFileNameLocal For Output As #1
Print #1, sListLocal
Close #1
DoCmd.Hourglass False
End Sub
The idea is to add more text to the file as we go through the while loop based on certain conditions - but since I can't even get the while loop to compile...
Link referenced in question is VB.net example, which has similarities to VBA and in some simple examples, easily confused. Replace End While with Wend or use Do … Loop structure.
Review: https://excelmacromastery.com/vba-while-loop/

How can I assign subroutine value to variable in access VBA

I have below procedure in Module1:
public sub Evaluate(Salary as double)
Dim Overtimesalary as Double
Overtimesalary = salary * 1.5
End Sub
Now, I am calling this procedure for my form click button event to calculate overtime salary and taking input value from textbox value from form, Code for that,
When I am trying to execute below code, I am getting "Compile error: Expected function or variable":
Private sub cmd_Calculate()
Dim Test as Double
test = Evaluate(txt.salary.value)
MsgBox Test
End Sub
Convert your subroutine into a Function, and return your value as the function's value.
public Function Evaluate(Salary as double)
Evaluate = salary * 1.5
End Sub
This will run the procedure, perform the calculation, then return the value assigned within the function to the calling subroutine.
That said, I'm assuming that this is a simplified version of what you're actually doing - if all you're doing is literally multiplying a value by 1.5, you can just do that in the main subroutine!

Use object as variable for function

I'm trying to create a function called wait that would use an object:
Function wait(browser As Object)
' loop until the page finishes loading
Do While browser.READYSTATE <> 4
Loop
End Function
I also have:
Function GetIE() As Object
On Error Resume Next
Set GetIE = CreateObject("InternetExplorer.Application")
End Function
and:
Dim appIE As Object
Set appIE = GetIE
sURL = "http://google.com"
wait (appIE)
But i'm getting "Run time error '424'; Object required.
Any idea?
Change this line
wait (appIE)
to
wait appIE
Explanation: In VBA, whenever you call a Function that has parameters, if you are not doing anything with the return value, then you have to call it without the parenthesis. In this case, since the code is not returning anything, it should be defined as a Sub and not a Function. The same thing applies to Sub routines that take parameters also, i.e. you have to call it without parenthesis with the parameters separated by comma.
Further Reading (via #doug) : Quick VBA Tip: Parentheses

Eval scope in Access VBA

Please help.
=Does not work:
Function f()
f = 1
End Function
Private Sub Button1_Click()
k = Eval("f()")
End Sub
=Does not work:
Private Sub Button1_Click()
с=1
k = Eval("с")
End Sub
=Do work:
Function f()
f = 1
End Function
Private Sub Button1_Click()
k = f()
End Sub
=In help:
The following example assumes that you have a series of 50 functions defined as A1, A2, and so on. This example uses the Eval function to call each function in the series.
Sub CallSeries()
Dim intI As Integer
For intI = 1 To 50
Eval("A" & intI & "()")
Next intI
End Sub
How to make variant 1 work?
Thanks in advance.
++++++++++++++++++++++++++++
=UPDATE:
The number of error I get with "Does not work" sections is 2425. "Can not find the name of the function." (or "Can not find the name of the expression." in the second case). Sorry for my English.
=UPDATE:
When I try explicitly name the function in Eval:
k = Eval("[Forms]![Form1].f()")
I get error 31005 - "Access can not calculate expression because there is a reference to "f"". I start to be suspicious of Access prohibiting use of user-defined functions and variables in Eval. Though help states opposite.
=UPDATE:
Do work:
Function f()
f = 1
End Function
Private Sub Button1_Click()
k = Eval("val(""551" & "9" & "6"")")
End Sub
Very strange rules of double-quoting, as for me. But this does not solve my problem.
The Eval function cannot access functions that are in Form modules. Place the function in an ordinary Module.
There is one interesting fact. Eval() does not accept user variables as arguments, but accepts form controls data.

Returning Multiple Values from a Custom Function

So, I've got a ValidateForm function that loops through a form to validate each control. I have a collection set up called ValData to capture different bits of info to be passed out of the function. This is working great.
However, I don't know how to access each item in ValData after the function returns. I can get one at a time like: ValidateForm().IsValid, but in order to get each item, I have to run the function again. I want to avoid this.
Is there a way to run the function once, but access the values of each item returned?
Depending upon your requirements (which are NOT clear in your question! ;-) ), you might consider using a Collection as the return from your function:
Private Function MyResultsFunction() As Collection
Dim output As Collection
Set output = New Collection
'Hydrate your collection with data by whatever means necessary:
With output
'Stupid example code:
.Add "Item1"
.Add "Item2"
.Add "Item3"
.Add "Item4"
End With
'Return a reference to the collection as the function output:
Set MyResultsFunction = output
End Function
As a simple, retarded test of the above:
Private Sub Form_Load()
'A variable to receive the results from your function:
Dim Results As Collection
'An iterator to loop through the results contained in the collection:
Dim CurrentItem As Variant
'For this example, a string to toss the results into to display in the
'MsgBox:
Dim output As String
'Use the local Collection defined above to access the reference returned by
'your function:
Set Results = MyResultsFunction
'Iterate through the collection and do something with the results
'per your project requirements:
For Each CurrentItem In Results
'This is stupid example code:
output = output & CurrentItem & vbCrLf
Next
'I am just displayng the results to show that it worked:
MsgBox output
'Clean up:
Set Results = Nothing
End Sub
Hope that heps!
Without seeing your code it's hard to say what exactly you are tyring to do, but here is one of several ways you can store results to query later.
Declare a public variable at the top of your module to represent the items from your ValData function. After you populate the array, you can access the items through a normal function.
You obviously could do more sophisticated things, especially if you use a collection object. You could even store a counter and create a GetNext() function. I hope this gives you a heads start.
Public Results(1 To 2) As String
Sub CreateTestArray()
Results(1) = "Foo"
Results(2) = "Bar"
End Sub
Function GetResult(ByVal i As Long) As String
If i <= UBound(Results) Then
GetResult = Results(i)
End If
End Function
Sub ProofOfConcept()
MsgBox GetResult(2) ' will show "Bar"
End Sub