Announcement

Collapse
No announcement yet.

Passing user types from VB to PB

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Passing user types from VB to PB

    I need to write a DLL which can accept almost any VB5 user type, so I wrote the following simple DLL to examine the actual data passed. I then declared it as shown, created a type and passed it with with the short routine also shown below.
    The results looked as expected except fot the following bug.
    Double Words 17 and 18 of test 1 should be BBBBBBBB,CCCCCCCC but are garbage.
    Changing the definition of the fixed length string array sa to sa(5) as string * 1 for test 2 gives expected result.
    Changing the definition of the fixed length string array sa to sa(4) as string * 2 for test 3 gives one double word of garbage.
    Changing the definition of the fixed length string array sa to sa(4) as string * 3 for test 4 gives three double words of garbage.
    Does anyone have any clues as to where VB is putting the missing data?

    $COMPILE DLL
    GLOBAL sp AS LONG PTR
    GLOBAL lp AS LONG PTR
    GLOBAL spa AS BYTE PTR
    SUB tpass(fld AS BYTE,so AS INTEGER ) EXPORT
    DIM bp AS BYTE PTR
    bp=VARPTR(fld)
    FOR x&=0 TO 79
    a$=HEX$(@bp[x&])
    IF LEN(a$)<2 THEN a$="0"+a$
    IF x& MOD 4 =0 THEN t$=t$+","
    t$=t$+a$
    NEXT
    IF so >0 THEN
    lp=bp
    [email protected][so]
    [email protected][so]
    t$=t$+CHR$(13)+CHR$(10)
    t$=t$+STR$(@sp[-1])
    t$=t$+CHR$(13)+CHR$(10)
    FOR x&=0 TO @sp[-1]-1
    t$=t$+CHR$(@spa[x&])
    NEXT
    END IF
    MSGBOX t$
    END SUB

    Public Declare Sub TPass Lib "testpass.dll" Alias "TPASS" (tp As Any, so As Integer)

    Type newpass
    i As Integer
    l As Long
    s As String
    sa(5) As String * 2
    l2 As Long
    ia(4) As Integer
    la(4) As Long
    l3 As Long
    End Type
    Public np As newpass
    Private Sub Command1_Click()
    np.i = &H1155
    np.l = &H10203
    np.sa(0) = "AA"
    np.sa(1) = "BB"
    np.sa(2) = "CC"
    np.sa(3) = "DD"
    np.sa(4) = "EE"
    np.sa(5) = "FF"
    np.l2 = &HEEEEEEEE
    np.s = "ABCDEFGHIJK, the quick etc"
    np.ia(0) = &H1111
    np.ia(1) = &H2222
    np.ia(2) = &H3333
    np.ia(3) = &H4444
    np.ia(4) = &H5555
    np.la(0) = &H88888888
    np.la(1) = &H99999999
    np.la(2) = &HAAAAAAAA
    np.la(3) = &HBBBBBBBB
    np.la(4) = &HCCCCCCCC
    np.l3 = np.l2
    TPass np, 2
    End Sub

    Test 1
    ,55110000,03020100,F87E5F00,41414242,43434444,45454646,44004400,45004500,46004600,EEEEEEEE,11112222,33334444,55550000,88888888,99999999,AAAAAAAA,74F37F00,4CF47F00,EEEEEEEE,00005083
    26
    ABCDEFGHIJK, the quick etc

    Test2
    ,55110000,03020100,84315F00,41424344,45464400,45004600,EEEEEEEE,11112222,33334444,55550000,88888888,99999999,AAAAAAAA,BBBBBBBB,CCCCCCCC,EEEEEEEE,4CF47F00,E45BF500,55005083,F73A0000
    26
    ABCDEFGHIJK, the quick etc

    Test 3
    ,55110000,03020100,4C3F5E00,41414242,43434444,45454300,44004400,45004500,EEEEEEEE,11112222,33334444,55550000,88888888,99999999,AAAAAAAA,BBBBBBBB,74F37F00,EEEEEEEE,A033F500,55005083
    26
    ABCDEFGHIJK, the quick etc

    Test 4
    ,55110000,03020100,3C455F00,41414142,42424343,43444444,45454600,43004400,44004400,45004500,46000000,EEEEEEEE,11112222,33334444,55550000,88888888,99999999,74F37F00,4CF47F00,90E7F400
    26
    ABCDEFGHIJK, the quick etc

  • #2
    PB does not support variable length strings within a UDT. You also need to consider member-alignment issues - by default PB uses byte-alignment, but VB uses a hybrid dword-alignment (called "natural-alignment" ).

    If you visit the FAQ forum on this BBS, you'll find an article on VB and PB UDT's that is essential reading.


    ------------------
    Lance
    PowerBASIC Support
    mailto:[email protected][email protected]</A>
    Lance
    mailto:[email protected]

    Comment


    • #3
      Thanks Lance for your speedy comments, however you have totally missed the point.
      As i said i need to write a dll that accepts almost any VB UDT, this means that at the time of compiling the dll it will not know the structure of the UDT that may be passed to it and so it cannot be defined as a UDT in PB, rather the dll will decode it using a called in table. This makes the PB limitation of not having variable length strings in UDT's inaplicable. As you will notice from the sample ouputs I am having no trouble decoding the variable length string contained in the UDT.
      I am also very aware of "natural alignment" even though it would appear that the information in you FAQ is slightly erroneous.
      Firstly as can be seen from the sample outputs if the UDT contains a fixed length string array then VB passes the original length of the uuencode strings (plus padding) inside the UDT.
      Secondly VB does not use safe arrays inside a UDT (as even VB does not allow them to be REDIMed).
      My problem as stated is that the data towards the end of the UDT which in these test cases was a long array (np.la(x)) and a simple long (np.l3) is corrupted. The degree of corruption seems to be directly related to the exact dimensions of the fixed length string array (np.sa(x)).

      PS I removed the variable length string from the UDT and it makes no difference!

      ------------------

      Comment


      • #4
        1St let me state that I'm not a VB programmer... my suggestions were simply pointing out basic (no pun intended) facts that I thought you may need to know.

        You say:
        a fixed length string array then VB passes the original length of the uuencode strings (plus padding) inside the UDT
        Your example code has a subtle mind-twist at first glance because your example code declares the UDT member order differently than your code allocates the member values, but it looks to me like the variable string at member position 3 is actually a pointer of some type (I 'guess' that it is a BSTR handle to a unicode string, but I'm probably wrong?!).

        However, it does seem that you have some kind problem at the VB end... if you copy the UDT data into a fixed length string (VB byte array) and pass that PB DLL, does all the data turn up as expected? Possibly a worthwhile test for experimentation purposes.

        Beyond this, I'm not really the best person to help you with this problem... there are a bunch of VB-savvy guys that visit here, and with any luck they will be able to help you further in the mysteries of VB's storage of UDT's.


        ------------------
        Lance
        PowerBASIC Support
        mailto:[email protected][email protected]</A>
        Lance
        mailto:[email protected]

        Comment


        • #5
          If you are decoding "what type of UDT was passed on this call," you should consider using a UNION if VB supports that.

          Code:
          UNION ThePassedUnion
            A  AS  UDTA
            B  AS  UDTB
            C  AS  UDTC
          END UNION
          
          FUNCTION Foo (X AS ThePassedUnion).....

          (I don't know VB)

          MCM
          Michael Mattias
          Tal Systems (retired)
          Port Washington WI USA
          [email protected]
          http://www.talsystems.com

          Comment


          • #6
            After many more hours testing i will now attempt to define the "natural" alignment that is passed by VB5 to a DLL in case it may help others.

            Quote from BB FAQ:
            ________________________________________________________________________________________
            TYPE MyType
            alpha AS STRING * 1
            beta AS INTEGER
            gamma AS LONG
            END TYPE
            With DWORD alignment, beta would be aligned on a DWORD, so there would be three bytes of padding between alpha and beta. However, beta only requires two bytes, so there's enough room for it to fit inside the padding. With "natural" alignment, then, beta is stored directly after alpha. Now, the first two elements are taking up three consecutive bytes. With DWORD alignment, gamma would be aligned on a DWORD, so there would be one byte of padding between alpha/beta and gamma. There isn't enough room to store gamma in one byte, so DWORD alignment is used, leaving that one byte of padding empty. With Visual Basic, this MyType structure requires eight bytes (1 byte for the STRING*1 + 2 bytes for the integer + 1 byte of padding + 4 bytes for the long). In order to match this structure in PowerBASIC, you'd set up a similar structure using BYTE alignment:
            _________________________________________________________________________________________
            I believe this should actually read STRING*1 + 1 byte padding + 2 bytes for integer + 4 bytes for long.

            As described in the FAQ "The way "natural" alignment works is a combination of BYTE alignment and DWORD alignment. The members are allowed to act as padding as long as they don't cross a DWORD boundary", the problem is in defining the size of a "member". Basically for the purposes of alignment the member will be treated as it's smallest operable length, thus a fixed length string, no matter how long it is defined as, is considered to be one byte in length and thus will always be aligned on the first available byte. Similarly a byte array will be aligned on the first available byte. An integer, even if it is part of an integer array will be treated as a word and aligned on the first available WORD boundary. Everything else is aligned on a DWORD boundary.

            All fixed length strings are converted from Unicode to ASCII before passing.
            Variable length strings in a UDT are stored in the UDT as a pointer to the first byte. The DWORD in memory before the first byte of the actual string contains the length of the string. All variable length strings (even string arrays) are converted to ASCII before passing.

            The only problem arises with fixed length string arrays, VB5 (dont know about VB6) seems to lose track of where to place the members during the conversion from Unicode to ASCII. The passed array sometimes remains at its Unicode length, even though converted, and other members are lost or trashed. The problem can be overcome by only placing such an array as the last member of the UDT.
            Consider the follwing UDT in VB
            Type Test_UDT
            Alpha1 as String * 1
            Int1 as Integer
            Int2 as Integer
            Long1 as Long
            str(2) as String
            Alpha2 as String * 3
            Byt(2) as Byte
            Alpha3 as string * 3
            IntA(2) as Integer
            AlphA(3) as string * 5
            End Type

            This would be defined in PB using Byte alignment as
            TYPE Test_UDT
            Alpha1 as STRING * 1
            Dummy1 as BYTE 'padding
            Int1 as INTEGER
            Int2 as INTEGER
            Dummy2 as INTEGER 'padding
            Long1 as LONG
            StrP1 as BYTE PTR
            StrP2 as BYTE PTR
            StrP3 as BYTE PTR
            Alpha2 as STRING * 3
            Byt(2) as BYTE
            Alpha3 as STRING * 3
            Dummy3 as BYTE 'padding
            IntA(2) as INTEGER
            AlphaA(3) as STRING * 5
            END TYPE

            To read the variable length strings you can DIM another pointer as a long pointer and obtain the length i.e.
            DIM UTP as Test_UDT
            DIM NewPoint as LONG PTR
            NewPoint = UTP.StrP1StrngLngth& = @NewPoint[-1]
            the bytes of the string are then in the range of @StrP1 to @StrP1[StrngLngth& - 1]

            Thanks Michael but VB doesn't support unions and in any case the UDT's will be of different lengths


            ------------------

            Comment


            • #7
              I've asked R&D to review the FAQ... thanks for the feedback!



              ------------------
              Lance
              PowerBASIC Support
              mailto:[email protected][email protected]</A>
              Lance
              mailto:[email protected]

              Comment


              • #8
                A DLL to accomplish VB to 'C' or PB UDT translation has already been written
                it is at http://www.softcircuits.com/sw_tools.htm.
                The DLL is included in VBHLP32.ZIP.

                I tested the DLL when I upgraded to VB4.0 and needed to use Btrieve API calls and it worked for my purposes at the time.
                I now use PB to access the Btrieve API.

                There a many other good VB/32 utilites at this site

                I have no connection to Soft Circuits

                Joe Murphy

                ------------------

                Comment

                Working...
                X