Announcement

Collapse
No announcement yet.

Possible bug in PowerBASIC's implementation of Fixed-length strings

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

  • Bob Zale
    replied
    VARPTR() returns the address of a variable. It's simply important to understand the nature and contents of the variable. In the case of a dynamic string, it's a handle which is implemented as a pointer to string data. Therefore, it's correct to say that VARPTR returns the address of a string handle/pointer. If this handle/pointer is zero, the string is nul/empty. If it is non-zero, it's a pointer to the actual string data. The actual string data is preceded by a DWORD which is the string length, in bytes.

    In contrast, STRPTR() returns a pointer to the actual string data, bypassing the initial handle/pointer. Knowing just the STRPTR() of a dynamic string will not allow you to find the STRPTR() of other members of a dynamic string array.

    Best regards,

    Bob Zale
    PowerBASIC Inc.

    Leave a comment:


  • Michael Mattias
    replied
    I am a newbie at Basic and am not sure how to implement your suggestion. Is there available any example code which shows how to pass a VARPTR, get a handle, and follow it to its target data item? Also what is the VARPTR being passed to? And how does one get the handle of a VARPTR?
    A newbie? Really? No!

    Developing mixed-language software requires a good fundamental understanding of addresses and pointer variables.

    VARPTR is used to get an address. But if you do not understand that to be the purpose of the VARPTR function, you should not be using it. If you think there is such a thing as a "handle" for "a VARPTR" , you do not understand it. If you do not understand VARPTR, you should not be using pointer variables, either.

    Bottom line? IMO you are in a hole and first thing you should do is stop digging.

    Take a suggestion?

    Instead of calling your function in your PB-DLL from VBA, write yourself a little test program and get your code working correctly when calliing from your own EXE. Then you will know any problems you have calling the function from VBA are caused by the addressing scheme used by VBA and not by your misunderstanding of addresses.

    Take a second suggestion? Forget about using either VB or PB arrays in this program

    Have your VBA code pass one (1) string only. If the lengths of the elements are variable, send it as a single delimited string and use PARSE to break it apart in your function.

    MCM

    Leave a comment:


  • Bob Zale
    replied
    Here's one way of doing it. There are many...


    Code:
    Function PBMain()                                                             █
      Local AnswStr As String                                                     ░
      Dim MyVarArr(0 To 3) As String                                              ░
      MyVarArr(0) = "xc"                                                          ░
      MyVarArr(1) = "SR"                                                          ░
      MyVarArr(2) = "DI"                                                          ░
      MyVarArr(3) = "CO"                                                          ░
      AnswStr = ProcStrArry(MyVarArr(0))                                          ░
      MsgBox "AnswStr = " & AnswStr                                               ░
    End Function                                                                  ░
                                                                                  ░
    FUNCTION ProcStrArry ALIAS "ProcStrArry" (BYREF x AS STRING) EXPORT AS STRING ░
      Local xPtr as String Ptr                                                    ░
      Local Result0, Result1, Result2, Result3 AS STRING                          ░
      xPtr = VarPtr(x)                                                            ░
                                                                                  ░
      Result0 = @xPtr[0]                                                          ░
      Result1 = @xPtr[1]                                                          ░
      Result2 = @xPtr[2]                                                          ░
      Result3 = @xPtr[3]                                                          ░
                                                                                  ░
      MSGBOX "Current value of Result0 is: " & Result0                            ░
      MSGBOX "Current value of Result1 is: " & Result1                            ░
      MSGBOX "Current value of Result2 is: " & Result2                            ░
      MSGBOX "Current value of Result3 is: " & Result3                            ░
      FUNCTION = "DONE"                                                           ░
    END FUNCTION                                                                  ░


    The misunderstanding was thinking that data for 4 dynamic strings would be stored contiguously in memory. Not true. A single dynamic string variable is a 32-bit handle which represents the location of the string data. Windows implements those handles as 32-bit pointers to string data in OLE string space. A 4 element array is four of those pointers which could point anywhere, because each could be any length, including nul, in which case the pointer would be zero. Effectively, you have string pointers with two levels of indirection.

    Best regards,

    Bob Zale
    PowerBASIC Inc.

    Leave a comment:


  • Michael Fitzpatrick
    replied
    PowerBASIC strings function just fine

    Hi Bob:

    Thanks for your quick response. I am a newbie at Basic and am not sure how to implement your suggestion. Is there available any example code which shows how to pass a VARPTR, get a handle, and follow it to its target data item? Also what is the VARPTR being passed to? And how does one get the handle of a VARPTR? Thanks! May you have a blessed day.

    Sincerely,

    Michael Fitzpatrick

    Leave a comment:


  • Bob Zale
    replied
    "xcSRDICO" is your data that you used for your example.

    Best regards,

    Bob Zale
    PowerBASIC Inc.

    Leave a comment:


  • Michael Fitzpatrick
    replied
    No references to xcSRDICO

    Hi Michael:

    Thank you very much for your response. I searched the entire PowerBasic web site, all discussion groups, and the User's manual for xcSRDICO and found nothing. Then I searched the WWW using Google for xcSRDICO and found nothing. Then I searched all of Amazon.com and was informed: "Your search "xcSRDICO" did not match any products. " I am not sure how to proceed at this point. What is the best way to learn about xcSRDICO and how to use it? Also what is the best way to learn how to set xPtr to the address of the eight-character buffer ="xcSRDICO"? Is "xcSRDICO" hexadecimal? Thanks! May you have a blessed day.

    Sincerely,

    Michael Fitzpatrick

    Leave a comment:


  • Michael Mattias
    replied
    Code:
    DIM xPtr AS STRING PTR * 2
    
     xPtr      = ????
    
     Result0 = @xPtr[0]
     Result1 = @xPtr[1]
     Result2 = @xPtr[2]
     Result3 = @xPtr[3]
    This code assumes xPtr is the address of an eight-character buffer ="xcSRDICO"

    So if you change the way you call the function, your code will work just fine.

    MCM

    Leave a comment:


  • Bob Zale
    replied
    PowerBASIC strings function just fine.

    If I were you, Michael, I'd report this terrible bug at once to SuperBasic Technical Support. However, if they aren't able to help, you might try this idea in PowerBASIC instead. {smile}

    If you try that approach, you'll need to correct your code a bit. You are passing a parameter as a pointer to the target data of a dynamic (OLE) string. OLE strings are not allocated contiguously by Windows. They can be virtually anywhere Windows thinks is best for you.

    Rather, you need to pass the VARPTR, get each handle, and follow it successively to each target data item. There are other methodologies, as well.

    PowerBASIC strings function just fine.

    Best regards,

    Bob Zale
    PowerBASIC Inc.

    Leave a comment:


  • Michael Fitzpatrick
    replied
    xPtr[1] doesn't point to 2nd element of array whose 1st element is passed to DLL

    After extensive testing, I have come to the conclusion that in the SuperBASIC DLL, although @xPtr[0] is in fact the contents (= "xc") of the first string of the fixed-length array that xPtr = STRPTR(x) is pointing to, xPtr[1] does not point to the second string of that array and therefore @xPtr[1] is not the contents of the second string of that array. In fact, I wrote a loop to search from xPtr[-1000] through xPtr[6000] , and could not find "SR" (the contents of the second string of that array) in that range. It seems that this might be a bug in SuperBASIC's implementation of Pointers (@) when the first element of the fixed-length string array in question is passed from Excel to a SuperBASIC DLL and it is desired to examine or utilize the other elements of that fixed-length string array. So far, my testing shows that the implementation of Pointers (@) is correct for integers, double precision numbers, strings, and arrays of double precision numbers. I haven't tested other types.
    Last edited by Michael Fitzpatrick; 28 Mar 2009, 12:58 AM. Reason: typo

    Leave a comment:


  • Michael Fitzpatrick
    replied
    Hi Edwin:
    Thanks for your responses. There is one thing we both should keep in mind: Result0 is always displayed correctly. This tells me that the problem is not an incorrect string format (ansi, unicode, etc.) If incorrect string format or handling were the problem, Result0 could never be displayed correctly. Further, repeated executions of the Excel VBA code, always result in Result1 through Result3 containing random gibberish which is not repeatable over successive executions. In other words, every time I execute the VBA code, different results are obtained for Result1, Result2, and Result3. This tells me that Result1 = @xPtr[1], Result2 = @xPtr[2], and Result3 = @xPtr[3] are either being incorrectly implemented, or my code is not using @xPtr correctly. But since I am getting the correct result when the PowerBASIC DLL executes Result0 = @xPtr[0], and then correctly displays Result0, we know that the problem is probably not in the implementation or handling of Result0 = @xPtr[0], but rather in the implementation or handling of Result1 = @xPtr[1], Result2 = @xPtr[2], and Result3 = @xPtr[3]. May you have a blessed evening.

    Sincerely,

    Michael Fitzpatrick
    Last edited by Michael Fitzpatrick; 27 Mar 2009, 10:11 PM. Reason: typos

    Leave a comment:


  • Edwin Knoppert
    replied
    looking at your code.. why not pass it byval so VB will make it an ansi string (a feature that is), it doesn't seem to be modified??

    added:
    Yukk, you try to reach the array from inside with pb code, no..!

    Like i mentioned, you can use a variant like:
    Local v as variant
    v = thearray()
    pass v.
    The internal conversion to/from safarray should be done this way.
    Not tested but should work.
    Last edited by Edwin Knoppert; 27 Mar 2009, 06:47 PM.

    Leave a comment:


  • Edwin Knoppert
    replied
    Not sure what you messing with..
    BYREF in VB(A) is most likely a varptr to unicode string.
    PB is ansi code so you would need the Windows API.
    Better is to use a variant (evt. safearray).

    Maybe the VB data exchange examples are still in the examples folder?

    Leave a comment:


  • Possible bug in PowerBASIC's implementation of Fixed-length strings

    There may be a possible bug in PowerBASIC's implementation of Fixed-length strings.

    Below is the Excel VBA code which calls a PowerBASIC DLL function:

    Code:
     
    Declare Function ProcStrArry Lib "C:\PBWin90\MySamples\MySample1.dll" (ByRef x$) As String
    Sub TestPassStrArrs()
    Dim MyVarArr(0 To 3) As String
    ' The following strings have a Fixed length of 2:
    MyVarArr(0) = "xc"
    MyVarArr(1) = "SR"
    MyVarArr(2) = "DI"
    MyVarArr(3) = "CO"
    Dim AnswStr As String
    ' Call the PowerBASIC DLL's ProcStrArry function:
    AnswStr = ProcStrArry(MyVarArr(0))
    MsgBox "AnswStr = " & AnswStr
    End Sub
    Following is the code for the PowerBasic DLL called by the above Excel VBA code:

    Code:
     
    FUNCTION ProcStrArry ALIAS "ProcStrArry" (BYREF x AS STRING) EXPORT AS STRING
    DIM xPtr AS STRING PTR * 2
    ' Using xPtr = VARPTR(x$) gives random non-repeatable displays of Result0 - Result4
    ' Let's try:
    xPtr = STRPTR(x$) ' At least this results in a correct display of Result0.
    DIM Result0 AS STRING
    DIM Result1 AS STRING
    DIM Result2 AS STRING
    DIM Result3 AS STRING
    Result0 = @xPtr[0]
    MSGBOX "Current value of Result0 is: " & Result0
    Result1 = @xPtr[1]
    MSGBOX "Current value of Result1 is: " & STR$(Result1=Result1)
    Result2 = @xPtr[2]
    MSGBOX "Current value of Result2 is: " & Result2
    Result3 = @xPtr[3]
    MSGBOX "Current value of Result3 is: " & Result3
    FUNCTION = "DONE"
    END FUNCTION
    Executing the above Excel VBA code always yields a correct display by the PowerBasic DLL of Result0, namely "xc". This correct result is repeatable. The displays for Result1, Result2, and Result3, however, appear to be random text and are not repeatable.

    Hopefully the bug is in my code and not in PowerBASIC's implementation of
    Fixed-length strings. Your suggestions and corrections will be greatly appreciated. May you have a blessed evening.
Working...
X
😀
🥰
🤢
😎
😡
👍
👎