Page 1 of 2 12 LastLast
Results 1 to 40 of 68

Thread: Len vs LenB for specifying API structure lengths, and internal vs end padding

  1. #1

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Len vs LenB for specifying API structure lengths, and internal vs end padding

    I pretty much know the answers to this, but it might be worth a re-visit. I'm sure several have opinions on this. And there are several different situations that come up with some of the convoluted structures (i.e., UDTs) expected by API calls.
    Last edited by Elroy; Jun 22nd, 2022 at 10:16 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  2. #2
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,156

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Frankly I’m sick and tired of both. Cannot remember but I think LenB was the evil twin esp. with byte-arrays.

    With byte-arrays in UDT passing ByVal VarPtr(uData) prevents ANSI transcoding which happen with directly using uData at callsite so in first case you have to use LenB and in the second use Len as VB6 will pass a smaller temp UDT and expand byte-arrays to double byte UTF-16 for you. (Might be getting the details wrong but this is the general idea).

    Nowadays I just declare a separate sizeof_MYUDT As Long const with correct size as reported by printf(“%d”, sizeof MYUDT) in C/C++ and I rest assured that the size is correct and does not involve calling an intrinsic (faster) so can concentrate on whatever struct allignment issues happened during translation to VB6 UDT.

  3. #3
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Why would it fiddle with Byte arrays? Are you thinking about String members of UDTs instead?

  4. #4
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,600

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    To my mind it any problems with this could be simplified with a little discipline. One, always makes external calls such that Unicode to ANSI conversions are avoided(Use ByVal/VarPtr and avoid ByRef). 2nd, all fixed length string buffers defined in external structures should be rendered as a fixed length String or fixed length array in a VB6 UDT. 3rd, all string pointer(eg. LPWCHAR) types in external structures should be rendered as Long in a VB6 UDT. LenB should always work fine if you're consistent about this.

    I am very strict about this whenever I deal with Win32 APIs in VB6. I even have a strict personal discipline for doing it in .Net too. I think this has helped me avoid all the potential traps that are inherent to this kind of thing. I very rarely screw up importing APIs from the Win32 and C libraries.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  5. #5
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Code:
    typedef struct _SHFILEINFOW{ 
        HICON hIcon; 
        int   iIcon; 
        DWORD dwAttributes; 
        TCHAR szDisplayName[MAX_PATH]; 
        TCHAR szTypeName[80]; 
    } SHFILEINFOW;
    Wrong:

    Code:
    Type SHFILEINFOW
        hIcon As Long
        iIcon As Long
        dwAttributes As Long
        szDisplayName As String * MAX_PATH
        szTypeName As String * 80
    End Type
    Better:

    Code:
    Type SHFILEINFOW
        hIcon As Long
        iIcon As Long
        dwAttributes As Long
        szDisplayName(MAX_PATH * 2 - 1) As Byte
        szTypeName(80 * 2 - 1) As Byte
    End Type
    It seems that Len() will count Unicode TCHARs in order to match the "converted behind the scenes copy" length passed to a Declare's ByRef X As SHFILEINFOW. LenB() counts the UDT's actual length in bytes without ANSI conversion behind your back.


    Edit: Added "W" suffix, these were meant for Unicode calls.
    Last edited by dilettante; Jun 22nd, 2022 at 12:36 PM.

  6. #6
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,600

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Quote Originally Posted by dilettante View Post

    Wrong:

    Code:
    Type SHFILEINFOW
        hIcon As Long
        iIcon As Long
        dwAttributes As Long
        szDisplayName As String * MAX_PATH
        szTypeName As String * 80
    End Type
    This is precisely what I was talking about with discipline. The above is correct if you're disciplined in handling your imports. I always use LenB to measure structures and I never ever pass structures by reference. I use VarPtr to pass their pointer by value. And I always use Unicode versions of external functions where possible. I avoid ANSI like the plague. The only function I'm aware of in Win32 that has only an ANSI version is GetProcAddress.

    Note that all of this just a personal preference. There's no strict rule saying anyone has to do it the way I do.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  7. #7
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Quote Originally Posted by Niya View Post
    I use VarPtr to pass their pointer by value.
    Yes, this does sidestep the to/from ANSI conversions on Declare calls.

    However if the structure has a "cb" length member to assign (or you must pass a length argument) the Len() function can give the wrong value if there are any String members in the UDT.

  8. #8
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Quote Originally Posted by dilettante View Post
    However if the structure has a "cb" length member to assign (or you must pass a length argument) the Len() function can give the wrong value if there are any String members in the UDT.
    We'll have to look for real life examples.
    I think I'll recall that a call to the common dialog API failed when not used the proper Len/LenB

    PS: and the proper one to use was... Len

    I agree with Niya that when using all Unicode and properly declared UDTs, both should return the same so there is no issue.

  9. #9

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    I forget what API call it was (maybe something to do with printers, but not sure), but the structure size specified had to be an exact number (and not larger). And, the way the structure was defined, it caused VB6 to put padding on the end of the UDT. In this one case, LenB failed because it picked up that trailing padding and didn't supply that exact number that was needed.

    I'm thinking/guessing that that's what Argen is thinking about.

    However, when using StrPtr for BSTRs in UDTs, and using byte arrays for fixed strings, and using ...W calls, LenB should give us what we need.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  10. #10

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Yeah, it's that PRINTDLGA structure that's tough to get aligned correctly, and also difficult get set the correct length for it.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  11. #11
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Quote Originally Posted by Elroy View Post
    I forget what API call it was (maybe something to do with printers, but not sure), but the structure size specified had to be an exact number (and not larger). And, the way the structure was defined, it caused VB6 to put padding on the end of the UDT. In this one case, LenB failed because it picked up that trailing padding and didn't supply that exact number that was needed.

    I'm thinking/guessing that that's what Argen is thinking about.
    Exactly, you said it: LenB failed.

    Quote Originally Posted by Elroy View Post
    However, when using StrPtr for BSTRs in UDTs, and using byte arrays for fixed strings, and using ...W calls, LenB should give us what we need.
    And also Len.
    I would like to know if Len can ever fail.

  12. #12

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Code:
    
    Option Explicit
    
    
    Private Type t1
        i1 As Long
        s1 As String * 5
        i2 As Long
    End Type
    
    
    Private Sub Form_Load()
        Dim u1 As t1
        Debug.Print Len(u1), LenB(u1)
    End Sub
    
    
    I would think that Len would fail in the above case if the UDT was passed in via a pointer. That's why people prefer LenB.

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

    And I deliberately made that a difficult case. Technically, neither Len nor LenB is correct. Len isn't correctly reporting the bytes of our fixed length string. And LenB is counting the trailing padding. Some APIs won't care about that trailing padding, seeing they've got plenty of room. However others (like PrintDlgA) do care, and need an exact number.

    EDIT: Actually, I'm not certain that LenB isn't correct. It may be, as I'm not sure where the padding actually is.
    Last edited by Elroy; Jun 22nd, 2022 at 02:10 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  13. #13
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Quote Originally Posted by Elroy View Post
    Code:
    
    Option Explicit
    
    
    Private Type t1
        i1 As Long
        s1 As String * 5
        i2 As Long
    End Type
    
    
    Private Sub Form_Load()
        Dim u1 As t1
        Debug.Print Len(u1), LenB(u1)
    End Sub
    
    
    I would think that Len would fail in the above case if the UDT was passed in via a pointer. That's why people prefer LenB.

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

    And I deliberately made that a difficult case. Technically, neither Len nor LenB is correct. Len isn't correctly reporting the bytes of our fixed length string. And LenB is counting the trailing padding. Some APIs won't care about that trailing padding, seeing they've got plenty of room. However others (like PrintDlgA) do care, and need an exact number.

    EDIT: Actually, I'm not certain that LenB isn't correct. It may be, as I'm not sure where the padding actually is.
    If you are going to pass that to an API ByRef, Len is giving the "correct" size: 13 bytes:
    i1 = 4
    s1 = 5 (5 ANSI characters)
    i2 = 4
    13 total

    If you are going to use ByVal VarPtr and String members in the UDT at the same time (instead of Byte arrays), better count the bytes manually.

  14. #14
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    ----
    Last edited by argen; Jun 22nd, 2022 at 06:56 PM.

  15. #15
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,600

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    I think you guys are confusing two issues here. You're confusing the behavior of Len/LenB with regards to structure alignment and their behavior with regards to VB6 Strings. I wholly blame Microsoft for this. Len should never have been allowed to be used on anything but Strings and LenB should have been restricted to structures. If you want to know the byte length of a String then do what everybody else does and multiply the character length by 2(in the case of UTF-16 Strings) or convert the String to a byte array in whatever encoding you desire(UTF-8, UTF-16 etc) and measure that array.

    However what's done is done. If one wants to wrap their heads around all this they should think of Strings and structures as two separate things. Lets start with structures.

    Len measures the length of a structure's packed size, which is to say, it measures it as if it were not padded. For example:-
    Code:
    Private Type MyUDT
        a As Byte
        b As Integer
    End Type
    Len measures the above structure as 3 bytes. However, this is typically not how external C libraries like the Win32 API expect structures to be laid out. They expect them structure's members to be aligned which is done through padding. LenB measures the structure as it's actually laid out in memory which is to say it's members are aligned through the use of padding. LenB would return 4 bytes for the above structure which is exactly how an external function in a C library would typically measure it.

    Now lets look at Strings in structures. Take the following:-
    Code:
    Private Type MyUDT
        a As String * 10
        b As String * 10
    End Type
    Len would measure the above structure as 20 because Len measures the String by character count. LenB would measure that structure as 40 because it's counting the actual number of bytes used by it and since VB6 Strings are 2 bytes per character then it means the structure occupies 20 * 2 bytes of memory.

    Finally, variable length Strings should be thought of as pointers so in these cases the padding rules applies as if they were Longs.

    So with all that in mind we should be able to correctly predict the behavior of Len and LenB no matter what is thrown at us. Let me throw a curveball here:-
    Code:
    Private Type MyUDT
        a As Integer
        b As String
    End Type
    How do you think Len and LenB would react to the above structure? I'll give you a second to think about it........................The answer is Len would report 6 bytes and LenB would report 8 bytes. Remember a variable length String aligns just like a Long so that structure is packed as if it were defined like this:-
    Code:
    Private Type MyUDT
        a As Integer
        b As Long
    End Type
    VB6 and C compilers would pad the 16 bit Integer member with 2 bytes so that the 32 bit Long would align to a 4 byte boundary.

    What about this one?:-
    Code:
    Private Type MyUDT
        a As String * 3
        b As Long
    End Type
    Think carefully about this one. What do you think?...................Len would report 7 bytes and LenB would report 12 bytes. But why?

    Well lets start with Len. Remember Len measures a Strings character length so that String is measured as 3 characters. Also remember that Len does not count padding bytes and the byte length of a Long is 4 so we add 4 and 3 we get 7.

    What about LenB, why 12 bytes? Well remember LenB counts the bytes occupied by the String and since it's 2 bytes per character it means the String occupies 6 bytes. However, we have a Long after this String and we need that Long to be aligned on a 4 byte boundary so what happens is that 2 bytes of padding is added after the String to "push" to Long downard to a 4 byte boundary. So we have 6 bytes of the String plus 2 bytes of padding plus 4 bytes for the Long. 6+2+4 = 12.

    This is basically all you need to know and you will never get tripped up by Len and LenB again.
    Last edited by Niya; Jun 22nd, 2022 at 03:32 PM.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  16. #16
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    ----
    Last edited by argen; Jun 22nd, 2022 at 06:48 PM.

  17. #17
    Hyperactive Member
    Join Date
    Jan 2018
    Posts
    268

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Anyone who deals with fixed-length binary structures in VB can benefit from LenB. The two functions don't have much overlap (except their first 3 letters).

  18. #18
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,600

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Quote Originally Posted by argen View Post
    Too long to read... Niya.

    Maybe you are confusing things and not us?
    Elroy seems to have trouble grasping finer details of how structures work and how they relate to Len/LenB. I on the other had understand it very well, not perfectly but well enough to makes sense of what is happening. I'm just sharing what I know. He can choose to read it or ignore it. Either way it's here for anyone who is interested in knowing a bit about it.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  19. #19
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Update: LenB only seems to be a problem when used with Strings in the UDT and ByRef (when a conversion to ANSI is performed by VB6 behind curtains).
    Last edited by argen; Jun 22nd, 2022 at 06:59 PM.

  20. #20
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    I wonder if ANSI APIs required no padding at all.
    Len does not seem to do any padding.
    Last edited by argen; Jun 22nd, 2022 at 07:12 PM.

  21. #21
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,600

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Before you deleted your posts you asked why I said this:-
    I wholly blame Microsoft for this. Len should never have been allowed to be used on anything but Strings and LenB should have been restricted to structures.
    I think you misunderstand something fundamental about structures. LenB returns the true size of a structure. Structures in C/C++ are padded by their compilers. Of course this behavior could be disabled but typically it isn't. VB6 uses more or less the same alignment rules for UDTs. This is so a VB6 UDT is compatible with a C struct and the result is that it is easy to work with the Win32 API which is written mostly in C. When you use Len on a UDT, it's actually lying to you. You can prove that UDTs are padded in memory just by running this code:-
    Code:
    Private Declare Sub MemCpy Lib "Kernel32.dll" Alias "RtlMoveMemory" (ByVal dest As Long, ByVal src As Long, ByVal cb As Long)
    
    Option Explicit
    
    Private Type T1
        a As Integer
        b As Long
    End Type
    
    Private Sub Form_Load()
        
        Dim data As T1
        
        data.a = &HABCD
        data.b = &HABCDEF01
        
        Debug.Print "Len : " & Len(data)
        Debug.Print "LenB : " & LenB(data)
    
        PrintMemory VarPtr(data), LenB(data)
            
    
    End Sub
    
    Private Sub PrintMemory(ByVal ptr As Long, ByVal count As Long)
        Dim memData() As Byte
        Dim i As Long
        
        ReDim memData(0 To count - 1)
        
        MemCpy VarPtr(memData(0)), ptr, count
        
        For i = 0 To UBound(memData)
            Debug.Print Format(Hex(memData(i)), "00") & IIf(i = UBound(memData), "", "-");
        Next
        Debug.Print ""
    End Sub
    Which outputs this:-
    Code:
    Len : 6
    LenB : 8
    CD-AB-00-00-01-EF-CD-AB
    If you look carefully you see that in memory the UDT is actually padded. Highlighted in red are the two bytes of padding that precede the Long in the UDT. LenB tells you how big the structure actually is. In my opinion it is pointless to have Len length give you the size of the structure without the padding as it's generally not useful and as such I believe it would have been better to restrict Len to just giving the character count of Strings. When it comes to passing UDTs around especially to C library functions, you're almost always going to want the actual length of the structure from LenB because this is what C functions typically expect.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  22. #22
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,600

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Quote Originally Posted by argen View Post
    I wonder if ANSI APIs required no padding at all.
    Len does not seem to do any padding.
    This is what I was talking about when I said that you guys seemed to be confused. Whether the API is ANSI or not has absolutely nothing to do with how structures are padded. Use LenB always.

    If you have an ANSI API that takes a UDT with String members, they the best way to handle this is to declare the String members as byte arrays in the UDT. When you want to write to or read from the String members in the UDT, use StrConv to convert between Unicode and ANSI.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  23. #23
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,600

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    One more thing, if you want to pass the UDT ByRef to an ANSI API function, then you need to halve all the string lengths but use LenB. You will get the correct behavior.

    For example if you have a C Struct like this:-
    Code:
    struct Data
    {
        TCHAR str[10];
        int x;
    };
    If you want to pass it to an ANSI function ByRef from VB6 using the String type, declare it like this:-
    Code:
    Private Type Data
        str As String * 5
        x As Long
    End Type
    Or this:-
    Code:
    Private Type Data
        str(1 To 10) As Byte
        x As Long
    End Type
    Both ways work correctly with LenB. Do not use Len.

    Also as proof, check this out:-
    https://onlinegdb.com/QVUAGuO0c

    Run that program and you will see that C reports that struct as 16 bytes. Now run this in VB6:-
    Code:
    Private Type Data
        str As String * 5
        x As Long
    End Type
    
    Private Type Data2
        str(1 To 10) As Byte
        x As Long
    End Type
    
    
    Private Sub Form_Load()
            
        Dim d As Data
        Dim d2 As Data2
        
        Debug.Print "Len : " & Len(d) & ", " & Len(d2)
        Debug.Print "LenB : " & LenB(d) & ", " & LenB(d2)
    
    End Sub
    You get this:-
    Code:
    Len : 9, 14
    LenB : 16, 16
    Len reports it wrong both times! LenB gets it right.

    TLDR;

    Stop using Len on UDTs!
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  24. #24
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Quote Originally Posted by Niya View Post
    This is what I was talking about when I said that you guys seemed to be confused. Whether the API is ANSI or not has absolutely nothing to do with how structures are padded. Use LenB always.
    Len is lying because there is an automatic conversion of strings from unicode to ANSI.
    So, in fact, it is not lying so much after all.

    Quote Originally Posted by Niya View Post
    If you have an ANSI API that takes a UDT with String members, they the best way to handle this is to declare the String members as byte arrays in the UDT. When you want to write to or read from the String members in the UDT, use StrConv to convert between Unicode and ANSI.
    Yeah, yeah, but we are not talking about that case, and that's is not normal at all in the code that is out there.

    Whether the API is ANSI or not has absolutely nothing to do with how structures are padded
    I would have to do some testing to see how the APIs receive the string converted from Unicode from Vb6, and also how is padded the rest of the UDT.
    I think I could use RTLMoveMemory for that purpose.

    Just mention that it seems that yes, it has something to do, otherwise the VB developers would not have made the Len function for UDTs. And it is actually required to use it for UDTs with Strings with ANSI APIs.
    Last edited by argen; Jun 23rd, 2022 at 06:31 AM.

  25. #25
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Results: Len does actually a padding but cuts the final part of the UDT!

    Code:
    Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
    
    Private Type MyUDT
        a As String * 3
        b As Long
    End Type
    
    
    Private Sub Form_Load()
        Dim x As MyUDT
        Dim b1() As Byte
        Dim b2() As Byte
        
        x.a = "AAA" 'ChrW(&HAAAA) & ChrW(&HAAAA) & ChrW(&HAAAA)
        x.b = &H7FFFFFFF 'A1A1A1
        
        ReDim b1(11)
        CopyMemory ByVal VarPtr(b1(0)), ByVal VarPtr(x), LenB(x)
        
        ReDim b2(Len(x) - 1)
        CopyMemory ByVal VarPtr(b2(0)), x, Len(x) 
        
        Dim c  As Long
        
        For c = 0 To LenB(x) - 1
            Debug.Print c, b1(c)
        Next
        Debug.Print
        
        For c = 0 To Len(x) - 1 
            Debug.Print c, b2(c)
        Next
        Debug.Print
    End Sub
    Code:
     0             65 
     1             0 
     2             65 
     3             0 
     4             65 
     5             0 
     6             0 
     7             0 
     8             255 
     9             255 
     10            255 
     11            127 
    
     0             65 
     1             65 
     2             65 
     3             0           <------- 1 bit of padding by Len
     4             255 
     5             255 
     6             255
     The Long is cut, the last byte is missing
    Code:
    Private Sub Form_Load()
        Dim x As MyUDT
        Dim b1() As Byte
        Dim b2() As Byte
        
        x.a = "AAA" 'ChrW(&HAAAA) & ChrW(&HAAAA) & ChrW(&HAAAA)
        x.b = &H7FFFFFFF 'A1A1A1
        
        ReDim b1(11)
        CopyMemory ByVal VarPtr(b1(0)), ByVal VarPtr(x), LenB(x)
        
        ReDim b2(Len(x) - 1 + 1)
        CopyMemory ByVal VarPtr(b2(0)), x, Len(x) + 1
        
        Dim c  As Long
        
        For c = 0 To LenB(x) - 1
            Debug.Print c, b1(c)
        Next
        Debug.Print
        
        For c = 0 To Len(x) - 1 + 1
            Debug.Print c, b2(c)
        Next
        Debug.Print
    End Sub
    Code:
     0             65 
     1             0 
     2             65 
     3             0 
     4             65 
     5             0 
     6             0 
     7             0 
     8             255 
     9             255 
     10            255 
     11            127 
    
     0             65 
     1             65 
     2             65 
     3             0    
     4             255 
     5             255 
     6             255 
     7             127     <-------- this is the last byte of the Long
    Last edited by argen; Jun 22nd, 2022 at 09:18 PM.

  26. #26
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    I updated the last post.

  27. #27

  28. #28
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,600

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Quote Originally Posted by argen View Post
    Results: Len does actually a padding but cuts the final part of the UDT!
    No no no no. This is wrong. This is why I wrote that long post to explain this. Let me quote it again:-
    Quote Originally Posted by Niya View Post
    Len measures the length of a structure's packed size, which is to say, it measures it as if it were not padded.
    It does not measure padding. I also said this:-
    Quote Originally Posted by Niya View Post
    Now lets look at Strings in structures......... Len measures the String by character count.
    Knowing those two things it should be easy to predict what would happen when you use Len on this structure:-
    Code:
    Private Type MyUDT
        a As String * 3
        b As Long
    End Type
    The character count of the String member is 3 and the byte count of the Long is 4. 4 + 3 = 7. That structure would be measured as 7 bytes using Len which is wrong. If you were to pass that ByRef to a C ANSI function it would expect 8 bytes, not 7. Why 8 bytes? Because passing it by reference would invoke VB6's Unicode to ANSI conversion and since an ANSI String is 1 byte per character, what the C function would actually see is a structure like this:-
    Code:
    Private Type MyUDT
        a(0 To 2) As Byte
        b As Long
    End Type
    The above structure would be padded with 1 byte after the string to align the Long on a 4 byte boundary. This extra byte is why a C function expects a 8 bytes and not 7.

    The key thing you're missing is that Len is inconsistent when it comes to structures that contain Strings. It measures Strings in a structure by character count and everything else by byte count and it ignores padding. This is not what you want when measuring structures to pass to C functions. You want a byte count, even when the structure contains strings. You also want to count the padding. This is why you must always use LenB.

    Quote Originally Posted by wqweto View Post
    It’s official: Len is the evil twin (not LenB)
    Yep.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  29. #29
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Quote Originally Posted by Niya View Post
    No no no no. This is wrong. This is why I wrote that long post to explain this. Let me quote it again:-
    It is just that I expressed it wrongly.
    I meant that the ANSI conversion does the padding, not Len.

    All the rest you are explaining is the obvious. An again: too long.

  30. #30
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    ----
    Last edited by argen; Jun 23rd, 2022 at 05:10 PM.

  31. #31
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,156

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    > But take care of something: use even character counts, not uneven.

    Why is that? What's the problem with odd count and Len? Wrong padding?

    Nevertheless it seems Len was evil back in olden times of ANSI APIs too.

    API Viewer for instance declares LOGFONT struct with lfFaceName(1 To LF_FACESIZE) As Byte just to be sure no Strings are used with the API so that both Len and LenB return the same size.

    One reason no one noticed how evil Len actually is stems from such careful UDT declarations in API Viewer, so that both Len and LenB lead to the same "pit of success".

    cheers,
    </wqw>

  32. #32
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Len and LenB can be both "evil" or not evil depending in how you declare the UDT and the API.

    The tendency is not to use ANSI APIs and not to declare strings in UDT (for use with APIs). And to declare strings ByVal Ptr in APIs.
    So, doing that, yes, you can just use LenB reliably.
    Last edited by argen; Jun 23rd, 2022 at 05:12 PM.

  33. #33

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    How about this? We should have a good understanding of how either works, and then it's just a matter of style which one we use, so long as we're using it correctly ... and our code works.

    And here's how they work:

    * Both Len & LenB count all pointers and numeric types in UDTs as the same (accurate) length.
    * Len always counts fixed length strings as one-byte-per-character.
    * LenB always counts fixed length strings as Unicode two-bytes-per-character.
    * Len never reports any padding in a UDT (internal nor at end).
    * LenB reports all padding in a UDT (both internal and at end).

    EDITED to correct conceptions about padding.

    ADDED: Some API structures may require a length specification that counts internal padding but not end-padding. In these cases, special considerations must be made when setting up these UDTs.
    Last edited by Elroy; Jun 23rd, 2022 at 12:08 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  34. #34
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Quote Originally Posted by Elroy View Post
    * Both count any internal padding that's in the UDT.
    It seems that Len does not count any padding, internal or not.

    Code:
    Private Type MyUDT
        s1 As String * 3
        l1 As Long
        s2 As String * 3
        l2 As Long
    End Type
    
    Private Sub Form_Load()
        Dim x As MyUDT
        
        Debug.Print Len(x), LenB(x)
    End Sub
    returns 14, 24

  35. #35

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Ok, Len appears to report NO padding. I've corrected the above post to reflect that.
    LenB reports all padding.

    And also, it's my understanding that most (if not all) API calls want the internal padding reported as part of the structure's length (which is where Len falls down). It's only that end-padding that sometimes confuses things.

    Here's a proof of concept:

    Code:
    
    Option Explicit
    
    ' Padding of the following:
    ' a (starts on DWORD boundary)
    ' 3 bytes of padding
    ' b (starts on DWORD boundary
    ' c
    ' 3 bytes of padding to end an even number of DWORDs.
    
    Private Type myUDT
         a As Byte
         b As Long
         c As Byte
    End Type
    '
    Dim u As myUDT
    '
    
    
    Private Sub Form_Load()
    
        Debug.Print Len(u)      ' Reports 6, no padding reported.
        Debug.Print LenB(u)     ' Reports 12, all padding reported.
    
    End Sub
    
    
    Private Sub Form_Click()
        ' Proof of padding.
    
        Debug.Print "Padding between a & b: "; VarPtr(u.b) - VarPtr(u.a) - 1    ' The -1 is to account for the length of a.
        Debug.Print "Padding between b & c: "; VarPtr(u.c) - VarPtr(u.b) - 4    ' The -4 is to account for the length of b.
        Debug.Print "Padding at end: "; LenB(u) - (VarPtr(u.c) - VarPtr(u) + 1) ' The +1 is to account for the length of c.
    End Sub
    
    
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  36. #36

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    And here's a pretty good webpage that explains the padding:

    http://billmccarthy.com/projects/Arc...rmVB/udts.html
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  37. #37

  38. #38

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Hey Trick, if you've got the time, could you jump over to THIS thread and maybe suggest how you'd convert an IPicture (with bitmap) into a GDI+ bitmap?
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  39. #39
    Addicted Member
    Join Date
    Oct 2011
    Posts
    179

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Quote Originally Posted by Elroy View Post
    And here's a pretty good webpage that explains the padding:

    http://billmccarthy.com/projects/Arc...rmVB/udts.html
    Quote Originally Posted by The trick View Post
    Len returns the size when you save a variable to a file. When you save a variable to a file there is no padding.

  40. #40
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,600

    Re: Len vs LenB for specifying API structure lengths, and internal vs end padding

    Quote Originally Posted by Elroy View Post
    And here's how they work:

    * Both Len & LenB count all pointers and numeric types in UDTs as the same (accurate) length.
    * Len always counts fixed length strings as one-byte-per-character.
    * LenB always counts fixed length strings as Unicode two-bytes-per-character.
    * Len never reports any padding in a UDT (internal nor at end).
    * LenB reports all padding in a UDT (both internal and at end).
    YES!

    Quote Originally Posted by Elroy View Post
    How about this? We should have a good understanding of how either works, and then it's just a matter of style which one we use, so long as we're using it correctly ... and our code works.
    Use LenB to measure structures and Len to measure strings by character count. Never use Len to measure a structure unless it's about saving a structure to or loading from a file as trick pointed out. If files aren't involved, use LenB.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

Page 1 of 2 12 LastLast

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