This question already has answers here:
VBA does not accept my method calling and gives Compile error: Syntax error [duplicate]
(2 answers)
Closed 3 years ago.
I have a small VBA macro in Word that will not compiles with an Expected: = error. Since these are all subroutines I am not sure what would cause this. I have simplified this as much as possible to the code listed below.
Sub test()
tmp = MsgBox("test")
test2("tmp2","tmp3") ' this is the line where the compile error appears.
End Sub
Sub test2(test1String As String, test2String As String)
MsgBox (test1String)
End Sub
I would not expect there to be any assignment errors with something this simple. Enter the code and try to run the test macro.
You are calling a Sub, not a Function. The syntax
test2("tmp2","tmp3")
calls the sub test2 with only one argument, namely an (invalid) expression ("tmp2","tmp3")
You should call it as
test2 "tmp2","tmp3"
The braces ( and ) turns the argument list in an expression.
Note: also when calling a function with braces around the argument list requires that the function result is assigned, otherwise the function arguments too are evaluated as an expresion
i = myFunction(1, 2) ' valid
myFunction 1, 2 ' valid
myFunction(1, 2) ' invalid
mySub(1, 2) ' invalid
mySub 1, 2 ' valid
mySub(1 + 2), (3 + 4) ' valid!
The last example calls the sub with two arguments, which both are expressions.
Related
I am getting the 800A0414 error in lines 7 and 12 of this script:
Module Module1
Dim p
Sub Main()
CreateObject("Wscript.Shell").Run("program.bat", 0, True)
p = Process.GetProcessesByName("program")
If p.Count > 0 Then
WScript.Sleep(300000)
Else
CreateObject("Wscript.Shell").Run("program clean up.bat", 0, True)
End If
End Sub
Private Function WScript() As Object
Throw New NotImplementedException
End Function
End Module
I am trying to run a batch script, that starts a process, then wait until the process terminates, then run another batch script. I also do not want any command boxes being shown. If their is a easier way please let me know.
Thanks for your help
When you enclose a procedure's argument list in parentheses, you must use the Call keyword:
Call CreateObject("WScript.Shell").Run("program.bat", 0, True)
If you omit the Call keyword, you must also drop parentheses:
CreateObject("WScript.Shell").Run "program.bat", 0, True
To complete what's been said before:
When Call keyword is used to call a procedure (i.e. sub or function) the arguments must be enclosed in parentheses, except when the procedure has no arguments in which case the parentheses are optional. For example all the statements:
Call test()
Call test
Call test(1,2)
are valid, but not this one:
Call test 1
When calling a procedure without using the Call keyword, the parentheses can only be used when either the procedure has zero or one argument or the procedure has a return value (i.e. is a function) and its value is used in the same statement. For example all the statements:
test()
test(1)
test(1,2)
a = test
a = test(1,2)
a = test(test(1,2),2)
are valid, except the third one which has more than one argument. In case it's not clear, the inner call of "test" in the last statement is valid because its return value is used as an argument to another call.
Note that whenever parentheses is used in this text, it is meant to imply the possible comma-separated values as well.
Seems to me this is a VB.NET, not VBScript code.
You have Shell function in VB.NET (and other methods).
Anyway, Run returns any error code returned by the program, and if you
store that result in a variable, you can use parentheses in this case.
Dim lResult As Long
lResult = CreateObject("Wscript.Shell").Run("program.bat", 0, True)
The rest was answered by #Helen.
This question already has answers here:
VB6 pass by value and pass by reference
(2 answers)
Closed 1 year ago.
Public Sub SavePendleValues(ByVal row1 As Integer, ByVal row2 As Integer)
Calling it
For sheetrow = 2 To 15 ' number of rows to scan
SavePendleValues (sheetrow, sheetrow)
Next sheetrow
Getting error : Compile error: Syntax error
When I uncomment the line: SavePendleValues (sheetrow, sheetrow)
Everything works.
Remove the parentheses.
SavePendleValues sheetrow, sheetrow
Otherwise you are trying to pass as a first argument something in parentheses that has two variables in it, which doesn't make sense for VBA parser.
I kept getting this compile error syntax error, I copied code from here: https://learn.microsoft.com/en-us/previous-versions/office/developer/office-2007/bb206765(v=office.12)?redirectedfrom=MSDN
So the code should be good.
Then, somehow, I removed all the leading empty spaces for all lines, the error goes away!
So it seems, the vba editor is not very tolerant, it doesn't like certain invisible printing-control characters.
This question already has answers here:
What does the Call keyword do in VB6?
(5 answers)
Closed 3 years ago.
I have been copying code moslty to work on and learn macro's in Word. I have got it working where I can get a MsgBox to appear before printing, but I would like it to call another module/macro to compartmentalize the modules.
For testing, this works:
Private Sub App_DocumentBeforePrint(ByVal Doc As Document, Cancel As Boolean)
MsgBox "Before Print"
End Sub
But if I do:
Private Sub App_DocumentBeforePrint(ByVal Doc As Document, Cancel As Boolean)
Call Greeting
End Sub
Which is a working macro that I have which simple opens a MsgBox and says "Greetings", I get the following error:
Compile Error: Expected variable or procedure, not module
How can I call another Macro inside this Private Sub App*?
While this post has been covered before, I will share the answer here as well in case others land here.
The issue is that you can't have a module named the same as a sub. See Screenshot below for what is WRONG!
Interestingly, if you put the sub that calls the other sub (greeting) inside the same module (greeting) it works! But I would say this is bad practice and should be avoided. See example below:
I will generally just append _Sub to my module names to avoid this issue like below:
Also a note about using the keyword Call.
You are not required to use the Call keyword when calling a procedure.
However, if you use the Call keyword to call a procedure that requires
arguments, argumentlist must be enclosed in parentheses. If you omit
the Call keyword, you also must omit the parentheses around
argumentlist. If you use either Call syntax to call any intrinsic or
user-defined function, the function's return value is discarded.
See here for more information --> What does the Call keyword do in VB6?
This question already has an answer here:
Array argument must be ByRef
(1 answer)
Closed 6 years ago.
Given the following code:
I can not seem to successfully pass a Range Object Variable from one sub-function to another. I spent an entire day researching, and experimenting before I swallowed pride and came here.
Please read the comments below, and reply with any ideas you have regarding why the LAST two lines will not behave.
Public Sub doSomethingToRows(ROI As Range)
*'do Something with the cell values within the supplied range*
End Sub
'
Public Sub testDoAltRows()
Dim RegionOfInterest As Range 'is this an object or not?
'*The following yields: Class doesn't support Automation (Error 430)*
'*Set RegionOfInterest = New Worksheet 'this just gives an error*
Set RegionOfInterest = Worksheets("Sheet1").Range("A1")
RegionOfInterest.Value = 1234.56 '*okay, updates cell A1*
Set RegionOfInterest = Worksheets("Sheet1").Range("B5:D15")
RegionOfInterest.Columns(2).Value = "~~~~~~" '*okay*
'doSomethingToRows (RegionOfInterest) 'why do I get "OBJECT IS REQUIRED" error?
doSomethingToRows (Worksheets("Sheet1").Range("B5:C15")) 'but this executes okay
End Sub
From the msdn documentation of the Call keyword statement,
Remarks
You are not required to use the Call keyword when calling a procedure.
However, if you use the Call keyword to call a procedure that requires
arguments, argumentlist must be enclosed in parentheses. If you omit
the Call keyword, you also must omit the parentheses around
argumentlist. If you use either Call syntax to call any intrinsic or
user-defined function, the function's return value is discarded.
To pass a whole array to a procedure, use the array name followed by
empty parentheses.
From a practical standpoint, even though Subs can be called with or without the "Call" keyword, it makes sense to pick one way and stick with it as part of your coding style. I agree with Comintern - it is my opinion, based on observation of modern VBA code, that using the "Call" keyword should be considered deprecated. Instead, invoke Subs without parenthesis around the argument list.
And now the answer to the important question:
Why does your code throw an error?
Take for example the following Subroutine:
Public Sub ShowSum(arg1 As Long, arg2 As Long)
MsgBox arg1 + arg2
End Sub
We have established that, if not using the Call keyword, Subs must be invoked like so:
ShowSum 45, 37
What happens if it were instead called like ShowSum(45, 37)? Well, you wouldn't even be able to compile as VBA immediately complains "Expected =". This is because the VBA parser sees the parenthesis and decides that this must be a Function call, and it therefore expects you to be handling the return value with an "=" assignment statement.
What about a Sub with only one argument? For example:
Public Sub ShowNum(arg1 As Long)
MsgBox arg1
End Sub
The correct way to call this Sub is ShowNum 45. But what if you typed this into the VBA IDE: ShowNum(45)? As soon as you move the cursor off of the line, you'll notice that VBA adds a space between the Sub name and the opening parenthesis, giving you a crucial clue as to how the line of code is actually being interpreted:
ShowNum (45)
VBA is not treating those parenthesis as if they surrounded the argument list - it is instead treating them as grouping parenthesis. MOST of the time, this wouldn't matter, but it does in the case of Objects which have a default member.
To see the problem this causes, try running the following:
Dim v As Variant
Set v = Range("A1")
Set v = (Range("A1")) '<--- type mismatch here
Notice that you get a "Type Mismatch" on the marked line. Now add those two statements to the watch window and look at the "Type" column:
+-------------+-----+--------------+
| Expression |Value| Type |
+-------------+-----+--------------+
|Range("A1") | |Object/Range |
|(Range("A1"))| |Variant/String|
+-------------+-----+--------------+
When you surround an Object with grouping parenthesis, its default property is evaluated - in the case of the Range object, it is the Value property.
So it's really just a coincidence that VBA allowed you to get away with "putting parenthesis around the argumentlist" - really, VBA just interprets this as grouping parenthesis and evaluates the value accordingly. You can see by trying the same thing on a Sub with multiple parameters that it is invalid in VBA to invoke a Sub with parenthesis around the argument list.
#PaulG
Try this:
Public Sub Main()
Debug.Print TypeName(Range("A1"))
Debug.Print TypeName((Range("A1")))
End Sub
okay, I knew after I posted this question I'd be struck by lighting and receive an answer.
When passing an object VARIABLE to a sub-function and wishing to use parentheses "()", one must use CALL! Thus the correction to my code sample is:
**CALL doSomethingToRows(RegionOfInterest)**
Thank you!
Maybe we're talking about different things, but here's an example to make it a bit clearer what I mean.
Option Explicit
Sub TestDisplay()
Dim r As Range
'Create some range object
Set r = Range("A1")
'Invoke with Call.
Call DisplaySomething(r)
'Invoke without Call.
DisplaySomething r
End Sub
Sub DisplaySomething(ByVal Data As Range)
Debug.Print "Hi my type is " & TypeName(Data)
End Sub
Both calls work perfectly. One with Call and the other without.
Edit:
#Conintern. Thanks for explaining that. I see what is meant now.
However, I still respectively disagree.
If I declare the following:
Function DisplaySomething(ByVal Data As String)
DisplaySomething = "Hi my type is " & TypeName(Data)
End Function
and invoke it:
Debug.print DisplaySomething(Range("A1"))
I believe that Excel has been clever and converted to a string. It can do that by invoking the Default Parameter and can convert to a string.
However, as in the original parameter example, If I declare the following:
Function DisplaySomething(ByVal Data As Range)
DisplaySomething = "Hi my type is " & TypeName(Data)
End Function
There is no call on the Default Parameter, however it is called, because Excel was able to resolve it to that type.
Function DisplaySomething(ByVal Data As Double)
DisplaySomething = "Hi my type is " & TypeName(Data)
End Function
will return a double because it was able to coerce to a double.
Indeed in those examples the Default was called.
But in this example we are defining as Range. No Default called there however it is invoked - brackets or no brackets.
I believe this is more to do with Excel and data coercion.
Similar to the following:
Public Function Test(ByVal i As String) As Integer
Test = i
End Function
and invoking with:
Debug.print Test("1")
BTW, yes I know this isn't an object without a Default parmeter. Im pointing out data coercion. Excel does its best to resolve it.
Could be wrong mind you...
This question already has answers here:
VBA does not accept my method calling and gives Compile error: Syntax error [duplicate]
(2 answers)
Closed 7 years ago.
I tried to create procedure that passes 2 arguments, mandatory and optional, before I added optional argument procedure was running correctly. Here is Code:
Sub a2(var As String, Optional num As Integer = 5)
MsgBox (num)
End Sub
Sub start_a2()
a2 ("null_text", 5)
End Sub
When I pass any second argument, running procedure start_a2 fails at 1st line: Sub start_a2(), VBA higlight this line with Yellow and returns Syntax error, but do not provide any details. Second argument is inproperely passed?
Does it work if you use Call? Such as
Sub start_a2()
Call a2("null_text", 5)
End Sub
Edit: Though the above will work, #SO's comment below is right on (Thanks!); you can just use
Sub start_a2()
a2 "null_text", 5
End Sub