Results 1 to 13 of 13

Thread: RtlToFromString - Number Bases

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Feb 2006
    Posts
    21,546

    Post RtlToFromString - Number Bases

    For the most part we're already set for converting to/from number bases in VB6. But sometimes people want something more.

    Here is a little bit more based upon two API calls:

    • RtlInt64ToUnicodeString()
    • RtlUnicodeStringToInteger()


    Bases:

    • Binary (2)
    • Octal (8)
    • Decimal (10)
    • Hex (16)


    This wrapper code supports a number of numeric data types.

    FromString():

    • Byte
    • Integer
    • Long
    • Single


    ToString():

    • Byte
    • Integer
    • Long
    • Single
    • Double
    • Date
    • Currency


    ToString() will optionally pad with 0's on the left to fill out the full precision of the input numeric data type (32 bits for Long, etc.). By default leading 0's are suppressed.

    FromString() can be told what base to convert explicitly, or the input text can use a leading prefix (like "0x" for Hex) to indicate the base. An optional + or - sign can also be used in the input text.


    Tests:

    Code:
        Dim B As Byte
    
        Report "------------------ FromString ----------------------"
        Report """-123""", "In Default", FromString("-123")
        Report """0b1111""", "In Default", FromString("0b1111", vbByte)
        Report """  +1111""", "In Binary", FromString("  +1111", vbByte, fmtBinary)
        Report """-b""", "In Hex", FromString("-b", vbInteger, fmtHex)
        Report "------------------- ToString -----------------------"
        B = 254
        Report "From Byte:"
        Report B, "Out Default", ToString(B)
        Report B, "Out Dec", ToString(B, fmtDecimal)
        Report B, "Out Hex", ToString(B, fmtHex)
        Report B, "Out Binary", ToString(B, fmtBinary)
        Report "From Integer:"
        Report 32767, "Out Dec", ToString(32767, fmtDecimal)
        Report 32767, "Out Hex", ToString(32767, fmtHex)
        Report 32767, "Out Binary", ToString(32767, fmtBinary)
        Report "From Long:"
        Report 32767&, "Out Dec", ToString(32767&, fmtDecimal)
        Report 32767&, "Out Oct pad", ToString(32767&, fmtOctal, True)
        Report 32767&, "Out Hex pad", ToString(32767&, fmtHex, True)
        Report 32767&, "Out Binary pad", ToString(32767&, fmtBinary, True)
        Report -65535, "Out Dec", ToString(-65535, fmtDecimal)
        Report -65535, "Out Hex", ToString(-65535, fmtHex)
        Report -65535, "Out Binary", ToString(-65535, fmtBinary)
        Report "From Double:"
        Report 1.123, "Out Dec", ToString(1.123, fmtDecimal)
        Report 1.123, "Out Hex", ToString(1.123, fmtHex)
        Report 1.123, "Out Binary", ToString(1.123, fmtBinary)
        Report "From Currency:"
        Report 0.0254@, "Out Dec", ToString(0.0254@, fmtDecimal)
        Report 0.0254@, "Out Hex", ToString(0.0254@, fmtHex)
        Report 0.0254@, "Out Binary pad", ToString(0.0254@, fmtBinary, True)
    Results:

    Code:
    ------------------ FromString ----------------------
    "-123"         In Default     -123
    "0b1111"       In Default     15
    "  +1111"      In Binary      15
    "-b"           In Hex         -11
    ------------------- ToString -----------------------
    From Byte:
    254            Out Default    254
    254            Out Dec        254
    254            Out Hex        FE
    254            Out Binary     11111110
    From Integer:
    32767          Out Dec        32767
    32767          Out Hex        7FFF
    32767          Out Binary     111111111111111
    From Long:
    32767          Out Dec        32767
    32767          Out Oct pad    00000077777
    32767          Out Hex pad    00007FFF
    32767          Out Binary pad 00000000000000000111111111111111
    -65535         Out Dec        4294901761
    -65535         Out Hex        FFFF0001
    -65535         Out Binary     11111111111111110000000000000001
    From Double:
    1.123          Out Dec        4607736361554183979
    1.123          Out Hex        3FF1F7CED916872B
    1.123          Out Binary     11111111110001111101111100111011011001000101101000011100101011
    From Currency:
    0.0254         Out Dec        254
    0.0254         Out Hex        FE
    0.0254         Out Binary pad 0000000000000000000000000000000000000000000000000000000011111110
    You could easily write your own wrappers for these API calls if you don't like these.
    Attached Files Attached Files

  2. #2

    Thread Starter
    PowerPoster
    Join Date
    Feb 2006
    Posts
    21,546

    Re: RtlToFromString - Number Bases

    BTW:

    There does seem to be a RtlUnicodeStringToInt64() function (at least in Windows 10). This would provide more symmetry but as far as I can tell it is only available to kernel-mode code such as some drivers.

  3. #3
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    6,502

    Re: RtlToFromString - Number Bases

    This is pretty cool. I've written pieces of this in the past, but never gathered it all into one function. Also, just perusing the code, I had a couple of thoughts. I primarily focused on the ToString function:

    • You're passing in a Variant for your value, but you don't seem to be checking the ByRef/ByVal flag of the variant. If it's ByRef, it doesn't seem that things would work correctly.
    • The way it is, I'm not sure why you couldn't add LongLong to the list. Also, these only work ByVal (as sitting in a variant) so that issue is obviated.
    • With just a bit of work (on how the CopyMemory is performed), it seems that you could also accommodate the Decimal type.


    ----------

    Ok, another one. I didn't include it in the bullet-list because it's a bit complex. As it is, you're getting Hex (or Octal, or whatever) representations for integers (Long, Integer, Byte). But that's not at all what you're getting when anything floating point (Double, Single, Currency) is supplied. Basically, it's just treating the memory representation of these floating point numbers as integers, and then converting them to the base you've specified.

    But, there actually are Hex representations of floating point numbers. Using the &H... notation, VB6 has never done it. But I believe almost all C, C++, and C# compilers will do it with the 0x... notation. I suspect you're familiar with this, but here's a link in case you're not. Basically, the secret is in the "p" separator, with everything after the "p" denoting a base-2 exponent for moving the decimal-point. (It's a quasi-scientific-notation.) Since you actually specify the base format for both FromString and ToString (and don't use the &H), you could actually use this same convention for the other basis.

    This hex (etc) floating-point representation of a number is something I've wished for in the past.

    ----------

    Ok, one more. It's clearly possible to just forget the "p" notation and just report the full floating-point number in the other bases. For Single (and I believe Double as well), I've done this to Binary. However, I see no problem with doing it to Hex and Octal as well. Basically, our Format$ function already does it for us to base-10.

    ----------

    Take Care,
    Elroy
    Last edited by Elroy; Sep 28th, 2020 at 03:11 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. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  4. #4

    Thread Starter
    PowerPoster
    Join Date
    Feb 2006
    Posts
    21,546

    Re: RtlToFromString - Number Bases

    Doesn't ByVal Value As Variant always pass a ByVal Variant? I'd expect that even if passing in a String Variant.

    The wrapper functions I wrote have their limitations, and I don't consider them perfect by any means. I really just meant to show that these two RTL functions are readily callable from VB6 and what they do. Stuff like adding left-zero padding was just an example of possible added value in wrapper functions.

    I just found these in an old program and realized that searches turned up no examples of use in VB. So posting them along with a bunch of key words and phrases (like "to hex" and "to binary" and "from octal" as well as byte, long, and integer) might help this turn up in future searches.

    I don't have a lot of uses for these myself. That old program was only using them because it processed some delimited text input that had numeric columns containing a mix of decimal values and "0x" prefixed hex values with an optional sign.

  5. #5
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    6,502

    Re: RtlToFromString - Number Bases

    Quote Originally Posted by dilettante View Post
    Doesn't ByVal Value As Variant always pass a ByVal Variant? I'd expect that even if passing in a String Variant.
    Hmmm, ok, I wasn't talking about how the Variant was passed. I suspect it makes little difference whether it was passed ByVal or ByRef. However, within the Variant's 16 bytes, there's another ByRef/ByVal flag. It's the &H4000 bit of the "Type" (first) two-bytes. If it's set, the Variant is a ByRef Variant. If not, it's a ByVal Variant.

    Yes, most Variants are ByVal, especially those that deal with the intrinsic numeric types. However, that's not mandated. It's entirely possible to have a Variant with an address pointer (i.e., ByRef) with the vbSingle (4) (or other numeric) type in the second-byte of the Variant. When this is done, the Variant contains an address to the data.

    And, you mentioned a String Variant. Regardless of how the Variant variable is actually passed, these Variants with Strings are basically always ByRef. They've got to be, or we'd be limiting strings to 14 bytes (7 characters).
    Last edited by Elroy; Sep 28th, 2020 at 03:53 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. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  6. #6

    Thread Starter
    PowerPoster
    Join Date
    Feb 2006
    Posts
    21,546

    Re: RtlToFromString - Number Bases

    Yes of course a String is always indirect. But passing a String Variant ByVal makes a copy by definition.

    I just don't think this is an issue for numeric types passed ByVal As Variant. If you want to go to the trouble of including code to handle that possibility feel free, I doubt your extra code will ever get used though.

  7. #7

    Thread Starter
    PowerPoster
    Join Date
    Feb 2006
    Posts
    21,546

    Re: RtlToFromString - Number Bases

    What’s the difference between VARIANT and VARIANTARG?

    The VARIANT type cannot have the VT_BYREF bit set.
    Read Raymond's analysis. I think he's implying we are quite safe in VB6 unless somebody has gone under the covers to create a faulty Variant.

    Even in a scenario where VariantCopyInd() calls are required I suspect that the emitted code or runtime calls handle this for us implicitly.

    Sounds like a red herring to me. Do you have concrete examples that result in the VT_BYREF bit being set?

  8. #8
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    6,502

    Re: RtlToFromString - Number Bases

    Quote Originally Posted by dilettante View Post
    Do you have concrete examples that result in the VT_BYREF bit being set?
    It's just something I thought of when reading your code. I thought I had seen the VB_BYREF flag set in the past on intrinsic numeric types, but I'm not sure I'm up for trying to make an example. I certainly don't have anything handy.

    Also, I suspect you're right in that it's an esoteric situation. Also, I now see that you're just playing around with RtlInt64ToUnicodeString and RtlUnicodeStringToInteger, showing possible uses for them. So, I'll leave it at that.
    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. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  9. #9

    Thread Starter
    PowerPoster
    Join Date
    Feb 2006
    Posts
    21,546

    Re: RtlToFromString - Number Bases

    I just wanted to post something beyond "Hey kids, you can call these functions!"

  10. #10
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Posts
    2,309

    Re: RtlToFromString - Number Bases

    ByVal Value As Variant parameters have never VT_BYREF set. Dim Value As Variant too.

    In VB it would have been cumbersome to have Public Function ToString(ByRef Value As VariantArg, ...) explicitly used, just to be reminded that VT_BYREF might be set when caller uses a variable for the actual argument.

    cheers,
    </wqw>

  11. #11
    Frenzied Member
    Join Date
    Jun 2012
    Posts
    1,626

    Re: RtlToFromString - Number Bases

    Quote Originally Posted by wqweto View Post
    ByVal Value As Variant parameters have never VT_BYREF set. Dim Value As Variant too.

    In VB it would have been cumbersome to have Public Function ToString(ByRef Value As VariantArg, ...) explicitly used, just to be reminded that VT_BYREF might be set when caller uses a variable for the actual argument.

    cheers,
    </wqw>
    A byte array passed to a Sub which has ByRef as Variant can have the VT_BYREF flag.

  12. #12
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Posts
    2,309

    Re: RtlToFromString - Number Bases

    Quote Originally Posted by Krool View Post
    A byte array passed to a Sub which has ByRef as Variant can have the VT_BYREF flag.
    Not only. *Any* type of variable passed to a ByRef ... As Variant parameter can have the VT_BYREF flag set. That's what I meant.

    It's the *ByVal* ... As Variant that cannot have VT_BYREF. Just tested with arrays too.

    cheers,
    </wqw>

  13. #13
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    6,502

    Re: RtlToFromString - Number Bases

    Here's one of the scenarios I was imagining. When you have a Variant as an incoming argument, that particular Variant argument declaration is often used so that many different data types can be passed in. And that's specifically the case for the way dilettante used it.

    However, when this is done, there's nothing to stop you from actually setting up a Variant for the call before the call is actually made, and actually passing a Variant type into the function. And furthermore, in that case, we may have no idea where that Variant came from, or whether or not it has VT_BYREF set. In that case, I would think it'd make little difference as to whether the Variant was passed ByVal or ByRef, but I'm not 100% sure about that. I would think ... if that Variant is passed ByRef, when we get into the function, we're just using the same variable.

    And, I would think ... if that Variant is passed ByVal, the original 16 bytes (VT_BYREF and all) are copied and placed on the stack to be "caught" by the function. And, the fact that it's VT_BYREF, it'd still use the same data, even though it was passed ByVal. However, again, I'm not entirely certain about that. And wqweto (in post #10) seems to suggest that I'm wrong about that.

    ByVal Value As Variant parameters have never VT_BYREF set. Dim Value As Variant too. [emphasis added]
    If that's truly the case, then the way dilettante is doing it would probably work just fine, as he did specify that the Variants be pass as ByVal. I am a bit surprised though that, whether you pass ByVal or ByRef potentially tampers with the VT_BYREF flag.

    -----

    Also, all of this seems to be getting away from Dil's original intent for this thread. But this stuff is good to know, at least form my own edification.
    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. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

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