Solved

UDT Array to String -- URGENT!!!!

Posted on 2001-06-06
28
440 Views
Last Modified: 2008-02-01
Hi all,

I need to convert a array of UDT's to a string.
I already know how to convert a string to an array, using the CopyMemory API.
But when I want to do it reversed, VB generates a fatal exception :(

Please help with this, I need this *really* fast!!

Thanks in advance,

D. Walsarie

this was my test:

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

Public Type udtITEM
  ItemID As Long
  ItemValue As Byte
End Type

Public myArray() As udtITEM
Public myString As String

Public Sub ConvertArrayToString()

  ReDim myArray(0 To 2)

  myArray(0).ItemID = 100
  myArray(0).ItemValue = 3

  myArray(1).ItemID = 200
  myArray(1).ItemValue = 6

  myArray(2).ItemID = 300
  myArray(2).ItemValue = 9

  CopyMemory ByVal myString, myArray(0), 3

End Sub
0
Comment
Question by:dwalsarie
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 5
  • 5
  • +5
28 Comments
 
LVL 2

Author Comment

by:dwalsarie
ID: 6159333
wOops..

CopyMemory ByVal myString, myArray(0), 3

should be

CopyMemory ByVal myString, myArray(0), 3 * 5

the value 5 is the length of the UDT :)
however, it still don't work
0
 
LVL 1

Expert Comment

by:zzconsumer
ID: 6159375
Mhh, I'm not sure what is a UDT, but maybe this can help you a bit:

Strig to Array:
dim s as String
dim a() as String

a = split(s,"")

Array to String:
s = join(a,"")

If this is not what you wanted, please exlain UDT to me. I'm always searching for something new. ;-)
0
 
LVL 1

Expert Comment

by:morgan_peat
ID: 6159392
   Dim myArray() As udtITEM
    Dim myString As String
   
    ReDim myArray(0 To 2)
       
    myArray(0).ItemID = 100
    myArray(0).ItemValue = 3
       
    myArray(1).ItemID = 200
    myArray(1).ItemValue = 6
   
    myArray(2).ItemID = 300
    myArray(2).ItemValue = 9
   
   
   
    ' Create some room in the string
    ' 3 items to be stored, and UDT is
    ' 8 bytes in length (alligned on DWord boundaries)
    ' Therefore needs to be 24 bytes long -> 12 chars
    myString = Space$(12)
   
    ' Copy the 24 bytes into the string
    CopyMemory ByVal StrPtr(myString), ByVal VarPtr(myArray(0).ItemID), 24
   
   
    ' Wipe the array, and re-instate as proof.
    ReDim myArray(0 To 2)
    CopyMemory ByVal VarPtr(myArray(0).ItemID), ByVal StrPtr(myString), 24


When using CopyMemory with UDT's, you need to be aware of the byte length.  Items are always aligned on DWords (Long) boundaries - ie. 4 bytes each.  Therefore, this UDT is 8 bytes in length.

To copy data into a string, you need to allocate memory first.  You didn't, so you were trying to copy data into a piece of memory you did not own - hence the exception.
0
Industry Leaders: 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!

 
LVL 1

Expert Comment

by:morgan_peat
ID: 6159400
I generally find it's better to 'pad' the UDT, so you remember where the DWORD boundaries are.  ie.:

Public Type MyType
    ItemID as Long
0
 
LVL 1

Expert Comment

by:morgan_peat
ID: 6159406
Oops - as I was saying...

I generally find it's better to 'pad' the UDT, so you remember where the DWORD boundaries are.  ie.:

Public Type MyType
   ItemID As Long
   ItemValue As Byte
   ' Dummy(2) As Byte
End Type
0
 
LVL 10

Expert Comment

by:caraf_g
ID: 6159423
Option Explicit
Private Type udt1B
    ccc As Long
    bbb As Byte
End Type
Private Declare Sub CopyMemoryLong _
                Lib "kernel32" _
              Alias "RtlMoveMemory" (ByVal Destination As Long, _
                                     ByVal Source As Long, _
                                     ByVal Length As Long)



Private Sub Command1_Click()

Dim arrudt1Bs(1 To 3) As udt1B
Dim arrudt2Bs(1 To 3) As udt1B
Dim strX As String
Dim lngVP As Long

arrudt1Bs(1).ccc = 1
arrudt1Bs(1).bbb = 1
arrudt1Bs(2).ccc = 2
arrudt1Bs(2).bbb = 2
arrudt1Bs(3).ccc = 3
arrudt1Bs(3).bbb = 3


strX = Space(LenB(arrudt1Bs(1)) * 3 / 2)

'from array to string
CopyMemoryLong VarPtr(lngVP), VarPtr(strX), 4

CopyMemoryLong lngVP, VarPtr(arrudt1Bs(1)), LenB(arrudt1Bs(1)) * 3


'from string back to array
CopyMemoryLong VarPtr(arrudt2Bs(1)), lngVP, LenB(arrudt1Bs(1)) * 3

MsgBox arrudt2Bs(1).bbb
MsgBox arrudt2Bs(2).bbb
MsgBox arrudt2Bs(3).bbb


End Sub
0
 
LVL 10

Expert Comment

by:caraf_g
ID: 6159427
PS - like morgan sez..... :o)
0
 
LVL 6

Expert Comment

by:VK
ID: 6159429
PS: To get the size of a type

Len(myArray(0))=5
0
 
LVL 2

Accepted Solution

by:
WalterM earned 300 total points
ID: 6159434
You have to reserve sufficient string space first before copying the array elements into it. If you don't, you will crash VB - as you discovered already ;-) - because you are writing to memory that very likely isn't yours to write to!

I've written a small example to demonstrate the correct technique. Add a new module to you project and paste this code:

--- code starts here ---

Option Explicit

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

Public Type udtITEM
    ItemID As Long
    ItemValue As Byte
End Type

Public Sub Test()
    Dim SrcArray() As udtITEM
    Dim S As String
    Dim DstArray() As udtITEM
    Dim I As Long

    ' Initialize the source array
    ReDim SrcArray(0 To 2)
   
    SrcArray(0).ItemID = 100
    SrcArray(0).ItemValue = 3
   
    SrcArray(1).ItemID = 200
    SrcArray(1).ItemValue = 6
   
    SrcArray(2).ItemID = 300
    SrcArray(2).ItemValue = 9
   
    ' Show the array
    For I = LBound(SrcArray) To UBound(SrcArray)
        With SrcArray(I)
            Debug.Print I, .ItemID, .ItemValue
        End With
    Next I
   
    ' Copy the array to a string
    Array2String SrcArray(), S
    ' Show the result
    Debug.Print "'"; S; "'"
   
    ' Copy the string back to an array
   
    String2Array S, DstArray
   
    ' Show the result
    For I = LBound(DstArray) To UBound(DstArray)
        With DstArray(I)
            Debug.Print I, .ItemID, .ItemValue
        End With
    Next I

End Sub

Public Sub Array2String(Source() As udtITEM, Dest As String)
    Dim LB As Long
    Dim ItemSize As Long
    Dim ItemCount As Long
    Dim ByteCount As Long

    ' Determine the array's start index
    LB = LBound(Source())
    ' Determine the number of items in the array
    ItemCount = (UBound(Source()) - LB + 1)
    If ItemCount > 0 Then
        ' Determine the size of one array element
        ItemSize = LenB(Source(LB))
        ' Determine the total number of bytes to copy
        ByteCount = ItemCount * ItemSize
        ' Reserve sufficient string space
        ' Note: since VB strings are Unicode, i.e. two
        ' bytes per character, we only need to initialize
        ' the string to half that number of characters
        Dest = String$(ByteCount \ 2, vbNullChar)
        ' Copy the source array into the destination string
        ' Use StrPtr to prevent the usual ANSI/Unicode string conversion
        CopyMemory ByVal StrPtr(Dest), Source(LB), ByteCount
    End If

End Sub

Public Sub String2Array(ByVal Source As String, Destination() As udtITEM, Optional ByVal StartIndex As Long = 0&)
    Dim LB As Long
    Dim ItemSize As Long
    Dim ItemCount As Long
    Dim ByteCount As Long

    ' Determine the number of source bytes
    ByteCount = LenB(Source)
    If ByteCount > 0 Then
        ' Determine the size of one array element
        ReDim Destination(StartIndex To StartIndex)
        ItemSize = LenB(Destination(StartIndex))
        ' Checl if the bytecount is an integer multiple of the element size
        If ((ByteCount Mod ItemSize) <> 0) Then Err.Raise 5, "Invalid string length"
        ' Determine the number of elements
        ItemCount = ByteCount \ ItemSize
        ' Reserve array space
        ReDim Destination(StartIndex To StartIndex + ItemCount - 1)
        ' Copy the source string into the destination array
        ' Use StrPtr to prevent the usual ANSI/Unicode string conversion
        CopyMemory Destination(StartIndex), ByVal StrPtr(Source), ByteCount
    End If
   
End Sub

--- code ends here ---

Michel
0
 
LVL 15

Expert Comment

by:ameba
ID: 6159492
Uh, uh, too many posts to check  :-)

>       Dest = String$(ByteCount \ 2, vbNullChar)

should be:
       Dest = String$((ByteCount + 1) \ 2, vbNullChar)

Ref.:
http://www.vb2themax.com/Item.asp?PageID=TipBank&ID=325
0
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6159507
interesting...
0
 
LVL 15

Expert Comment

by:ameba
ID: 6159534
Public Sub ConvertArrayToString()
    ReDim myArray(0 To 2)
   
    myArray(0).ItemID = 100
    myArray(0).ItemValue = 3
   
    myArray(1).ItemID = 200
    myArray(1).ItemValue = 6
   
    myArray(2).ItemID = 300
    myArray(2).ItemValue = 9
   
    Dim bytes As Long
    bytes = 3 * LenB(myArray(0))
    myString = Space((bytes + 1) / 2)
    CopyMemory ByVal StrPtr(myString), ByVal VarPtr(myArray(0)), bytes
   
    ' back to array
    ReDim myArray(0 To 2)
    CopyMemory ByVal VarPtr(myArray(0)), ByVal StrPtr(myString), bytes
End Sub
0
 
LVL 1

Expert Comment

by:morgan_peat
ID: 6159562
Any reason why there's an extra 1 added?
0
 
LVL 15

Expert Comment

by:ameba
ID: 6159651
>Any reason why there's an extra 1 added?
Maybe not for this UDT, but, imagine there is only one byte in UDT:
Public Type udtITEM
 ' ItemID As Long  <- commented
 ItemValue As Byte
End Type

To save 3 bytes you'll need 1.5 characters string.

3/2 will give 1 for length of string.
(3+1)/2 will give correct value for length (2).

Ref.:
http://www.vb2themax.com/Item.asp?PageID=TipBank&ID=350
"byte elements aren't aligned at all"
0
 
LVL 2

Author Comment

by:dwalsarie
ID: 6159672
pfffrrrtt... I am going to try all these methods now :)
many many response on this question .. yipeeh! :D
0
 
LVL 2

Expert Comment

by:WalterM
ID: 6159817
Indeed, reserving an extra byte will make the code more robust, and it can hardly be considered a waste of memory in case it isn't required.

Thanx for pointing this out, ameba!

And happy programming to you, dwalsarie ;-)

Michel
0
 
LVL 15

Expert Comment

by:ameba
ID: 6159862
Thanks, WalterM
Actually, it's not always 'extra byte', but only when needed:  5 \ 2  gives 2
0
 
LVL 2

Expert Comment

by:WalterM
ID: 6159915
Correct again, ameba.

Haven't slept that much - apparently - and it's late in the afternoon.

I guess I should shut up and go home ;-)

Michel
0
 
LVL 15

Expert Comment

by:ameba
ID: 6159964
>Haven't slept that much
All Dutch programmers are a bit weird, I think  ;-)

dwalsarie,
sorry for extra notifications, and don't worry - there is no additional code for testing  :-)
0
 
LVL 10

Expert Comment

by:caraf_g
ID: 6160037
:o)
0
 
LVL 2

Expert Comment

by:WalterM
ID: 6160058
>All Dutch programmers are a bit weird, I think  ;-)

You could make that either

   All programmers are a bit weird

or

   All the Dutch are a bit weird

and still be right.

Michel
0
 
LVL 10

Expert Comment

by:caraf_g
ID: 6160119
but wouldn't that make all Dutch programmers VERY weird?
0
 
LVL 2

Expert Comment

by:WalterM
ID: 6160231
No comment.
0
 
LVL 2

Expert Comment

by:WalterM
ID: 6160237
frantic laughing...
0
 
LVL 10

Expert Comment

by:caraf_g
ID: 6160279
Ik ben niet gek, ik ben een vliegtuig

(and for those of you who don't understand *that*, "I'm not mad, I'm an aeroplane")
0
 
LVL 2

Author Comment

by:dwalsarie
ID: 6166688
I thank you all very much for helping me with this problem.
I awarded the points to WalterM because I he was the first person who provided a stable and clean solution which seem to work perfectly. However, all of you guys deserve a big *hug* anyway :p

>All Dutch programmers are a bit weird, I think  ;-)

idd :-) and that's what make us the dutch :)
0
 
LVL 2

Expert Comment

by:WalterM
ID: 6167341
Thanx for the points, dwalsarie!

Glad I could be of help (feeling a bit less weird now).

Michel
0
 
LVL 2

Author Comment

by:dwalsarie
ID: 6186567
Yikes! I was to fast with accepting the answer :(
It still doesn't work.

However, my situation has changed a little:

Public ByteArray() As Byte
Public OutputString As String

I need to convert the ByteArray() to OutputString and back

When I use the code from WalterM and fill all the bytes in the array with value 65 (which is the ASCII code for 'A') it returns garbage only, instead of a sequence of A's..

Can someone fix this for me? I will have another 50 points waiting for the person who fixes this problem
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Have you ever wanted to restrict the users input in a textbox to numbers, and while doing that make sure that they can't 'cheat' by pasting in non-numeric text? Of course you can do that with code you write yourself but it's tedious and error-prone …
Most everyone who has done any programming in VB6 knows that you can do something in code like Debug.Print MyVar and that when the program runs from the IDE, the value of MyVar will be displayed in the Immediate Window. Less well known is Debug.Asse…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…
Suggested Courses
Course of the Month8 days, 1 hour left to enroll

617 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question