• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 252
  • Last Modified:

How to Save classes to binary file vb6

I have 2 classes I am trying to save to a binary file eg:
RoofCo.cls
Public CompanyName As String
Public Address As String
Public City As String
Public State As String
Public Zip As String
Public Sqs As Double
Public BidAmount As Currency
Public BidMaterial As String
Public Bid2Amount As Currency
Public Bid2Material As String
Public Sdate As String
Public BusYrs As Integer
Public Estimator As String
Public Email As String
Public Notes As String
Public Phones As String '(mshflexgrid gridPhones)
Public Tasks As String '(mshflexgrid  grid2Column)

Open in new window


This class contains a collection:
RoofCoCollection.cls
Private m_RoofCompany As Collection
' Add an RoofCo object to the collection.

Public Sub Add(ByVal emp As RoofCo, Optional ByVal key As Variant)
    If IsMissing(key) Then
         m_RoofCompany.Add emp
    Else
         m_RoofCompany.Add emp, key
    End If
End Sub
' Return the number of items in the collection.
Public Function Count() As Long
    Count = m_RoofCompany.Count
End Function
' Return an RoofCo object.

Public Function Item(ByVal Index As Variant) As RoofCo   '
    Set Item = m_RoofCompany(Index)
End Function



Public Sub Remove(ByVal Index As Variant)   
    m_RoofCompany.Remove Index
End Sub

Public Function NewEnum() As IUnknown
    Set NewEnum = m_RoofCompany.[_NewEnum]
End Function

Private Sub Class_Initialize()
    Set m_RoofCompany = New Collection
End Sub

Open in new window

How can this be done ?
0
isnoend2001
Asked:
isnoend2001
  • 17
  • 17
1 Solution
 
SethiCommented:
You need to create  DLL in VB6 and then you will be able to use this DLL in your other VB6 projects. This link would be a good start:

http://msdn.microsoft.com/en-us/library/aa229332%28v=vs.60%29.aspx
0
 
isnoend2001Author Commented:
Thanks Sethi
Darn i was hoping for something easier like saving a udt
0
 
isnoend2001Author Commented:
I think I posted incorrectly
I want to save the data created by the classes and be able to edit and add to the created data
This for a homeowner getting different bids from many roofing companies for comparison.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
isnoend2001Author Commented:
meant to include jpg
Roof-Bids.jpg
0
 
aikimarkCommented:
@isnoend2001

sethi thought you wanted to make your class a binary object.

1. Can we assume you want to repopulate your class data from a prior serialization operation or is this going to be a save-only process?

2. Do you need to serialize the data when the class object is removed from memory or as a result of some action (a method of the class)?

3. Why save to a file instead of a database?

4. Do you have any preferences or restrictions on the format of saved data?
0
 
isnoend2001Author Commented:
I was wondering when someone would say a database which for me would not work as i have tried in the past and ran into one problem after another mostly i think was installing on a users machine.

As far as the saving/loading I wrote a roof estimating program as a retired roofing contractor and rookie coder and everything(variables)in the project belonged to to the roof estimate.
This new program has many variables belonging to different companies. This really thru me a curve.
The code need to be saved-edited added to recalled

It works like this:
Homeowner is getting roofing bids for a new roof. With each bid all the information for the Roofing Companys bid is entered into the texboxes and saved all the info may not be received at one time,
so the companies info needs to be updated.
I do not have any restrictions on the format of the saved data, only i try to stay away from the fso
0
 
aikimarkCommented:
Might you need to consume this saved data with any other program?

Might you need to integrate this saved data with other data from other bids?

Do you have repeating/array data other than the collection?  I see some references to grids in your example above.
0
 
aikimarkCommented:
I added a structure to the general declarations section of the RoofCoCollection class and added code to the class terminate() event to persist the data.
Option Explicit
Private Type Roof_struc
    CompanyName As String
    Address As String
    City As String
    State As String
    Zip As String
    Sqs As Double
    BidAmount As Currency
    BidMaterial As String
    Bid2Amount As Currency
    Bid2Material As String
    Sdate As String
    BusYrs As Integer
    Estimator As String
    Email As String
    Notes As String
    Phones As String
    Tasks As String
End Type

'===================================
'your existing code remains unchanged here
'===================================

Private Sub Class_Terminate()
    Dim intFN As Integer
    Dim vItem As Variant
    Dim roofthing As Roof_struc
    intFN = FreeFile
    Open "C:\users\aikimark\downloads\Roofbid_" & Format(Now, "yyyymmddhhnnss") & ".txt" For Binary As #intFN
    For Each vItem In m_RoofCompany
        roofthing.CompanyName = vItem.CompanyName
        roofthing.Address = vItem.Address
        roofthing.City = vItem.City
        roofthing.State = vItem.State
        roofthing.Zip = vItem.Zip
        roofthing.Sqs = vItem.Sqs
        roofthing.BidAmount = vItem.BidAmount
        roofthing.BidMaterial = vItem.BidMaterial
        roofthing.Bid2Amount = vItem.Bid2Amount
        roofthing.Bid2Material = vItem.Bid2Material
        roofthing.Sdate = vItem.Sdate
        roofthing.BusYrs = vItem.BusYrs
        roofthing.Estimator = vItem.Estimator
        roofthing.Email = vItem.Email
        roofthing.Notes = vItem.Notes
        roofthing.Phones = vItem.Phones
        roofthing.Tasks = vItem.Tasks
        Put #intFN, , roofthing
    Next
    Close #intFN
End Sub

Open in new window

Something similar would need to happen in reverse to repopulate the class from the serialized file.
0
 
aikimarkCommented:
This would be an example of a function in your class that would populate the class from a prior serialization:
Public Function Populate(ByVal parmPathAndFilename As String)
    Dim intFN As Integer
    Dim vItem As Variant
    Dim roofthing As Roof_struc
    Dim clsRoof As RoofCo
    intFN = FreeFile
    If Len(Dir(parmPathAndFilename)) = 0 Then
        Populate = 53   'file not found
        Exit Function
    End If
    On Error Resume Next
    Open parmPathAndFilename For Binary As #intFN
    If Err <> 0 Then
        Populate = Err.Number
        Exit Function
    End If
    Do Until EOF(intFN)
        Get #intFN, , roofthing
        clsRoof.CompanyName = roofthing.CompanyName
        clsRoof.Address = roofthing.Address
        clsRoof.City = roofthing.City
        clsRoof.State = roofthing.State
        clsRoof.Zip = roofthing.Zip
        clsRoof.Sqs = roofthing.Sqs
        clsRoof.BidAmount = roofthing.BidAmount
        clsRoof.BidMaterial = roofthing.BidMaterial
        clsRoof.Bid2Amount = roofthing.Bid2Amount
        clsRoof.Bid2Material = roofthing.Bid2Material
        clsRoof.Sdate = roofthing.Sdate
        clsRoof.BusYrs = roofthing.BusYrs
        clsRoof.Estimator = roofthing.Estimator
        clsRoof.Email = roofthing.Email
        clsRoof.Notes = roofthing.Notes
        clsRoof.Phones = roofthing.Phones
        clsRoof.Tasks = roofthing.Tasks
        add clsRoof
    Loop
    Close #intFN
    Populate = 0
End Function

Open in new window

0
 
isnoend2001Author Commented:
Sorry about the late reply had errands
Yes the program already saves other data from the main form
A homeowner can enter roof measurement.
s and materials are calculated It uses a class to calculate the roof measurments
A udt is saved and 2 mshflegrids.
didn't realize this was going to be so involved. I was thinking i could just add it to the save/open I already have
Like this:
gMypath = app.path
MyFile = gMypath & "\" & txtlName & txtaddress & ".job"
 SaveRandomData MyFile, Job, gSizeQuickGrid 'in form

In a module
Public Sub SaveRandomData(ByVal sfilename As String, myData As JobInfo02_08, MyGrid As String) 
   Dim fnumber As Integer
    fnumber = FreeFile()
    
    Dim b()  As Byte
    Open sfilename For Binary As #fnumber
    Put #fnumber, , myData
    
    
    If myData.SizeQuickGrid Then
        b = MyGrid
        Put #fnumber, , b
    End If    

    
    Close #fnumber
   
End Sub

Public Sub LoadOldRandomData(ByVal sfilename As String, myData As JobInfo, MyGrid As String, myrtf As String)
     Dim fnumber As Integer
    fnumber = FreeFile()
    Dim b()  As Byte
    Open sfilename For Binary As #fnumber
    Get #fnumber, , myData
    
    If myData.SizeRTF Then
        ReDim b(myData.SizeRTF * 2 - 1) As Byte
        Get #fnumber, , b
        myrtf = b 'Cast byte array to string
    End If
    
    If myData.SizeQuickGrid Then
        ReDim b(myData.SizeQuickGrid * 2 - 1) As Byte
        Get #fnumber, , b
        MyGrid = b 'Cast byte array to string
    End If
    
    Close #fnumber
End Sub

Open in new window

All the reading i did on Collections-Classes never mentioned the pain of saving/opening files
0
 
aikimarkCommented:
That's what makes ORM software so attractive.

You would have had fewer statements if your RoofCo class had implemented an iterable collection of properties, rather than distinct properties.  In such cases, I might use a dictionary object.  Unfortunately, the dictionary object in VB6 does not have methods that allow you to persist/serialize its data and doing I/O operations (Get, Put) on an object variable is not supported.

I did run a quick test and found that the dictionary object's keys and items properties can be serialized.  This routine assigns some values to a dictionary object, based on the properties in your RoofCo object.
Sub SaveDic()
    Dim oDic As Object
    Dim intFN As Integer
    
    Set oDic = CreateObject("scripting.dictionary")

    oDic!CompanyName = "Now is the time"
    oDic!Address = "for all good men"
    oDic!City = "Durham"
    oDic!State = "NC"
    oDic!Zip = "27714"
    oDic!Sqs = CSng(123.45)
    oDic!Sdate = CStr(Date)
    oDic!BusYrs = CLng(15)

    intFN = FreeFile
    Open "C:\users\aikimark\downloads\SaveDic.txt" For Binary As #intFN
    Put #intFN, , oDic.keys
    Put #intFN, , oDic.items
    Close #intFN
End Sub

Open in new window

Repopulating the dictionary only takes a few more statements.
Sub LoadDic()
    Dim oDic As Object
    Dim intFN As Integer
    Dim vDicKeys As Variant, vDicItems As Variant
    Dim lngLoop As Long

    Set oDic = CreateObject("scripting.dictionary")
    
    intFN = FreeFile
    Open "C:\users\aikimark\downloads\SaveDic.txt" For Binary As #intFN
    Get #intFN, , vDicKeys
    Get #intFN, , vDicItems
    Close #intFN
    For lngLoop = 0 To UBound(vDicKeys)
        oDic(vDicKeys(lngLoop)) = vDicItems(lngLoop)
    Next
End Sub

Open in new window

If you switch your properties to a dictionary, the property references in your code will need to change from a period separator to a bang (exclamation) character.  But that might only require a single find/replace operation.

It is also common to save properties (or dictionary name/value pairs) in XML and JSON.
0
 
aikimarkCommented:
If the bang notation looks familiar, you have probably used it or seen it referencing recordset fields.
0
 
isnoend2001Author Commented:
I've requested that this question be closed as follows:

Accepted answer: 0 points for isnoend2001's comment #a40295090

for the following reason:

Thank You
I have decided to use the first code you wrote (not the dictionary)
I have decide that the other Save routine will stay as is it will be separate just with a different file name
In trying to read the values i get an error on this line call this public function
 Populate FileName' sub or function undefined
Private Sub Command3_Click()
Dim FileName As String
Dim gMypath As String
    gMypath = App.Path ' will be changed in sub main to typical path C:\Users\Public\Documents\RoofCalcWriter\AppFolder
    FileName = gMypath & "\" & RoofBidder.txtLname & RoofBidder.txtAddress & "bids" & ".dat"
 Populate FileName' sub or function undefined
End Sub
what could cause this error ?
0
 
aikimarkCommented:
@isnoend2001

I am halting your close request.  You are using a solution that I have provided.  Please accept one (or more) of my comments as the answer to this question, as appropriate.
0
 
isnoend2001Author Commented:
Thank you
Sorry
i did not post a close request. I must have clicked the wrong item or something.
I appreciate the help
0
 
aikimarkCommented:
Glad I was able to help.

Did you resolve the error you mentioned in your prior statement?
Populate FileName' sub or function undefined
I would assume it is and artifact left over from my example.  I can reopen this question to help you resolve the error.
0
 
isnoend2001Author Commented:
Thanks aikimark
Populate FileName' sub or function undefined
End Sub
what could cause this error ?
0
 
isnoend2001Author Commented:
Thanks aikimark
I posted before reading your last post.
No i have not found why the error occures
0
 
aikimarkCommented:
When I posted my code, I included a function for the class to populate it from the the previous save operation.  This is most likely the code (or related to calling this function from your code).
0
 
isnoend2001Author Commented:
i do not understand
for some reason it is not seeing the public function

In the form:
Private Sub Command3_Click()
'http://www.experts-exchange.com/Programming/Languages/Visual_Basic/Q_28508429.html#a40295293
  Dim FileName As String
    Dim gMypath As String
    gMypath = App.Path ' will be changed in sub main to typical path C:\Users\Public\Documents\RoofCalcWriter\AppFolder
    FileName = gMypath & "\" & RoofBidder.txtLname & RoofBidder.txtAddress & "bids" & ".dat"
 Populate FileName


End Sub

Open in new window

in RoofCoCollection
Public Function Populate(ByVal parmPathAndFilename As String)
    Dim intFN As Integer
    Dim vItem As Variant
    Dim roofthing As Roof_struc
    Dim clsRoof As RoofCo
    intFN = FreeFile
     Dim FileName As String
    
    
    Open parmPathAndFilename For Binary As #intFN
    If Len(Dir(parmPathAndFilename)) = 0 Then
        Populate = 53   'file not found
        Exit Function
    End If
    On Error Resume Next
    'Open parmPathAndFilename For Binary As #intFN
     Open FileName For Binary As #intFN
    If Err <> 0 Then
        Populate = Err.Number
        Exit Function
    End If
    Do Until EOF(intFN)
        Get #intFN, , roofthing
        clsRoof.CompanyName = roofthing.CompanyName
        clsRoof.Address = roofthing.Address
        clsRoof.City = roofthing.City
        clsRoof.State = roofthing.State
        clsRoof.Zip = roofthing.Zip
        clsRoof.Sqs = roofthing.Sqs
        clsRoof.BidAmount = roofthing.BidAmount
        clsRoof.BidMaterial = roofthing.BidMaterial
        clsRoof.Bid2Amount = roofthing.Bid2Amount
        clsRoof.Bid2Material = roofthing.Bid2Material
        clsRoof.Sdate = roofthing.Sdate
        clsRoof.BusYrs = roofthing.BusYrs
        clsRoof.Estimator = roofthing.Estimator
        clsRoof.Email = roofthing.Email
        clsRoof.Notes = roofthing.Notes
        clsRoof.Phones = roofthing.Phones
        clsRoof.Tasks = roofthing.Tasks
        Add clsRoof
    Loop
    Close #intFN
    Populate = 0
End Function

Open in new window

0
 
aikimarkCommented:
I don't see where you are referencing a RooferCoCollection class variable.  It is within that class that the Populate function resides.  Although the function is declared as "Public", it is not the same as a "Public" module function/sub.
0
 
isnoend2001Author Commented:
Thanks aikimark
that would explain the problem. did not realize that the public function was different in a class
How would i fix it ?
0
 
aikimarkCommented:
You need to qualify the method/function name with the name of a RooferCoCollection variable.
0
 
isnoend2001Author Commented:
Could you give an example:
I tried this to no avail:
Dim FileName As String
    Dim gMypath As String
    Dim SavedData As RoofCoCollection
    gMypath = App.Path ' will be changed in sub main to typical path C:\Users\Public\Documents\RoofCalcWriter\AppFolder
    FileName = gMypath & "\" & RoofBidder.txtLname & RoofBidder.txtAddress & "bids" & ".dat"
 Populate FileName
0
 
aikimarkCommented:
SavedData.Populate Filename

Open in new window


Note: I do not see in your posted code where you have populated the class collection with any data.
0
 
isnoend2001Author Commented:
I thought that is what the function does eg;
Populate with saved data from file
0
 
aikimarkCommented:
yes. it does.  You might need to pass the file name in parentheses
0
 
isnoend2001Author Commented:
Tried that to no avail
Private Sub Command3_Click()
'http://www.experts-exchange.com/Programming/Languages/Visual_Basic/Q_28508429.html#a40295293
  Dim FileName As String
    Dim gMypath As String
    Dim SavedData As RoofCoCollection
    gMypath = App.Path ' will be changed in sub main to typical path C:\Users\Public\Documents\RoofCalcWriter\AppFolder
    FileName = gMypath & "\" & RoofBidder.txtLname & RoofBidder.txtAddress & "bids" & ".dat"
 Populate (FileName)


End Sub
0
 
aikimarkCommented:
You didn't qualify it.
SavedData.Populate(FileName)

Open in new window

0
 
isnoend2001Author Commented:
That gives a different error: Object variable or With block variable not set
Private Sub Command3_Click()
  Dim FileName As String
    Dim gMypath As String
    Dim SavedData As RoofCoCollection
    gMypath = App.Path ' will be changed in sub main to typical path C:\Users\Public\Documents\RoofCalcWriter\AppFolder
    FileName = gMypath & "\" & RoofBidder.txtLname & RoofBidder.txtAddress & "bids" & ".dat"
 SavedData.Populate (FileName)

End Sub
0
 
aikimarkCommented:
Dim SavedData As New RoofCoCollection

Open in new window

0
 
aikimarkCommented:
One more thing you should consider serializing -- version.

Your class might change along with your application code.  If you add properties to the RoofCo class or change how the fields are used, you should probably include some class version datum along with the actual RoofCo data.  That way, your application can change to accommodate reading persisted data from a prior version serialization.
0
 
isnoend2001Author Commented:
Thanks i will keep that in mind
I have been fighting the populate function
It keep giving error: File already open
I cannot physically delete the file unless i unload the ide
I have also noticed the Private Sub Class_Terminate() does not always fire.
In Fact i can not get it to fire at all.
Once i get the problem solved I plan on moving the save routine to the form to get more control
don't know what this will involve If my efforts fail i will be posting as a new question
0
 
aikimarkCommented:
Be sure you have a close statement after reading or saving the file.

A class will not normally invoke the terminate event until one of the following happens
* The application ends
* The variable associated with the class is set to nothing
0
 
isnoend2001Author Commented:
ok thanks
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

  • 17
  • 17
Tackle projects and never again get stuck behind a technical roadblock.
Join Now