VBA multi-parameter function call Syntax Error
I'm trying to call a function in Excel VBA (2007), and am recieving a syntax error on the call. I have an array of data structures called ImportSets, which contains worksheets and strings, and am trying to pass members of items in that array to a function, called Import.
The calling code looks like this:
For n = 1 To 7
Debug.Print ("Destsheet: " & ImportSets(n).DestSheet.name)
Debug.Print ("Sourcesheet: " & ImportSets(n).SourceSheet.name)
Debug.Print ("Sourcecolumn: " & ImportSets(n).SourceColumn)
Import(CostAnalysisWorksheet.Sheets("Reimburs开发者_运维知识库ements"), ImportSets(n).DestSheet, ImportSets(n).SourceSheet, ImportSets(n).SourceColumn)
Next n
All of the Debug.Print statements return meaningful and correct strings, and check for the existence of "Reimbursements" returns true. The method call is on one line. Here is the ImportSet object code:
Public Type ImportSet
DestSheet As Worksheet
SourceSheet As Worksheet
SourceColumn As String
...other code...
End Type
The function body looks like this:
Function Import(ByRef ReimbursementSheet As Worksheet, ByRef DestSheet As Worksheet, ByRef ImportSheet As Worksheet, ByRef ImportSheetPriceColumn As String) As String
....code here .....
End Function
I am getting a red-highlighted syntax error on the function call (in the first snippet). I am probably missing something stupid. What is it?
I haven't used VBA in Excel 2007 but older versions only allow you to put brackets around function call parameters if you're assigning the return value to a variable. Try this:
Import CostAnalysisWorksheet.Sheets("Reimbursements"), ImportSets(n).DestSheet, ImportSets(n).SourceSheet, ImportSets(n).SourceColumn
The important point is how you want the function to return the value and whether your passing variables ByVal or ByRef. ByRef allows the function to change the variable ByVal means the function cannot change the variable.
These 2 examples essentially do the same thing but note the subtlety in manipulating a variable ByRef and returning a variable from a function.
Sub test()
Dim lngX As Long, lngY As Long, Product As Long
lngY = 10
lngX = 5
Product = multiply(lngX, lngY)
MsgBox (Product)
End Sub
Function multiply(ByVal lngX As Long, ByVal lngY As Long) As Long
multiply = lngY * lngX
End Function
or alternatively pass the variables ByRef and manipulate with the function
Sub test()
Dim lngX As Long, lngY As Long, Product As Long
lngY = 10
lngX = 5
Product = 0
multiply lngX, lngY, Product
MsgBox (Product)
End Sub
Function multiply(ByVal lngX As Long, ByVal lngY As Long, ByRef Product As Long)
Product = lngY * lngX
End Function
This example is quite trivial but often an object, array etc may need passed to a function for processing ByRef rather than to provide an answer ByVal
This Q&A is being used as a duplicate target, but none of the answers are telling the whole story.
First, this behavior has nothing to do with the version of Excel or whatever the host application is: it's just standard VBA syntax, and the rules have been been the same for well over 20 years now - JavaScript and Perl have their respective kinks as well, as does every single programming language ever made.
When the parentheses are delimiting an argument list, the VBE puts the opening parenthesis immediately after the invoked function:
foo = MsgBox("test")
^^^
When the parentheses are interpreted as part of the first argument (i.e. a parenthesized expression), the VBE puts a space between the invoked procedure and its argument list:
MsgBox ("test")
^^^
This code wouldn't compile:
MsgBox ("test", vbInformation)
^^^
Because the entire parenthesized expression is the first argument, and there's no way ("test", vbInformation)
can be evaluated as a value - it's a syntax error, like in the OP.
If the expression can be evaluated as a value, this value is then passed by value (ByVal
) regardless of the invoked procedure's signature specifying that parameter as ByRef
- see 5.3.1.11 Procedure Invocation Argument Processing, runtime semantics:
- If the parameter has no argument mapped to it, the parameter is ByVal, or the parameter is ByRef and the mapped argument’s expression is classified as a value, function, property or unbound member, a local variable is defined with procedure extent within the procedure being invoked with the same name value and declared type as the parameter [...]
The solution is, as others concluded, to drop the parentheses when making a procedure call:
MsgBox "test", vbInformation
...or to consistently use the obsolete explicit call syntax:
Call MsgBox("test", vbInformation)
Parentheses are only needed when making a function call (i.e. when capturing the return value into a local variable):
Dim result As vbMsgBoxResult
result = MsgBox("test", vbInformation Or vbOkCancel)
精彩评论