Search code examples
vbacomvb6user-defined-types

Can UDT's be used as method parameters in any way?


For years I've been avoiding the use of Public Type UDT's in VBA, because they're hard to pass around and I never really bothered trying to understand why.. until now - it was simply easier to just create a class module and work with actual objects instead.

But recently I gave it a shot, and once I figured they had to be passed ByRef (as an array would), things started to look like I could start using them.

So I defined a Public Type in a standard module, got this compile error:

Only public UDT's defined in a public object module can be used as a parameter for public procedures of class modules

So I moved the Public Type into a class module, made the class PublicNotCreatable, and then got this compile error:

Cannot define a public UDT in a class module


Here's some code to reproduce the compile error.

Class module "Something":

Option Explicit
' cannot define a public user-defined type within an object module
Public Type TSomething
    Foo As Integer
End Type

Public Function Create(ByRef info As TSomething) As Something
End Function

If you move the definition of TSomething to a standard module, you'll get the other compiler error, telling you that the public UDT must be defined in a public object module (i.e. a class module)... which takes you back to square one.


So if you cannot define a Public Type in a class module, why would the compiler throw a fit and even mention "public user defined types defined in public object modules" if such a thing can't legally exist?

Did it work in VB6 and the compiler message is a remnant of that version? Or is the reason somewhere in how COM works? Is it just me or the two error messages are contradicting each other? Or there's something I'm not understanding?

Obviously I'm misusing/abusing UDT's here. So what are they supposed to be used for, if not for passing a "record" to some method?


Solution

  • From standard module it works without any error. Following code threw no error.

    Public Type TEST_TYPE
        Prop1   As String
    End Type
    
    Public Function fTest(ByRef param1 As TEST_TYPE) As String
        param1.Prop1 = "Hello from function"
    End Function
    
    Public Sub sTest(ByRef param1 As TEST_TYPE)
        param1.Prop1 = "Hello from Sub"
    End Sub
    
    Public Sub caller()
    
        Dim p   As TEST_TYPE
    
        '/Call Sub
        Call sTest(p)
    
        MsgBox p.Prop1
    
        '/Call Function
        Call fTest(p)
    
        MsgBox p.Prop1
    
    End Sub
    

    One issue with UDT is about Forward referencing. So this will not compile, apart from that It works perfectly fine with standard modules.

    Public Type TEST_TYPE
        Prop1   As String
        Prop2   As TEST_TYPE2 '/ Fails due to Forward referencing. TEST_TYPE2 should be declared before this UDT.
    End Type
    
    Public Type TEST_TYPE2
        Prop3   As String
    End Type
    

    Edit:

    However, the work around to use the UDT in class is Friend

    VBA Code for Class

    '/ Using UDT in VBA-Class
    Private Type TEST_TYPE3
        Prop3   As String
    End Type
    
    Public Sub caller()
    
        Dim p As TEST_TYPE3
        p.Prop3 = "Hello from Class"
        Call testClassUDT(p)
    
    End Sub
    
    Friend Sub testClassUDT(p As TEST_TYPE3)
        MsgBox p.Prop3
    End Sub