简体   繁体   中英

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("Reimbursements"), 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 (ie 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 (ie when capturing the return value into a local variable):

Dim result As vbMsgBoxResult
result = MsgBox("test", vbInformation Or vbOkCancel)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM