Passing a Control as Parameter

shamas21

Registered User.
Local time
Today, 02:19
Joined
May 27, 2008
Messages
162
What I am trying to do is I am trying to be able to have a control supplied to a sub which then makes changes to the control

At the moment I have something like this

Code:
Public Sub updateListBox(ByVal lstbox As ListBox)
'Stuff to lstbox is carried out here
End Sub

What I am struggling with is that I am trying to supply the ListBox as a parameter like this

Code:
updateListBox(me.List1)


And this is coming up with the following error

Code:
Run-time error '424':

Object required

I was wondering whether anyone knows how I should be supplying the control as a parameter.

Any Ideas?

Thanks
 
Should work but note that Listboxes are objects and hence can only be passed ByRef.
 
Should work but note that Listboxes are objects and hence can only be passed ByRef.

Hi - I found the solution, I have to use the Call before the method

Code:
   Call updateListBox(me.List1)

Thanks
 
Last edited:
I guess there is sometimes a rush to get something working but we can take a little time with code.

When we write something like:-

updateListBox(me.List1)

we have the time to ask ourselves; why did I type the parentheses, what do they do?
Then we can experiment a little and remove them.
When we find out it works without them we can then ask ourselves; why does the extra junk prevent it from working?
It also stops other extra junk from being required to stop the needless junk from interfering.

So we don’t need the parentheses and we don’t need the Call to fix it.
That then stops us forming a wrong opinion as in “I have to use the Call before the method”... because you don’t.

An object, such as a lint box, must be passed by reference (ByRef) and the parentheses were attempting to force it being passed by value (ByVal), the parentheses are trying to evaluate the object, and we can’t do that with objects.

But the compiler will force the ByVal to ByRef for us at the receiving end so that is sort of okay. But only sort of okay. If we mean to receive ByRef then we should type ByRef and not ByVal.

Next we go back to the line of code:-
updateListBox(me.List1)

That is not what is in the editor and it in part hides the error.
What was in the editor is:-
updateListBox (Me.List1)
and there are two differences.

The first is that me has been shifted to proper case as in Me.
The second is that there is a space between updateListBox and the opening bracket.
That space should, in the future, give a hint as to what is happening. The parentheses are not simply enclosing an argument being passed they are attempting to force an evaluation.

This all leads to something else; we should not try to type code directly to site, copy/paste it.

Chris.
 
Hi - I found the solution, I have to use the Call before the method

If you drop the brackets around the argument you will also be able to drop the Call keyword.

There are two different syntaxes used to call Subs and the use of brackets is common syntactical misunderstanding.

The Call keyword is a somewhat deprecated syntax that requires brackets around the argument list. The newer syntax without Call simply uses the Sub name and no brackets.

Whether with or without Call, brackets used around an individual argument have a completely different meaning. They force the argument to be submitted ByVal even if the argument is declared in the Sub as ByRef, (or undeclared since the VBA default is ByRef.)

Consequently, without Call, the brackets are actually forcing the argument to be interpreted ByVal.

I cannot replicate the error you describe in Access 2007. Maybe it is not handled so well in earlier versions?

Just a guess but since objects can only be passed ByRef, maybe forcing the ByVal has the compiler assuming the argument cannot be an Object, hence the conflict with the argument typed as an Object causing the bewildering "Object Required" error.
 
it is worth taking the time to understand the above two posts. ChrisO in particular is very precise and accurate in terminology. The point he makes about actually posting the real code, rather than a possibly slightly mistyped variant of it is well made.

We often see similar issues when posters ask for help on error messages, but don't actually repeat the exact error message they received.

Out of interest, I tend to use the call syntax with brackets, as I find it more readable. I didn't appreciate the point that Galaxiom is making, that this changes parameters from byref to byval. That doesn't bother me too much, as I only very rarely need a byref parameter - but I will certainly recall this advice when I do need one!
 
The ‘bewildering "Object Required" error’ comes from the compiler ‘knowing’ that an object is required because of:-

Public Sub updateListBox(ByVal lstbox As ListBox)

So, in effect, the compiler is looking at the ‘As ListBox’ and then at the parentheses and saying “I can’t evaluate this passed argument because an Object is Required”.

Chris.
 
I tend to use the call syntax with brackets, as I find it more readable. I didn't appreciate the point that Galaxiom is making, that this changes parameters from byref to byval.

It only changes to ByVal without the Call. In the first and second of the following lines, the argument will be submitted ByRef. The third and fourth ByVal.

Code:
Call MySub (MyArgument)
MySub MyArgument
 
Call MySub ((MyArgument))
MySub (MyArgument)
 
Last edited:
And that's what I mean by NOT typing code directly to site.
Note the spacing...
Code:
Sub TestIt()
    Dim MyArgument
    
[color=green]'   Call MySub (MyArgument)     ' << incorrect.[/color]
    Call MySub(MyArgument)      [color=green]' << correct.[/color]
    MySub MyArgument            [color=green]' << correct.[/color]

[color=green]'   Call MySub ((MyArgument))   ' << incorrect.[/color]
    Call MySub((MyArgument))    [color=green]' << correct.[/color]
    MySub (MyArgument)          [color=green]' << correct.[/color]
    
End Sub


Sub MySub(vntArgument)
    MsgBox "I got here."
End Sub
The space is a hint as to what's actually going on.

Chris.
 
The ‘bewildering "Object Required" error’ comes from the compiler ‘knowing’ that an object is required because of:-

Public Sub updateListBox(ByVal lstbox As ListBox)

So, in effect, the compiler is looking at the ‘As ListBox’ and then at the parentheses and saying “I can’t evaluate this passed argument because an Object is Required”. .

Yes. That is basically what I indicated. I meant bewildering in the sense of how it would appear to someone who did not realise what the brackets were doing.
 
Admittedly “Object required (Error 424)”, even with the error number, is misleading and is not well documented.

The real point I’m trying to get across is that it would not take much time to edit the calling line to see what happens and that’s where the debug stops, on the calling line.

So if we have:-
updateListBox (Me.List1)

it really doesn’t take much time to try:-
updateListBox Me.List1

So it’s just a matter of looking at the line and asking; what is that junk doing there, why did I type it?
The inevitable answer is; the compiler and I disagree and the compiler will win the argument.

So we check our spelling, we trash what’s not required and it works. We can add stuff to get it to work but adding stuff really only masks the original problem and may cause us to form misconceptions.

Code is really complicated enough without having extraneous junk lying around.

Chris.
 
I looked into why I had not been able to replicate the original error and found something quite interesting. The brackets only cause an evaluation where the control is referred to as:
Code:
Me.controlname
Me!controlname
Forms!formname!controlname

However, as I had done in my test, referring to the control with a dot reference (ie as a defacto Property of the form) via the Forms collection does NOT cause an evaluation and the object itself is passed regardless of the brackets in the calling line.
Code:
Forms!formname.controlname

When used with this reference, the evaluation of an argument is caused only by the Typing of the argument variable in the Sub declaration. Where the argument is Typed as an Object (or Variant), that is what is passed regardless of the brackets around the argument in the calling line.

Clearly the effect of the brackets is not universally causing the expression to be evaluated in the usual sense because "evaluation" does return the Value property of the control.

Code:
Eval("Forms!formname.controlname")

(Yet another place where the dot and bang are subtlely different.)
 
Please post the exact code of the two instances, the one which works and the one which fails.

Chris.
 
So it’s just a matter of looking at the line and asking; what is that junk doing there, why did I type it?

I don't think it is that simple.

The similarity between Subs and Functions is the main source of the confusion. A Function can be used exactly like a Sub if a return value is not required. Indeed without being equated to something, the Function IS apparently treated EXACTLY as a Sub. This similarity often leads to the use of brackets with Subs by those who don't realise the true meaning of brackets when used without Call.

They have also probably seen some example Subs where Call is used, (of course with brackets), further suggesting brackets are supposed to be used with Subs. They might resaonably consider the Call keyword is simply optional.

The big difference is that the arguments of a function must be enclosed in brackets if a return value is required.

With a Function, the use of the return value makes the two lines below have a different effect with regard to the submission of the arguments. Without the equation, the brackets indicate the expression is to be enumerated just as it does in a Sub.
Code:
x = MyFunction(expression)
MyFunction (expression)

The difference becomes apparent when the brackets raise a syntax error when enclosing more than one argument in a Sub without using the Call keyword.

I suspect most developers use simple variables and references to control values as arguments long before they try passing a control as an object. The brackets don't cause a problem until they try to pass the object.

Even then if they happend to use the reference syntax I mentioned above, Forms.formname.controlname then they will continue to be unaware of the real effect of brackets because the brackets have no effect on that expression.

Then they use Me.whatever and get an unexpected error. Unfortunately it goes against not just one but several of the impressions they may have developed about the use of brackets.

A database demonstrating the difference in behaviour of the brackets with different control reference syntaxes is attached.
 

Attachments

Thanks GalaxiomAtHome, a very interesting demo.

Now comes the fun part; can we make some statements and put them up for critique?

1.
Forms!Form1!Text0
The compiler rejects it because it regards it purely an Object.
The Object can not be evaluated.

2.
Forms!Form1.Text0
The compiler can regard it either as an Object or Property.
The Object can not be evaluated.
The Property can be evaluated.

Assumptions for critique if both 1 and 2 are correct…
a. The compiler sees the bang and rejects it outright as an Object.
b. The compiler sees the dot and tries to evaluate the Property and succeeds.

Then the questions; is both a and b true and, more importantly, how do we prove it?
(Proof as in the form of code like your demo.)

Chris.
 
Well, b is not true…

(Me.Text0) fails and (Forms!Form1.Text0) works.

Code:
Private Sub Button0_Click()

    MySub (Me.Text0)

End Sub

Private Sub Button1_Click()

    MySub (Forms!Form1.Text0)

End Sub

More to do tomorrow (later today),
Chris.
 
I can’t see any rhyme, reason or logic as to why some syntax work and others don’t.

They all work without the parentheses so…don’t use parentheses around Objects.

Chris.
 

Users who are viewing this thread

Back
Top Bottom