Announcement

Collapse
No announcement yet.

Passing user types from VB to PB

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

  • Joseph W. Murphy
    Guest replied
    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

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

    Leave a comment:


  • Lance Edmonds
    replied
    I've asked R&D to review the FAQ... thanks for the feedback!



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

    Leave a comment:


  • John Petty
    replied
    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


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

    Leave a comment:


  • Michael Mattias
    replied
    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

    Leave a comment:


  • Lance Edmonds
    replied
    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>

    Leave a comment:


  • John Petty
    replied
    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!

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

    Leave a comment:


  • Lance Edmonds
    replied
    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>

    Leave a comment:


  • John Petty
    started a topic Passing user types from VB to PB

    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
Working...
X