#### Archived

This topic is now archived and is closed to further replies.

# Collection of a UDT in VB6

This topic is 5889 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I say:
  ''Module ReportInfo Public Type CostInfoChunk Level As Integer BaseID As String LotID As String SubID As String End Type Public Type CostInfo Info() As CostInfoChunk MaterialCost As Currency End Type ''WorkOrder class Dim m_MaterialCostCollection as Collection ''... Dim CI as ReportInfo.CostInfo CI.Info(1..n) = ''stuff CI.MaterialCost = SumMaterialCost(CI) m_MaterialCostCollection.Add(CI) 
And VB says:
quote:
Compile error: Only user-defined types defined in public object modules can be coerced to or from a variant or passed to late-bound functions
At the .Add <scratches head> ummm, it IS a user-defined type in a public module!!!! so I says fine:
  ''Class CostInfo Public Info() As ReportInfo.CostInfoChunk Public MaterialCost As Currency 
As VB says:
quote:
Constant, fixed-length strings, arrays, user-defined types and Declare statements not allowed as public members of object modules
Right, it''d be way too danergous to let a VB program to that... Fine, I''ll give in to the dark-side
  Dim m_Info() As ReportInfo.CostInfoChunk Dim m_MaterialCost As Currency Property Set Info(i As Integer, chunk As ReportInfo.CostInfoChunk) Info(i) = chunk End Property Property Get Info(i As Integer) As ReportInfo.CostInfoChunk Info = m_Info(i) End Property 
quoteth VB:
quote:
Compile Error: Only public user defined typed define in public modules can be used as parameters or return types for public procedure of class modules or as fields of public user defined types
(at the Property Set) AAAAAAAARRRRRRRRRRRRRGGGGGGGGGGGGGHHHHHHHHHHHHHHHHHHH Please, someone tell me how stupid I am, and give me a clue how to make a collection of a UDT? (VB6 SP5) Magmai Kai Holmlor "Oh, like you''ve never written buggy code" - Lee "What I see is a system that _could do anything - but currently does nothing !" - Anonymous CEO

##### Share on other sites
The only thing that is stupid is VB ...

I have hit this problem in the past and according to some good friends who code in VB all the time, you just can''t do it. There is no good reason, just a microsoftism.

I hate to say it, but any UDT''s that you require collections of must be made into classes... well the VB definition of a class anyhow.

Hope that is some consolation, no, it wasn''t to me either.

##### Share on other sites
  'Class: MyClassOption ExplicitPublic Key As StringPrivate mvarMyClassProperty As LongPublic Property Let MyClassProperty(ByVal vData As Long) mvarMyClassProperty = vDataEnd PropertyPublic Property Get MyClassProperty() As Long MyClassProperty = mvarMyClassPropertyEnd Property

  'Class: MyCollectionOption ExplicitPrivate mCol As CollectionPublic Function Add(Key As String, MyClassProperty As Long, Optional sKey As String) As MyClass 'create a new object Dim objNewMember As MyClass Set objNewMember = New MyClass 'set the properties passed into the method objNewMember.Key = Key objNewMember.MyClassProperty = MyClassProperty If Len(sKey) = 0 Then mCol.Add objNewMember Else mCol.Add objNewMember, sKey End If 'return the object created Set Add = objNewMember Set objNewMember = NothingEnd FunctionPublic Property Get Item(vntIndexKey As Variant) As MyClass Set Item = mCol(vntIndexKey)End PropertyPublic Property Get Count() As Long Count = mCol.CountEnd PropertyPublic Sub Remove(vntIndexKey As Variant) mCol.Remove vntIndexKeyEnd SubPublic Property Get NewEnum() As IUnknown Set NewEnum = mCol.[_NewEnum]End PropertyPrivate Sub Class_Initialize() Set mCol = New CollectionEnd SubPrivate Sub Class_Terminate() Set mCol = NothingEnd Sub

Basically, VB classes (including the collection) and UDTs don't mix. My guess is that they were going to get rid of the UDTs, except they realised that in many ways they are better than the class system they had devised. (Things like file saving, speed and simplicity)

When order isn't important, you can beat a collection hands down for speed (and code cleanliness). I haven't done tests for when the order within the container is needed to be sustained, but I haven't even thought about it.

What you *can* do, if you are in a position where you need to use UDTs, is something like this:

  Sub PutUDTInArray(MyUDT As udtBlah, PutIn() As Byte) Redim PutIn(Len(MyUDT) - 1) 'Assumes 0 based array CopyMemory ByVal VarPtr(PutIn(0)), MyUDT.FirstElement, Len(MyUDT)End SubFunction GetUDTFromArray(GetFrom() As Byte) As udtBlah CopyMemory ByVal GetUDTFromArray.FirstElement, VarPtr(PutIn(0)), Len(GetUDTFromArray)End Function

But, you have to be careful, because if you use that with a udt with indirect data types (variable length strings, dynamic arrays), then copying just that memory will not be enough, but you have resize the destination and copy across there too. Could turn into a lot more work than you want.

So, probably the best solution is to just make a dynamic array with a wrapper around it so it acts like a collection. It will probably be faster, since the VB collection is one of those great "lets use Variants for everything since they are flexible" type things. For games, this is what I do, and performance is fine, but when I do it, I don't need to maintain order.

btw, Magmai, are you Thraka at another message board?

Trying is the first step towards failure.

Edit: Switched from codeblock? tags to source tags... the tag I always forget . Oh, and I might as well try and squeeze this in here, because I meant to say that squashing the udt into a byte array is ugly... although I'm sure you noticed... and I don't know the copymemory api call off the top of my head.

Edited by - ragonastick on January 4, 2002 5:26:17 AM

##### Share on other sites
For those interested parties ..

Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

##### Share on other sites
the VB compiler is probably the worst compiler ever, and VB is just as bad.

im not sure, but i think that every native type in VB is actually a variant... native types get built in error code for type checking, notice that type mismatches are run time only. native examples would be integers, variant strings, and classes.

variants can not be fixed length structures for some reason, and the compiler enforces this (design time).

if this is true, then the reason classes dont like UDT is that the class wants a variant, and a UDT is obvuously not a variant (UDT = fixed-length).

you need to do everything with classes, not UDTs; the VB designers were clearly stoned when they said VB was done.

if its possible to make your UDT inherit from a variant, then maybe u can fix ur problem. i forget if this is possible, but i think that only classes can inherit.

Edited by - evilcrap on January 4, 2002 6:33:31 AM

##### Share on other sites
No, thats not true. Theregular data types are real. However, VB does all conversions implicitly. I usually notate conversions implicitly, but it won''t make a difference.

-----------------------------
The sad thing about artificial intelligence is that it lacks artifice and therefore intelligence.

##### Share on other sites
quote:
im not sure, but i think that every native type in VB is actually a variant... native types get built in error code for type checking, notice that type mismatches are run time only. native examples would be integers, variant strings, and classes.

Definately not. Have a look at the memory used, for a variant type to work, there needs to be a few extra bits used to store the type, this isn't the case with any of VBs native types.
Unfortunately for so many programmers, VB will convert between numerical types on the fly, so:

Dim A As Long
A = 5

Will compile just fine. While it should read
Dim A As Long
A = 5&

Also, to my horror, I just found that:

Dim A As String
A = 5

Will work, but worse is that the reverse
Dim A As Long
A = "5"

will work too. I can see why there is so much slow VB code

quote:
variants can not be fixed length structures for some reason, and the compiler enforces this (design time).

I've never had a situation where using variants would give me any benefit. Maybe for business apps, but even then, I think I would still prefer to code my own "variant" type.

quote:
you need to do everything with classes, not UDTs; the VB designers were clearly stoned when they said VB was done.

Or the opposite, and don't use classes at all. Usually, this is a lot faster.

quote:
if its possible to make your UDT inherit from a variant, then maybe u can fix ur problem. i forget if this is possible, but i think that only classes can inherit.

No, it is only semi-inheritance at best with VB. Really, classes aren't very useful since they are missing those useful things which C++ classes have. Not that you can't do what C++ programs do, but that

Edited by - ragonastick on January 4, 2002 7:20:09 AM

##### Share on other sites
Ok, so your susposed to use property Let/Get - what''s Set for then?

Ah ha!
  ''class CostInfoChunkPublic Level As IntegerPublic BaseID As StringPublic LotID As StringPublic SubID As String''class CostInfoPublic Info As CollectionPublic MaterialCost As Currency''...Dim g_CostInfoCollection as CollectionDim CI as CostInfoDim chunk as CostInfoChunkFor Each CI in g_CostInfoCollection For Each chunk in CI.Info ''mess with chunk NextNext

...
quote:

btw, Magmai, are you Thraka at another message board?

Afriad not, I''m MKH just about everywhere. A long time ago I used Silpheed (before the Internet went home).

##### Share on other sites
The reason a UDT is not supported as a valid parameter of a public interface is deeply rooted in COM Automation Interface rules. You can only pass a valid VARIANT type on a COM Automation Interface, which all VB classes are based on at very low level. This includes SAFEARRAY as well (which is a vb array, with both an upper and lower bound stored as part of the array object contrary to C/C++ which implements arrays as contiguous memory), the only caveat being that you can only have SAFEARRAY''s of VARIANT objects! It''s a little redundant but it makes sense from a low level. COM has to marshall all that stuff and it has to know how to pack and unpack memory to marshal it across processes, apartments, and machines. A UDT in vb is an unknown to COM. COM has no way of knowing how big your UDT is or how to stream it''s information (it may have special streaming requirements). This is the reason why you can''t have UDT''s on a public interface. I suggest you convert your UDT''s to classes as suggested by an earlier post. It''s more object oriented and a cleaner aproach. See Java and C#.

##### Share on other sites
The problem isn''t COM - it''s VB. Those automation rules were made for C++ (and other languages) to follow so that it could work with VB. If you abandon automation (VB/VBScript/JScript/ActiveX), you can marshal anything (other than a void*).

VB knows all the type information of the UDT, it could use custom marshlaing to tell COM how to handle those apartment issues. If you did something under handed, like stuff a HWND or void* into a LONG it woudl break, but if you used the types normally all the information needed is there.

There''s even a SAFEARRAYEX interface to handle manipulating safearrays of UDTs (Delphi 5 SP3 doesn''t natively support it btw, 6 may...)

##### Share on other sites
let is for anything thats not a class i think
property let x(lx as int)
m_x = lx
end property

set is for classes
property set x(c as class)
set m_x = c
end property