Results 1 to 20 of 20

Thread: Why do I keep getting this error?

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    Why do I keep getting this error?

    I'm trying to recursively use a user defined type.
    My first attempt was
    Code:
    Private Type testtype
        t As testtype
        b As Byte
    End Type
    but that didn't work because you can't use something's own type in its own definition.

    Then I tried
    Code:
    Private Type testtype
        v As Variant
        b As Byte
    End Type
    and VB6 allowed that so I then went on to this code to test it.
    Code:
    Private Sub Form_Load()
    Dim a As testtype
    Dim a2 As testtype
    a.v = a2
    End Sub
    But that gave the error:
    "only user-defined types defined in public object modules can be coerced to or from a variant passed to late-bound functions"



    That was the clue I needed, so then I just took the type definition code, changed it to public and put it in a "module" like this so as to fullfill the "public object module" requirement mentioned in the error message.
    Code:
    Public Type testtype
        v As Variant
        b As Byte
    End Type
    I then again used this code in my form.
    Code:
    Private Sub Form_Load()
    Dim a As testtype
    Dim a2 As testtype
    a.v = a2
    End Sub
    But I still get the error message:
    "only user-defined types defined in public object modules can be coerced to or from a variant passed to late-bound functions"

    There appears to be no way to do what I'm trying to do. I am trying to get the ability to recursively use User Defined Types so that I can use them as nodes in a tree, specifically a huffman tree, so I can write my own huffman compression algorithm. But whenever I try to use UDTs recursively, VB keeps standing in my way! I'm pretty sure any other programming language could accomplish this, though none are as easy to use as VB. ARGH!!!!!!!!!!!!

  2. #2
    Lively Member
    Join Date
    Oct 2013
    Posts
    124

    Re: Why do I keep getting this error?

    I played around with Huffman encoding for a while, maybe 15 years ag, and I know I never had to do anything like that. That just doesn't look right.

    You might save yourself a lot of time and frustration by looking at some of the source code available for building tree structures. I'm just about to get started reading a book that has a number of examples of creating trees in legacy VB, so I'm afraid I can't help you yet.
    AMD FX-4300, WinXPSP3, VB6SP6

  3. #3
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    14,205

    Re: Why do I keep getting this error?

    Code:
    Private Sub Form_Load()
    Dim a As testtype
    Dim a2 As testtype
    a.v = a2
    End Sub
    You are trying to set an element of a UDT= a UDT

    You can create an Array of a UDT
    You may even be able to define an element of a second UDT as a different UDT
    You can use a class with properties instead of a UDT

    In any case your definition is a UDT with the fields then you try to set one of those fields= the UDT but it is not expecting a UDT it is expecting a value

    This of course would work but not what your are trying to do
    Code:
    a.v = a2.v

  4. #4
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Why do I keep getting this error?

    I'm pretty sure that having a UDT type contain a field that is the UDT itself should be impossible.
    UDTs are not classes, so are not a reference type that can be set to Nothing.
    When you create a UDT variable, the storage for the UDT is allocated immediately, it doesn't have to be instantiated, like a class.
    So, if a UDT reference its own type, then the UDT field would have to be allocated, which contains the UDT, which has to be allocated, recursively until you run out of memory.

    So, as DataMiser has already said, if you want to implement a recursive structure, it will have to be a Class, not a UDT.

  5. #5
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Why do I keep getting this error?

    Quote Originally Posted by Ben321 View Post
    But I still get the error message:
    "only user-defined types defined in public object modules can be coerced to or from a variant passed to late-bound functions"
    Read the message more closely:

    only user-defined types defined in public object modules can be coerced to or from a variant passed to late-bound functions
    This is talking about Forms, UserControls, Classes, and the like where the Instancing property is greater than 1 (Private), i.e. modules that publish an interface. This module property is hidden in the IDE for a Standard EXE project because it can't be changed from Private anyway.

    A static module (.bas) cannot be published in a VB6 project of any type so that's useless as a solution.


    Basically this is telling you that what you are trying to do is better accomplished by using classes instead of UDTs.

    While a private (as in unpublished) UDT can be a lightweight thing meeting a few specific needs (stand-in for a struct in an API call, use of creaky old VB Random files, and a few other things) they are obsolete in most respects. A published UDT (i.e. those defined in a DLL, OCX, ActiveX project) has a huge amount of plumbing attached to it, turning it into a rather heavyweight specialized kind of class.

  6. #6
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Why do I keep getting this error?

    Quote Originally Posted by dilettante View Post
    While a private (as in unpublished) UDT can be a lightweight thing meeting a few specific needs (stand-in for a struct in an API call, use of creaky old VB Random files, and a few other things) they are obsolete in most respects. A published UDT (i.e. those defined in a DLL, OCX, ActiveX project) has a huge amount of plumbing attached to it, turning it into a rather heavyweight specialized kind of class.
    It is true that a published UDT has a bit of "plumbing" attached to it (in a way...when we talk about Variants or Dispatch-(LateBound-)Calls)...

    Though such a class-defined Public UDT (*.tlb-Defs would work too) is not larger "mem-allocation-wise" -
    meaning, you can pass variables of such types into API-functions without any difference to "normally
    defined UDTs".
    Also performance-wise (e.g. when you use a larger array of such an UDT-def) there's no difference.

    The difference is, that as soon as you assign (copy) such a public defined UDT into a Variant (and back) -
    which works without problems - VB (or COM-OleAut) assigns not only a pointer to the allocated
    memory for the "plain udt-copy" into Variant-Offset 8 (same position as with other Variant-PointerMembers)...
    what's different from other pointer-types is, that 4 Bytes *after* that (at Offset 12 in the Variant),
    a pointer to a COM-Class-instance which implements IRecordInfo is placed (describing the UDT-
    members with their names and sizes, and it is also responsible for copying etc.).

    This IRecordInfo-instance is only created *once* per Type (even when you fill a lot of different
    Variant-Variables with a lot of your UDT-allocations):

    In a Public Class of an ActiveX-Dll-Project (which was added as part of a ProjectGroup)
    Code:
    Option Explicit
    
    Public Type TestType
      V As Variant
      B As Byte
    End Type
    In a TestForm within the StdExe-Project (our first member in the ProjectGroup, needs a reference to 'Project2' above)
    Code:
    Option Explicit
    
    Private Declare Sub RtlMoveMemory Lib "kernel32" (Dst As Any, Src As Any, ByVal Bytes&)
    
    Private Sub Form_Load()
    Dim a0 As TestType, a1 As TestType, a2 As TestType
      
      Debug.Print LenB(a0) '<- prints 20
      
      Debug.Print TypeName(a0.V), VarType(a0.V) '<- prints 'Empty', 0
      a1.B = 1
      a0.V = a1
      Debug.Print TypeName(a0.V), VarType(a0.V) '<- prints 'TestType', 36 = vbUserDefinedType
      
      a2.B = 2
      a1.V = a2
      a0.V.V = a2
      Debug.Print a0.B, a1.B, a2.B
      Debug.Print a0.B, a0.V.B, a0.V.V.B
      
      'the IRecordInfo-instance is re-used (always the same Pointer in the different Variants)
      TestIRecordInfoPtr a0.V
      TestIRecordInfoPtr a0.V.V
      TestIRecordInfoPtr a1.V
    End Sub
    
    Private Sub TestIRecordInfoPtr(ByVal V)
    Dim pIRecInfo As Long
      RtlMoveMemory pIRecInfo, ByVal VarPtr(V) + 12, 4
      Debug.Print pIRecInfo
    End Sub
    To get a better picture about the behaviour and inner workings of this mechanism -
    I've implemented a light-weight-COM version of IRecordInfo in a *.bas module some time ago,
    which allows to avoid an external COM-Dll or TypeLib (the UDTs become Variant-wrappable
    then within a normal StdExe-project, using the *.bas-Module implemented IRecordInfo-
    wrapper.

    Here's the thread (in a german forum, but the comments in the code-modules are in english).
    http://foren.activevb.de/archiv/vb-c...GetFieldNames/

    Olaf
    Last edited by Schmidt; Apr 7th, 2014 at 02:03 AM.

  7. #7
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Why do I keep getting this error?

    The cost comes from when IRecordInfo gets used at run time for reading or writing each member of the UDT. It is true this only occurs when such UDT values get used in Variants:

    You only need to use IRecordInfo to pass a UDT by reference that is stored in a VARIANT. If the UDT is not stored in a VARIANT you can pass a pointer to the UDT because an IRecordInfo pointer can be retrieved from the UDT type description.

    IRecordInfo is used to get the amount of storage needed for a UDT, clear the storage for a UDT, copy or access the fields in a UDT. However, the layout of a UDT is the same as the layout of structures in C++, therefore you may not have to use IRecordInfo for clearing, copying and accessing the fields of the storage.
    As long as the IRecordInfo is available to the compiler (early binding) the overhead is optimized away. When Variant copies are used this optimization doesn't apply and "interpretive" calls into IRecordInfo methods passing field names must be made by the generated code.


    But to create hierarchies (from simple lists, to trees, or generalized DOM-like structures) you may as well use VB Classes and be done with it.

  8. #8

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    Re: Why do I keep getting this error?

    A variant SHOULD be able to be set to ANYTHING, including a UDT, so having a UDT with a Variant field, should allow you to at runtime stick a variable of even the same UDT type in there. But it doesn't. It gives me that stupid crap about latebound bla bla bla instead.

  9. #9
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    14,205

    Re: Why do I keep getting this error?

    A UDT is a single object. It is not multi instance.

    You can not set an object in any UDT to the UDT itself.

    You need to use a class that can be multi instance or use an array of the UDT. What you are trying to do will not work and there really is no need to do it that way.

    On second look you don't even need a UDT You only have two items there and one is trying to point back to itself so you really only have 1 and that is a byte. Seems like a Byte array is what you need here
    Last edited by DataMiser; Apr 8th, 2014 at 01:08 PM.

  10. #10
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Why do I keep getting this error?

    Quote Originally Posted by Ben321 View Post
    ... I'm pretty sure any other programming language could accomplish this, though none are as easy to use as VB. ARGH!!!!!!!!!!!!
    I'm pretty sure any other programming language wouldn't support using a value type in such a manner. Almost every example of nodes in lists or trees, etc will use a reference type so you can embed pointers to the objects that make up the nodes.
    By trying to use a variant, you're trying to provide a "reference" mechanism to the UDT. You can see the effort needed to make such a thing work, based on the previous posts.
    Why the resistance to using a Class instead of a UDT, when most every example of nodes in any language would use a class, or pointers to dynamically allocated memory in languages that don't have classes?
    If you willing to use a UDT, then you wouldn't have to implement the properties "properly", you could just make them public and access them directly.
    So the class in your example would simply be (using the default name Class1):
    Code:
    Option Explicit
    
    Public t As Class1
    Public b As Byte
    And the example test
    Code:
    Option Explicit
    
    Private Sub Form_Load()
      Dim a As New Class1
      Dim a2 As New Class1
      Set a.t = a2
    End Sub
    It's not that much extra effort, although I'm sure some would say that is not a good or correct way to use a class...

    I have used UDTs to implement trees, but in those cases I had known size limits that I wouldn't exceed so could create an array of the maximum UDTs I would allow, and use the array as a pool of UDTs to "allocate" from, and have Integer (or Long) fields in the UDT to server as pointers (i.e. the array index) to create linked lists, doubly linked lists, or binary tree nodes from.
    It works fine and is quick, but is not suited for unknown dynamic allocation, generally.

  11. #11

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    Re: Why do I keep getting this error?

    Quote Originally Posted by passel View Post
    I'm pretty sure any other programming language wouldn't support using a value type in such a manner. Almost every example of nodes in lists or trees, etc will use a reference type so you can embed pointers to the objects that make up the nodes.
    By trying to use a variant, you're trying to provide a "reference" mechanism to the UDT. You can see the effort needed to make such a thing work, based on the previous posts.
    Why the resistance to using a Class instead of a UDT, when most every example of nodes in any language would use a class, or pointers to dynamically allocated memory in languages that don't have classes?
    If you willing to use a UDT, then you wouldn't have to implement the properties "properly", you could just make them public and access them directly.
    So the class in your example would simply be (using the default name Class1):
    Code:
    Option Explicit
    
    Public t As Class1
    Public b As Byte
    And the example test
    Code:
    Option Explicit
    
    Private Sub Form_Load()
      Dim a As New Class1
      Dim a2 As New Class1
      Set a.t = a2
    End Sub
    It's not that much extra effort, although I'm sure some would say that is not a good or correct way to use a class...

    I have used UDTs to implement trees, but in those cases I had known size limits that I wouldn't exceed so could create an array of the maximum UDTs I would allow, and use the array as a pool of UDTs to "allocate" from, and have Integer (or Long) fields in the UDT to server as pointers (i.e. the array index) to create linked lists, doubly linked lists, or binary tree nodes from.
    It works fine and is quick, but is not suited for unknown dynamic allocation, generally.

    What is the trick to getting it to work using a Variant in a UDT? You say it's not easy, but that means you must know how to do it. Please let me in on the secret that you seem to know.

  12. #12
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,532

    Re: Why do I keep getting this error?

    I don't see in there anywhere where Passel said it was possible. Personally I wouldn't use an UDT in this case... A class seems much more appropriate for this case.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  13. #13
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Why do I keep getting this error?

    Schmidt in post #6 covered what it would take, and you can refer to dilettante's posts before and after that for additional discussion.
    Bottom line, you would have to publish the UDT as part of something, like an ActiveX Dll.
    At the end post #6 Schmidt points to an example that creates a "light weight" COM object to implement the necessary published interface, without requiring an external Dll or type lib, and allows the UDT to be wrapped in a variant (because the published interface requirement is met).
    By doing that, you essentially coerce the UDT into a reference type (the Variant being the reference holder), but that seems like so much work and effort to turn a UDT into a quasi class object, when you could just use a simple class to start with. I find it hard to imagine that there would be any speed advantage to wrapping the UDT into a variant as opposed to using a class, so seems like an unnecessary complication to me.

    You mentioned a Huffman tree, and I guess if I wanted to use UDTs and a worse case number of nodes needed can be determined, I would just create an array of them in a pool, as I stated before, and use the index of where the UDT is in the array as the pointers to link them.
    I know I did something similar as a possible coding competition entry years ago to try to quickly determine the frequency of words in a novel, but the competition never came about. That was done in VB6 but I would have to track the code down, it isn't on this machine.
    Don't know if you care to see it. I know in the initial version I didn't try to balance the tree in any way.
    I later tried to modify it in several ways, to try to add some measure of balancing, but in the case of a short novel, a little over 100,000 words, the overhead of the checks for balancing either slowed the process down, or didn't make enough of a speed difference to be worth the effort.

  14. #14
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Why do I keep getting this error?

    Quote Originally Posted by passel View Post
    Schmidt in post #6 covered what it would take, ...
    Yep, and it isn't much what is needed, to cover the requirements of the OP, just this simple code in a Public Class of an AX-Dll:
    Code:
    Public Type TestType
      V As Variant
      B As Byte
    End Type
    what the OP would need after compiling that simple snippet (which contains only an interface-description),
    is to just reference this compiled (Typelib-like) Dll in his Main-App.

    After that he can stuff these TypeLib-defined UDTs into Variants as he originally intended.

    Nothing complicated at all with that approach.
    And to DataMiser and techgnome - it is entirely possible and reliable to work this way
    with UDTs (stuffing them into Variants). It is just not practised - but that's more due
    to the simple reason, that many VBers don't like to work with ActiveX-Dlls.

    This approach would also be (much) more lightweight in terms of memory (compared with the
    otherwise recommended Class-based approaches).

    *But* it would require to work LateBound "through" the Variant-Wrappers of these
    (nested) UDT-definitions.

    And that would cost performance, compared with the class-based approach.

    So, a classbased approach would be faster (as long as no larger byte-content
    in the Megabyte-Range gets huffman-encoded) - whereas the Variant+UDT
    nesting-approach would need less memory (a VB-Class-Instance needs ~110Bytes -
    a Variant as the "outer hull" would take up only 16Bytes).

    So, both approaches are not optimal - and need to be avoided in a decent implementation.

    There's much easier (and faster) ways to accomplish performant tree-structures in VB6...
    as passel already pointed out, the simplest way to do it would be, to exchange the
    "reference-type" in the UDT with an Index-member (a VB-Long for example) - and
    use that Long to "refer" (by Index) into another allocation which then can be taken
    up in contiguous memory in larger block-reallocates (as e.g. in a "linear" array, or "vector")
    instead of a bunch of isolated, separated smaller ones.

    Quote Originally Posted by passel View Post
    You mentioned a Huffman tree, and I guess if I wanted to use UDTs and a worse case number of nodes needed can be determined, I would just create an array of them in a pool, as I stated before, and use the index of where the UDT is in the array as the pointers to link them.
    Yes, exactly (should have read further...)

    Quote Originally Posted by passel View Post
    I know I did something similar as a possible coding competition entry years ago to try to quickly determine the frequency of words in a novel, but the competition never came about. That was done in VB6 but I would have to track the code down, it isn't on this machine.
    Sounds suspicously like a contest I've also taken part in (is it by any chance the german "dotnet-pro journal",
    formerly known as "basic-pro" we're talking about)?

    Will try to find my submission (it was also tree-based, and came out only 10-20% slower, compared to the
    C++-based winner).

    Olaf

  15. #15
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    14,205

    Re: Why do I keep getting this error?

    And to DataMiser and techgnome - it is entirely possible and reliable to work this way
    with UDTs (stuffing them into Variants). It is just not practised - but that's more due
    to the simple reason, that many VBers don't like to work with ActiveX-Dlls.
    You should note that I was referring to using them within the program which is what the OP was trying to do, not wrapping them in a dll which ironically needs to use a class in order to make this work.

    Why not just use a class and be done with it.

  16. #16
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Why do I keep getting this error?

    Quote Originally Posted by DataMiser View Post
    You should note that I was referring to using them within the program which is what the OP was trying to do, not wrapping them in a dll which ironically needs to use a class in order to make this work.

    Why not just use a class and be done with it.
    Thought I've explained the advantage of using a UDT in a Variant-Hull already (it has the far leaner Mem-Consumption).

    Wrapping the Memory-Allocation of two simple members this way in a Class:
    Code:
    Option Explicit
    
    Public t As Class1
    Public b As Byte
    will allocate 8Byte for the two members + 110Bytes overhead per ("naked") VB-class-instance.


    ...whilst the following definition is not really a Class - it's a plain Typelib-definition, which
    just "happens to be noted in a class".
    Code:
    Public Type TestType
      V As Variant
      B As Byte
    End Type
    ...and it will allocate 20 Bytes for the two members + again 20 Bytes for additional entries of itself in V.

    There's another thing you got wrong, since you wrote: "A UDT is a single object. It is not multi instance."

    An UDT is just a Memory-allocation - you can have as many UDT-allocations of the same type
    as you want (behind Variables or Arrays) - and apparently also nested (with a Variant as the
    Reference-Container).

    There's C/C++ (or FreeBasic FWIW), ...any language which supports pointer-operators which
    allow a convenient access per "referenced-member-specifier":

    pStruct->SomeMember
    instead of:
    Struct.SomeMember

    With this kind of "Pointerbased, reference-nesting of Structs" the whole thing becomes
    a bit easier to handle - but a Struct is still the same thing as an UDT in VB - just an
    information for the compiler, how many bytes to allocate when such a thing gets used -
    (along with information, at which offset in those allocated Bytes the Members start).

    Classes always have more overhead than Structs (even in C++, where they are lighter than in VB -
    they (don't know the exact amount) have an overhead of perhaps 12 or 16Bytes there ...
    A Struct does not have *any* Overhead (other than the one caused by alignment-fillers -
    but the alignment-rules would cause the very same small overhead also on the members of
    C++ Classes.


    Olaf
    Last edited by Schmidt; Apr 9th, 2014 at 11:31 PM.

  17. #17
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    14,205

    Re: Why do I keep getting this error?

    Yes I was a bit confused when I mentioned the UDT being a single object, actually it could be more than one even in a module though you could not specify the UDT as a member of that same UDT.

    I guess I must be missing something here as the whole notion seems very odd to even want to try, especially considering that there is only a single byte of actual data being stored.

  18. #18
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,532

    Re: Why do I keep getting this error?

    Quote Originally Posted by DataMiser View Post
    I guess I must be missing something here as the whole notion seems very odd to even want to try, especially considering that there is only a single byte of actual data being stored.
    True... but you know how it is...we never get the full story and do get a lot of "That was for example, the real situation is different."


    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  19. #19
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    14,205

    Re: Why do I keep getting this error?

    Yep... hard to give good advice when not presented with real info. In the example case imagine what the code would look like to access an element 10 levels deep

    x=A.v.v.v.v.v.v.v.v.v.v.b

    where it could be

    x=b(9)

  20. #20
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Why do I keep getting this error?

    Quote Originally Posted by DataMiser View Post
    Yep... hard to give good advice when not presented with real info. In the example case imagine what the code would look like to access an element 10 levels deep

    x=A.v.v.v.v.v.v.v.v.v.v.b

    where it could be

    x=b(9)

    Yep - your x=b(9) code would be the use of an index as an alternative way to reference
    a Type - that's how one can work (with a few additional arrays and stuff) also performant
    with VB6 in such a scenario.

    Though what you wrote at the top is not quite, how it would be used - many parts in
    a Huffman (or general tree-like) implementation will need a "traversing the hierarchy" -
    and this would look more like:

    Do While CheckOutNode(A) = enmContinueTraversing
    A = A.v
    Loop

    Or something in analogy to that.

    Olaf

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width