Announcement

Collapse
No announcement yet.

Size of empty WSTRINGZ

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

  • Size of empty WSTRINGZ

    I was playing around with GetNumberFormatEx and ran into a problem with using Unicode wide strings. Is there a better way to get the size of a uninitialized WSTRINGZ buffer? LEN returns 0 and SIZEOF returns 30. I came up with a macro SizeOfW that divides the SIZEOF by CHRBYTES.

    Code:
    #COMPILER PBWIN
    #COMPILE EXE
    #DIM ALL
    
    %UNICODE = 1
    
    #INCLUDE "Win32API.Inc"
    
    MACRO SizeOfW(prm1) = SIZEOF(prm1) / CHRBYTES(prm1)
    
    '********************************************************************************
    FUNCTION PBMAIN() AS LONG
    '********************************************************************************
      LOCAL lDebug AS LONG: TXT.WINDOW "Debug", 10,10,50,75 TO lDebug 'Thanks Dave!
    
      LOCAL lpValue, lpNumberStr AS WSTRINGZ * 15
      LOCAL cchNumber, lResult AS LONG
    
      lpValue = "-12345678.90"
    
      TXT.PRINT "    Len = " & DEC$(LEN(lpNumberStr))
      TXT.PRINT " SizeOf = " & DEC$(SIZEOF(lpNumberStr))
      TXT.PRINT "SizeOfW = " & DEC$(SizeOfW(lpNumberStr))
      TXT.PRINT
    
      cchNumber = SizeOfW(lpNumberStr)
      TXT.PRINT "cchNumber = " & DEC$(cchNumber)
      TXT.PRINT
    
      lResult = GetNumberFormatEx(BYVAL %NULL, 0, lpValue, BYVAL %NULL, lpNumberStr, cchNumber)
      IF lResult = 0 THEN
        lResult = GetLastError()
        SELECT CASE lResult
        CASE %ERROR_INSUFFICIENT_BUFFER: TXT.PRINT "Error: Insufficient Buffer"
        CASE %ERROR_INVALID_FLAGS:       TXT.PRINT "Error: Invalid Flags"
        CASE %ERROR_INVALID_PARAMETER:   TXT.PRINT "Error: Invalid Parameter"
        CASE %ERROR_OUTOFMEMORY:         TXT.PRINT "Error: Out of Memory"
        CASE ELSE
        END SELECT
      ELSE
        TXT.PRINT "lpNumberStr = " & lpNumberStr & " (" & DEC$(lResult) & ")"
      END IF
      TXT.PRINT
    
      TXT.PRINT "Press any key to exit (just like the old days!)": TXT.WAITKEY$: TXT.END
    END FUNCTION

  • #2
    Don't forget - the number returned by SIZEOF on a STRINGZ includes the trailing null character.
    Dale

    Comment


    • #3
      My question was with WIDE strings but since you brought up STRINGZ. SIZEOF a STRINGZ of 15 characters shows 15 as expected not 16 (or 14 depending on your point of view).

      Comment


      • #4
        for example, LOCAL MyStr AS WSTRINGZ * 9
        SIZEOF will report 18
        but you can only put 8 characters (max), which is 16 bytes
        bytes 17 and 18 are used by the terminating wide null.
        '
        Code:
        #compile exe
        #dim all
        '
        function pbmain () as long
          local zstr as wstringz * 9
          zstr = "123456789"
          ? str$(sizeof(zstr)) + " " + zstr
          'will show 18 12345678
          'NOT 18 123456789
        end function '
        Cheers,
        Dale

        Comment


        • #5
          My question was never about how it stores a wide string it was about how to get back the original size later on in the code. If you define it as 15 wide characters, is there a better way to get back 15 besides using SizeOf / ChrBytes.

          For completeness the below code shows:
          GetNumberFormatEx
          GetCurrencyFormatEx
          GetDateFormatEx
          GetTimeFormatEx
          GetDurationFormatEx

          I only used the defaults for en-US and didn't include all the custom formats each provides. Duration shows the number of Hours:Minutes:Seconds since the start of the month (I didn't look into it further).

          Matthew Berg seemed to promote these functions in my searches.

          Code:
          #COMPILER PBWIN
          #COMPILE EXE
          #DIM ALL
          
          '%UNICODE = 1
          
          #INCLUDE "Win32API.Inc"
          
          MACRO SizeOfW(prm1) = SIZEOF(prm1) / CHRBYTES(prm1)
          
          '********************************************************************************
          FUNCTION PBMAIN() AS LONG
          '********************************************************************************
            LOCAL lDebug AS LONG: TXT.WINDOW "Debug", 10,10,50,75 TO lDebug 'Thanks Dave!
          
            LOCAL lpLocaleName  AS WSTRINGZ * (5+1)
            LOCAL lpValue       AS WSTRINGZ * (12+1)
            LOCAL lpNumberStr   AS WSTRINGZ * (14+1)
            LOCAL lpCurrencyStr AS WSTRINGZ * (16+1)
            LOCAL lpDateStr     AS WSTRINGZ * (10+1)
            LOCAL lpTimeStr     AS WSTRINGZ * (10+1)
            LOCAL lpDurationStr AS WSTRINGZ * (20+1)
            LOCAL lpDate, lpTime, lpDuration AS SYSTEMTIME
            LOCAL cchNumber, cchCurrency, cchDate, cchTime, cchDuration, lResult AS LONG
            LOCAL ullDuration AS QUAD
          
            lpLocaleName = "en-US"
            lpValue = "-12345678.90"
          
            TXT.PRINT "    Len = " & DEC$(LEN(lpNumberStr))
            TXT.PRINT " SizeOf = " & DEC$(SIZEOF(lpNumberStr))
            TXT.PRINT "SizeOfW = " & DEC$(SizeOfW(lpNumberStr))
            TXT.PRINT
          
            cchNumber = SizeOfW(lpNumberStr)
            TXT.PRINT "cchNumber = " & DEC$(cchNumber)
            TXT.PRINT
          
            lResult = GetNumberFormatEx(lpLocaleName, 0, lpValue, BYVAL %NULL, lpNumberStr, cchNumber)
            IF lResult = 0 THEN
              lResult = GetLastError()
              SELECT CASE lResult
              CASE %ERROR_INSUFFICIENT_BUFFER: TXT.PRINT "Error: Insufficient Buffer"
              CASE %ERROR_INVALID_FLAGS:       TXT.PRINT "Error: Invalid Flags"
              CASE %ERROR_INVALID_PARAMETER:   TXT.PRINT "Error: Invalid Parameter"
              CASE %ERROR_OUTOFMEMORY:         TXT.PRINT "Error: Out of Memory"
              CASE ELSE:                       TXT.PRINT "Error: Other Number Error"
              END SELECT
            ELSE
              TXT.PRINT "lpNumberStr = " & lpNumberStr & " (" & DEC$(lResult) & ")"
            END IF
            TXT.PRINT
          
          '********************************************************************************
          
            lpLocaleName = "en-US"
            lpValue = "-12345678.90"
            cchCurrency = SizeOfW(lpCurrencyStr)
          
            lResult = GetCurrencyFormatEx(lpLocaleName, 0, lpValue, BYVAL %NULL, lpCurrencyStr, cchCurrency)
            IF lResult = 0 THEN
              lResult = GetLastError()
              SELECT CASE lResult
              CASE %ERROR_INSUFFICIENT_BUFFER: TXT.PRINT "Error: Insufficient Buffer"
              CASE %ERROR_INVALID_FLAGS:       TXT.PRINT "Error: Invalid Flags"
              CASE %ERROR_INVALID_PARAMETER:   TXT.PRINT "Error: Invalid Parameter"
              CASE ELSE:                       TXT.PRINT "Error: Other Currency Error"
              END SELECT
            ELSE
              TXT.PRINT "lpCurrencyStr = " & lpCurrencyStr & " (" & DEC$(lResult) & ")"
            END IF
            TXT.PRINT
          
          '********************************************************************************
          
            lpLocaleName = "en-US"
            GetSystemTime(lpDate)
            cchDate = SizeOfW(lpDateStr)
          
            lResult = GetDateFormatEx(lpLocaleName, 0, lpDate, BYVAL %NULL, lpDateStr, cchDate, BYVAL %NULL)
            IF lResult = 0 THEN
              lResult = GetLastError()
              SELECT CASE lResult
              CASE %ERROR_INSUFFICIENT_BUFFER: TXT.PRINT "Error: Insufficient Buffer"
              CASE %ERROR_INVALID_FLAGS:       TXT.PRINT "Error: Invalid Flags"
              CASE %ERROR_INVALID_PARAMETER:   TXT.PRINT "Error: Invalid Parameter"
              CASE ELSE:                       TXT.PRINT "Error: Other Date Error"
              END SELECT
            ELSE
              TXT.PRINT "lpDateStr = " & lpDateStr & " (" & DEC$(lResult) & ")"
            END IF
            TXT.PRINT
          
          '********************************************************************************
          
            lpLocaleName = "en-US"
            GetSystemTime(lpTime)
            cchTime = SizeOfW(lpTimeStr)
          
            lResult = GetTimeFormatEx(lpLocaleName, 0, lpTime, BYVAL %NULL, lpTimeStr, cchTime)
            IF lResult = 0 THEN
              lResult = GetLastError()
              SELECT CASE lResult
              CASE %ERROR_INSUFFICIENT_BUFFER: TXT.PRINT "Error: Insufficient Buffer"
              CASE %ERROR_INVALID_FLAGS:       TXT.PRINT "Error: Invalid Flags"
              CASE %ERROR_INVALID_PARAMETER:   TXT.PRINT "Error: Invalid Parameter"
              CASE ELSE:                       TXT.PRINT "Error: Other Time Error"
              END SELECT
            ELSE
              TXT.PRINT "lpTimeStr = " & lpTimeStr & " (" & DEC$(lResult) & ")"
            END IF
            TXT.PRINT
          
          '********************************************************************************
          
            lpLocaleName = "en-US"
            GetSystemTime(lpDuration)
            cchDuration = SizeOfW(lpDurationStr)
          
            lResult = GetDurationFormatEx(lpLocaleName, 0, lpDuration, ullDuration, BYVAL %NULL, lpDurationStr, cchDuration)
            IF lResult = 0 THEN
              lResult = GetLastError()
              SELECT CASE lResult
              CASE %ERROR_INSUFFICIENT_BUFFER: TXT.PRINT "Error: Insufficient Buffer"
              CASE %ERROR_INVALID_PARAMETER:   TXT.PRINT "Error: Invalid Parameter"
              CASE ELSE:                       TXT.PRINT "Error: Other Duration Error"
              END SELECT
            ELSE
              TXT.PRINT "lpDurationStr = " & lpDurationStr & " (" & DEC$(lResult) & ")"
            END IF
            TXT.PRINT
          
            SetForegroundWindow(lDebug): TXT.PRINT "Press any key to exit (just like the old days!)": TXT.WAITKEY$: TXT.END
          END FUNCTION

          Comment


          • #6
            My question was never about how it stores a wide string it was about how to get back the original size later on in the code. If you define it as 15 wide characters, is there a better way to get back 15 besides using SizeOf / ChrBytes.
            Never said it was.

            Just wanted to remind that useable size of STRINGZ/WSTRINGZ is one character less.

            I don't know a better way than SIZEOF/CHRBYTES.

            Cheers,
            Dale

            Comment


            • #7
              is there a better way to get back 15 besides using SizeOf / ChrBytes.
              Perhaps...
              MACRO SizeOfW(prm1) = LEN(prm1)+1
              Rod
              I want not 'not', not Knot, not Knott, not Nott, not knot, not naught, not nought, but aught.

              Comment


              • #8
                Thanks Dale. Didn't know if someone found a new creative way.
                Rodney, LEN(prm1) +1 is 1. Len of a empty wstringz is 0

                Comment


                • #9
                  Well, I'll be da....!
                  %wchars=15
                  as in
                  LOCAL lpValue, lpNumberStr AS WSTRINGZ * %wchars
                  Rod
                  I want not 'not', not Knot, not Knott, not Nott, not knot, not naught, not nought, but aught.

                  Comment


                  • #10
                    for example, LOCAL MyStr AS WSTRINGZ * 9
                    SIZEOF will report 18
                    You only need the size of the buffer for Windows calls returning a string.. but even then, you need to read the windows doc to see if your function wants bytes or TCHARs.

                    But with the compiler now supporting native DBCS there maybe should be a PB function to return the character sizeof a WSTRINGZ variable. (I think LEN() here only returns USED chars)

                    Oops, my bad... Win 10 and CC 6 contain the CHRBYTES function. This function N/A in earlier versions of compiler which some of us used to work with Wide Chars before the current PB release was available. (See also "Microsoft Unicode Layer for Windows" )

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

                    Comment

                    Working...
                    X