Results 1 to 14 of 14

Thread: [RESOLVED] Change fields in UDT

  1. #1

    Thread Starter
    PowerPoster isnoend07's Avatar
    Join Date
    Feb 2007
    Posts
    3,237

    Resolved [RESOLVED] Change fields in UDT

    A few years ago as a pure VB rookie i created a UDT with the size of the fields specified. I now want to change some of the sizes.
    How can i do this and still be able to open the old files created with the old UDT ?

    Private Type PersonalInfo
    stDate As String * 10
    stLastName As String * 25
    stFirstName As String * 20
    stStreet As String * 45
    stCity As String * 20
    stState As String * 3
    stZip As String * 12
    stPhone As String * 20
    stEmail As String * 35
    stDeleted As String * 1
    stWPhone As String * 20
    stCell As String * 20
    stPager As String * 20
    stFax As String * 20
    stNotes As String * 250
    stCompany As String * 25
    stCompanyOrLastname As String * 1
    End Type

    I am opening the files like this:
    Dim gCustomer As PersonalInfo
    Get miFilenumber, miIndex, gCustomer

    I am saving the files like this:

    Put miFilenumber, miIndex, gCustomer

  2. #2
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Change fields in UDT

    Edited: Check post #3 below. A much easier solution in my opinon.

    VB will try to get the UDT based on the Len() of the UDT, in your case. So, unless the correct size in the file known, using the wrong UDT version will extract incorrect data.

    Two ideas
    1. Obvious. Use different files and then use different read routines based on the UDT being used.
    2. Append to any new files, a flag. The flag being the size/version of the UDT. Though the flag not used, it forces a mismatch when comparing the file size to the length of the expected UDT, which in a neat way can identify which version of the UDT is in use. If newer versions are added in the future, this flag can be retrieved to determine the UDT size. But in this case it isn't used for that purpose, only to determine if version 0 or version 1 is in use. Untested code
    Code:
    Public Const verFlag As Long = 1 ' change if new versions are applied later
    .... reading
      ' size of old UDT:  mLenVer0
      ' size of new UDT: mLenVer1
      If (LOF(miFilenumber)-4) Mod mLenVer1 = 0& Then ' new UDT version
          ' read using new UDT
      Else ' should be old UDT version, but you can double check
             If LOF(miFilenumber) Mod mLenVer0 > 0& Then ' not old version either
                 MsgBox "Unrecognized format"
             Else
                 ' read using old UDT
             End If
      End If
    
    ' then when saving in the new version
    Put miFilenumber, miIndex, gCustomer
    ' and when done writing any appended UDTs
    Put miFileNumber, [calc end of file if needed], verFlag
    But forward compatibility will be a challenge. In other words, your older app versions won't know to look for a newer version. This may be a problem.

    Edited. Above won't work in one case: file size is evenly divisible by both the old & new UDT+4 structures. Therefore, if used, it will have to be modified to check for that. Very doable, but won't post the modification here, because the next post is probably a better solution for your specific case.
    Last edited by LaVolpe; Jan 5th, 2008 at 05:01 PM.

  3. #3
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Change fields in UDT

    Ugh. There is a much easier way.
    In the New UDT, add a version member as the first member of the UDT, numerical or unique string.
    Then simply open the file and read the first x bytes of the file to retrieve that version member.

    If the first member of the Old & New UDTs are string Dates (10 bytes), this is simple. The version member of the new udt is a non date value, i.e., "Ver1". Now read the first 10 bytes into a string and use IsDate(). If it returns false, then it isn't a date and therefore the new version

    Edited: This only solves the problem of which UDT to use for reading. If reading, using the the old UDT, and want to use the new UDT structure, you will have to convert from old to new. In future programs, it may be wise to simply append new members to a UDT vs trying to change member sizes. This is how Windows does it (most of the time). One version may read 10 members, but a newer version may read 15 members. The first member of a UDT is generally the size of the UDT. This way any app version can know where one udt starts & ends. Internally, the app knows how many bytes it needs per UDT for its purpose. The key difference here is that the UDT member sizes don't change, only the number of members change.
    Last edited by LaVolpe; Jan 5th, 2008 at 04:57 PM.

  4. #4

    Thread Starter
    PowerPoster isnoend07's Avatar
    Join Date
    Feb 2007
    Posts
    3,237

    Re: Change fields in UDT

    Quote Originally Posted by LaVolpe
    Ugh. There is a much easier way.
    In the New UDT, add a version member as the first member of the UDT, numerical or unique string.
    Then simply open the file and read the first x bytes of the file to retrieve that version member.

    If the first member of the Old & New UDTs are string Dates (10 bytes), this is simple. The version member of the new udt is a non date value, i.e., "Ver1". Now read the first 10 bytes into a string and use IsDate(). If it returns false, then it isn't a date and therefore the new version

    Edited: This only solves the problem of which UDT to use for reading. If reading, using the the old UDT, and want to use the new UDT structure, you will have to convert from old to new. In future programs, it may be wise to simply append new members to a UDT vs trying to change member sizes. This is how Windows does it (most of the time). One version may read 10 members, but a newer version may read 15 members. The first member of a UDT is generally the size of the UDT. This way any app version can know where one udt starts & ends. Internally, the app knows how many bytes it needs per UDT for its purpose. The key difference here is that the UDT member sizes don't change, only the number of members change.
    I was hoping to get around opening 2 udt's into memory. Do you see any problem with using the files DateCreated to determine the udt to use?

  5. #5
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Change fields in UDT

    Quote Originally Posted by isnoend07
    I was hoping to get around opening 2 udt's into memory. Do you see any problem with using the files DateCreated to determine the udt to use?
    I don't see how you will get around it. The file will be in a format of one UDT or the other. In order to load them using VB's Get method, you would have to provide VB with the proper UDT structure.

    Eluded to in the previous post, another option is to simply convert old UDT to new UDT as needed. This still requires 2 UDTs initially. Read one & convert, read next and convert, etc. Yet another option is to read the file manually vs reading in UDTs by index, but is more work IMO and requires reading each UDT member individually.

    Please keep in mind what I said about the old app version not being able to read the new file version. I think this is another problem that isn't being addressed. There is no way the older version can determine if the file format is different. It will read the new version file incorrectly, period. The old version cannot be compatible with new format, but the new version can be compatible with old format.

    Regarding dates? I wouldn't rely on it. What if the old app version creates/updates a file, the new version app may mistakenly think the file is in the new format, no?

    Edited: I'd insert into the new UDT, as the first member, a Version member. This will definitively let you know which format the file is in by checking that member in IsDate() as described in previous post. Again the assumption is that the old UDT first member was also Date.
    Last edited by LaVolpe; Jan 5th, 2008 at 05:31 PM.

  6. #6

    Thread Starter
    PowerPoster isnoend07's Avatar
    Join Date
    Feb 2007
    Posts
    3,237

    Re: Change fields in UDT

    Quote Originally Posted by LaVolpe
    I don't see how you will get around it. The file will be in a format of one UDT or the other. In order to load them using VB's Get method, you would have to provide VB with the proper UDT structure.

    Eluded to in the previous post, another option is to simply convert old UDT to new UDT as needed. This still requires 2 UDTs initially. Read one & convert, read next and convert, etc. Yet another option is to read the file manually vs reading in UDTs by index, but is more work IMO and requires reading each UDT member individually.

    Please keep in mind what I said about the old app version not being able to read the new file version. I think this is another problem that isn't being addressed. There is no way the older version can determine if the file format is different. It will read the new version file incorrectly, period. The old version cannot be compatible with new format, but the new version can be compatible with old format.

    Regarding dates? I wouldn't rely on it. What if the old app version creates/updates a file, the new version app may mistakenly think the file is in the new format, no?

    Edited: I'd insert into the new UDT, as the first member, a Version member. This will definitively let you know which format the file is in by checking that member in IsDate() as described in previous post. Again the assumption is that the old UDT first member was also Date.
    I don't see a problem with an old version trying to read a new version. The old version only creates old UDT's.
    How would i read the first 10 bytes of the file?
    Using this to open: Get miFilenumber, miIndex, gCustomer

  7. #7
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Change fields in UDT

    Quote Originally Posted by isnoend07
    I don't see a problem with an old version trying to read a new version. The old version only creates old UDT's.
    How would i read the first 10 bytes of the file?
    Using this to open: Get miFilenumber, miIndex, gCustomer
    Finally, an easy question
    Code:
    Dim sDate As String * 10
    Get miFilenumber, 1, sDate

  8. #8

    Thread Starter
    PowerPoster isnoend07's Avatar
    Join Date
    Feb 2007
    Posts
    3,237

    Re: Change fields in UDT

    Quote Originally Posted by LaVolpe
    Finally, an easy question
    Code:
    Dim sDate As String * 10
    Get miFilenumber, 1, sDate
    I don't see what that tells me

  9. #9
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Change fields in UDT

    To allow us to be on the same page, please post the 1st 2 members of each UDT: old and new. Then I think I can make it very clear, ok?

  10. #10

    Thread Starter
    PowerPoster isnoend07's Avatar
    Join Date
    Feb 2007
    Posts
    3,237

    Re: Change fields in UDT

    Quote Originally Posted by LaVolpe
    To allow us to be on the same page, please post the 1st 2 members of each UDT: old and new. Then I think I can make it very clear, ok?
    New udt:
    Private Type NewPersonalInfo
    stVersion As String * 1 <-----New field
    stDate As String * 10
    stLastName As String * 25

    Old udt:
    Private Type PersonalInfo
    stDate As String * 10
    stLastName As String * 25
    stFirstName As String * 20

  11. #11
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Change fields in UDT

    Here's how that new member and the 1st 10 bytes makes a difference.
    Code:
    ' the member must be non-numeric
    Dim npi As NewPersonalInfo 
    Dim pi As PersonalInfo
    Dim sDate As String * 10
    Dim ff As Integer
       
       ' write old format for first test
       pi.stDate = Format$(Date,"dd/mm/yyyy")
       ff = FreeFile()
       Open "C:\Test.udt" For Binary As #ff
       Put #ff, , pi
       Close #ff
    
       ' now to determine if format is old or not
       Open "C:\Test.udt" For Binary As #ff
       Get #ff, 1 , sDate
       Close #ff
       If Left$(sDate,1)=" " Then ' in case your stDate member can be blank
            MsgBox "File in Old Format"
       ElseIf IsDate(sDate) Then 
            MsgBox "File in Old Format"
       Else
            MsgBox "File in New Format"
       End If
    
       ' now to test the new format
       npi.stVersion = "A" ' this prevents IsDate() below from returning true
       npi.stDate = Format$(Date,"dd/mm/yyyy")
       ff = FreeFile()
       Open "C:\Test.udt" For Binary As #ff
       Put #ff, , npi
       Close #ff
    
       ' now to determine if format is old or not
       Open "C:\Test.udt" For Binary As #ff
       Get #ff, 1 , sDate
       Close #ff
       If Left$(sDate,1)=" " Then 
            MsgBox "File in Old Format"
       ElseIf IsDate(sDate) Then 
            MsgBox "File in Old Format"
       Else
            MsgBox "File in New Format"
       End If

  12. #12
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Change fields in UDT

    If you like/understand the logic above, you can acutally use the new personal info udt without a stVersion member. If interested, two things to remember are:

    Writing Files
    1. Always write an alpha character in the 1st position of the file
    (i.e., Put miFileNumber, 1, CByte(65))
    2. Always start writing your UDTs from file position 2, not 1 becuase 1 is reserved for the alpha character

    Reading Files
    1. Perform same test in prev post using IsDate to determine format version
    2. Always start reading UDTs from file position 2 if new format, else from position 1 for old format
    Last edited by LaVolpe; Jan 5th, 2008 at 07:39 PM.

  13. #13

    Thread Starter
    PowerPoster isnoend07's Avatar
    Join Date
    Feb 2007
    Posts
    3,237

    Re: Change fields in UDT

    Quote Originally Posted by LaVolpe
    If you like/understand the logic above, you can acutally use the new personal info udt without a stVersion member. If interested, two things to remember are:

    Writing Files
    1. Always write an alpha character in the 1st position of the file
    (i.e., Put miFileNumber, 1, CByte(65))
    2. Always start writing your UDTs from file position 2, not 1 becuase 1 is reserved for the alpha character

    Reading Files
    1. Perform same test in prev post using IsDate to determine format version
    2. Always start reading UDTs from file position 2 if new format, else from position 1 for old format
    Thanks for your help, that seems to work, still testing
    Tried, but Vbwire says:
    You must spread some Reputation around before giving it to LaVolpe again.

  14. #14
    PowerPoster
    Join Date
    Nov 2002
    Location
    Manila
    Posts
    7,629

    Re: Change fields in UDT

    Rather than keeping track of each file independently why not just convert all of the files then manipulate them using the new scheme... if the data structure is expected to change once again then might as well consider more flexible options such as XML or a database so you won't have backward compatibility as too much of a maintenance burden.

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