3

Consider the following code in a VBA module called Module1:

Sub StartTest()
    Dim frm As UserForm1
    Set frm = New UserForm1
    frm.Show
End Sub

Sub Notify(fromForm As UserForm1)
    MsgBox "Notified."
End Sub

And the following code in UserForm1:

Private Sub CommandButton1_Click()
    Module1.Notify (Me)
End Sub

When I run StartTest the form appears, and when I click the button, I'm getting a "Type mismatch" error on Module1.Notify (Me) in the CommandButton1_Click() sub. Why?

If I change Module1.Notify (Me) to Call Module1.Notify(Me) (thanks @sous2817 for pointing this out) or to Module1.Notify Me, then I don't get the error. So why does it happen when I use Module1.Notify (Me)?

rory.ap
  • 34,009
  • 10
  • 83
  • 174
  • remove brackets: `Module1.Notify Me`. Also this might be interesting: [What is the difference between entering parameters in these four different ways?](http://stackoverflow.com/questions/23511707/what-is-the-difference-between-entering-parameters-in-these-four-different-ways/23512287#23512287) – Dmitry Pavliv Jun 18 '14 at 15:43

1 Answers1

3

Change your button code to this:

Private Sub CommandButton1_Click()
    Call Module1.Notify(Me)
End Sub

Seems to give the expected results on my end...

As for the "why", reference here: http://msdn.microsoft.com/en-us/library/wcx04ck5(VS.85).aspx

Specifically:

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 use either Call syntax to call any intrinsic or user-defined function, the function's return value is discarded.

I don't think you can get more of an authoritative explanation than this: http://blogs.msdn.com/b/ericlippert/archive/2003/09/15/52996.aspx

sous2817
  • 3,915
  • 2
  • 33
  • 34
  • Thanks a lot! Your code modification works. However, I think the article you referenced and the excerpt don't quite explain this situation. It doesn't say anything about different behavior when you *don't* use `Call` yet have arguments in parens. I've discovered, for instance, that I can also avoid the error I was getting by changing my code to `Module1.Notify Me`, i.e. without enclosing the argument in parens. At the risk of coming across as pedantic, I'd like to ask that you address this peculiarity in your answer before I accept it. – rory.ap Jun 18 '14 at 15:13
  • In other words, if you can find another article that explains the above-mentioned peculiarity, use that instead of what you referenced/excerpted. – rory.ap Jun 18 '14 at 15:13
  • I wish I had a better answer, but it seems to be a design choice by the original VB6 authors. If you use Call, you have to enclose your arguments in (), if you omit the Call, you can omit the ()...I can flood you with other stackoverflow links that have the same explanation (http://stackoverflow.com/questions/479891/what-does-the-call-keyword-do-in-vb6 and http://stackoverflow.com/questions/7715044/calling-a-sub-in-vba). Does that help? – sous2817 Jun 18 '14 at 15:20
  • It's just that, while I appreciate you helping me get past the error, my question is *why* does it happen. The MSDN article doesn't say "if you don't use Call but you have arguments in parens, you could get a Type Mismatch error, and here's the reason why..." You follow me? – rory.ap Jun 18 '14 at 15:25
  • Sure, no one is saying that the MSDN documentation is perfect, but it seems to be the authority. If you look at this link http://stackoverflow.com/questions/479891/what-does-the-call-keyword-do-in-vb6 you'll see examples and if / when they generate errors. I can copy and paste that in to my answer if you'd like. Sometimes it's less of a headache when looking for the "why" to just accept "that's the way it is". – sous2817 Jun 18 '14 at 15:29
  • @roryap Added a blog post by Eric Lippert that gives a better "why" explanation. – sous2817 Jun 18 '14 at 15:33
  • I was actually just reading that, and I found the answer. See: "4) Pass an argument which would normally be byref as byval: Result = MyFunction(Arg1, (Arg2)) ' Arg1 is passed byref, arg2 is passed byval" and "In fact it is a subroutine call with no parens around the arg list, but parens around the first argument! This passes the argument by value." – rory.ap Jun 18 '14 at 15:41
  • So the reason I'm getting "Type mismatch" is because you *can't* pass an object as 'ByVal'. – rory.ap Jun 18 '14 at 15:43
  • Great! Glad I could lead you down the path of enlightenment :) Honestly, I had no idea as to the "why" before you pressed me for an answer, so thank you for that. – sous2817 Jun 18 '14 at 15:48
  • Thanks again for leading me down that path! – rory.ap Jun 18 '14 at 16:04
  • +1 My favorite discussion off this is: http://dailydoseofexcel.com/archives/2012/05/01/quick-vba-tip-parentheses/ – Doug Glancy Jun 18 '14 at 17:03
  • 1
    @DougGlancy -- Wow, this is so amazing. I've been using VBA for 12 years and I've never known any of this. I find it incredibly interesting to have all these esoteric details of VBA expounded after having been blissfully ignorant of them for so long. – rory.ap Jun 18 '14 at 17:41