Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Assign User Defined Type to Dictionary Item 1

Status
Not open for further replies.

SmokinWrek

IS-IT--Management
Jun 20, 2002
36
0
0
US
I'm trying to assign a variable dim'ed as a UDT to a dictionary item, but am having problems.

When I define the UDT and variable within my form module like this:
Code:
Private Type DataInfo
  fldInd As String * 1
  fldName As String
  fldPos As Long
  fldLen As Long
  fldMax As Long
  fldMin As Long
  fldCnt As Long
  fldWithData As Long
End Type
Dim aryDataInfo As DataInfo

dict.Item(x) = aryDataInfo

I get a 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.

So, I put the declaration into a module as such:
Code:
Public Type DataInfo
  fldInd As String * 1
  fldName As String
  fldPos As Long
  fldLen As Long
  fldMax As Long
  fldMin As Long
  fldCnt As Long
  fldWithData As Long
End Type
Public aryDataInfo As DataInfo

...and call it the same way I had been from my form module, but I get the same error.

Is it not possible to do what I'm attempting to do? I understand that I can't use an array as a dictionary key, but according to the VB help, a dictionary item can be "any form of data".

Please, can I get a little help and direction with this?
 
I think it's trying to tell you such UDTs must be defined as a Public member of an ActiveX DLL Class module. In other words they mean "public" in the COM sense, not "public" in terms of scope.

You could try that: Make a separate DLL project with a Class that defines the UDT. Then go back to your standard EXE project, add a reference to the new DLL, and try declaring a UDT of that Type.

A little messy unless your project group already has a DLL in it. Might work though.
 
Whew! Uglier than I imagined:

Project1: Form1.frm
Code:
Option Explicit

Private C As New Collection

Private Sub cmdFetch_Click()
    Dim CDI As Project2.Class1
    
    Set CDI = C.Item("only")
    MsgBox CDI.DI.fldInd
End Sub

Private Sub Form_Load()
    Dim CDI As New Project2.Class1
    Dim DI As Project2.DataInfo
    
    DI.fldInd = "X"
    CDI.DI = DI
    C.Add CDI, "only"
End Sub

Project2: Class1.cls
Code:
Option Explicit

Public Type DataInfo
  fldInd As String
  fldName As String
  fldPos As Long
  fldLen As Long
  fldMax As Long
  fldMin As Long
  fldCnt As Long
  fldWithData As Long
End Type

Private m_DI As DataInfo

Public Property Get DI() As DataInfo
    DI = m_DI
End Property

Public Property Let DI(DIVal As DataInfo)
    m_DI = DIVal
End Property

Maybe I'm not thinking right now... but it works.

However since you have to store an object in the collection anyway, you might be better off just dropping the UDT entirely and just define the whole thing as a Class with all of your UDT fields as Public variables (thus getting the property set/getters generated for you by the compiler).

Note that fixed Strings can't be used with a UDT as shown above either!

Even so, if you want to do file I/O with UDTs (which still offers some advantages) you might use the clunky method I illustrated above.

Anyone who is thinking more clearly and can offer a better solution please feel free.
 
Sorry, I just awoke a little more here and realize you wanted to use a Dictionary instead of a Collection.

If I'm not mistaken the rules are very similar if not identical though.
 
Thanks for the effort, but I decided to avoid the mess, and just use an array of the UDT, and use a dictionary item just to point to where certain items are stored within the array.

Code:
Private Type DataInfo
  fldInd As String * 1
  fldName As String
  fldPos As Long
  fldLen As Long
  fldMax As Long
  fldMin As Long
  fldCnt As Long
  fldWithData As Long
End Type
Dim aryDataInfo() As DataInfo

Open txtControlFile.Text For Input As #1
lstDataInfo.Clear
Do
  Line Input #1, TempData
  lstDataInfo.AddItem TempData
Loop Until EOF(1)
Close #1
dict.RemoveAll
ReDim aryDataInfo(lstDataInfo.ListCount - 1)
For x = 0 To lstDataInfo.ListCount - 1
  Erase aryTemp
  aryTemp = Split(TempData, ";")
  With aryDataInfo(x)
    .fldInd = aryTemp(0)
    .fldName = aryTemp(1)
    .fldPos = aryTemp(2)
    .fldLen = aryTemp(3)
    .fldMax = 0
    .fldMin = 99999
    .fldCnt = 0
    .fldWithData = 0
    If dict.Exists(.fldInd & .fldPos & .fldLen) Then
      MsgBox "Error: You cannot count duplicate fields!" & vbCrLf & _
             "Please correct control file and try again.", vbOKOnly, _
             "Field Definition Error"
      Exit Sub
    Else
      dict.Add .fldInd & .fldPos & .fldLen, x
    End If
  End With
Next x


Kevin
 
Well, where I was going was that you can simplify things like:

Project1: Form1.frm
Code:
Option Explicit

Private C As New Collection

Private Sub cmdFetch_Click()
    Dim DI As Project2.DataInfo
    
    Set DI = C.Item("only one here")
    MsgBox DI.fldInd
End Sub

Private Sub Form_Load()
    Dim DI As New Project2.DataInfo
    
    DI.fldInd = "X"
    C.Add DI, "only one here"
End Sub

Project2: DataInfo.cls
Code:
Option Explicit

Public fldInd As String
Public fldName As String
Public fldPos As Long
Public fldLen As Long
Public fldMax As Long
Public fldMin As Long
Public fldCnt As Long
Public fldWithData As Long

You still can't use fixed-length Strings, but it cuts out a lot of the other sheep dip.

This way you don't need to fuss with that extra level of redirection to get the values. You also don't have to redimension that array of UDTs. Since you aren't using binary I/O with UDTS anyway you don't lost one of their major advantages by going with a Class. You are stuck with a DLL though.

If the array will do the trick for you, then great.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top