Collection of a UDT in VB6

Started by
9 comments, last by Shannon Barber 22 years, 3 months ago
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
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Advertisement
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.
  '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
Trying is the first step towards failure.
For those interested parties ..

Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
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
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.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
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
Trying is the first step towards failure.
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).
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
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#.
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...)
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara

This topic is closed to new replies.

Advertisement