Announcement

Collapse
No announcement yet.

PB DLL wants dynamic string BYVAL

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

  • John Petty
    replied
    Michael
    The address of what you call the string handle in BYVAL is the first character of the string, all other handle info is a negative of that pointer.
    Lets consider just a local string if you do VARPTR on it you get an address (sa &H10000) if you then retrieve the contents of that address you will then get another address the (STRPTR say &H20000) and if you then retrieve the contents of that address you will get the first character of the string no exceptions
    Thats why the very simple EXE and DLL I posted work as does the second simple pair I posted which reverses the types. To quote you try it.
    John

    Leave a comment:


  • Michael Mattias
    replied
    I don't think that is quite correct. In both cases the address on the stack will point to the first byte of the string
    Depending on how you interpret your statement , that may not be accurate.

    In the case of a PB function ...
    Code:
    FUNCTION FOO (BYVAL X AS STRING)
    .. this function expects a 32-bit string handle by value, not the address of the string data, always.

    A PB CALL FOO (BYVAL X [a STRING] ) will pass that.

    Except I'm not sure what PB will do if Foo is declared "AS ASCIIZ"... it may "help" by silently converting this call to the address of the first byte of of a copy of the data. (I would much prefer a compile-time "parameter mismatch error" to "helping" without being asked in a case like this.)

    A VB CALL (BYVAL X [A STRING]) will pass the address of first byte of copy of string DATA, AFIAK, always.

    MCM

    Leave a comment:


  • John Petty
    replied
    Michael
    VB:

    Code:
    DECLARE Foo...( BYVAL X AS STRING

    CALL Foo (stringvar)Passes address of first byte of copy of string data.

    PB

    Code:
    #COMPILE DLL
    FUNCTION Foo (BYVAL X AS STRING) EXPORT ....Expects the value of the string handle on the stack.

    Call PB "FOO" using "VB", PB gets a non-zero value (the address of the copy), which it then tries to use in string functions, only to find out that the passed value is NOT a string handle and therefore any memory references inherent in that string hande are worthless. GPF is probably the best result you can hope for (silent corruption of data being worse).
    I don't think that is quite correct. In both cases the address on the stack will point to the first byte of the string. The difference is that byval string will have descriptive information in the bytes before the first byte of the string (ie negative to the pointer) and the BYREF ASCIIZ wont (PB101 again). Of course VB does provide an ASCIIZ for OS etc communication.
    This may be the problem as however SQlitening in the line following the one I quoted does an IIF based on LEN so depending where VB saved the BYREF ASCIIZ it creates that might cause a GPF.
    I suspect the best solution given its goal is for SQlitening to change its BYVAL STRING functions to BYREF ASCIIZ which as I have already shown would not require any existing PB calls to be changed.
    John

    Leave a comment:


  • Michael Mattias
    replied
    See post #1 which showed this at the end of the posting.
    By golly, you are right. It isn't all that obvious at first glance, but in context that's exactly the same thing.

    But I said it more succinctly and eloquently. I guess that means I get that job writing documentation instead of you!

    MCM

    Leave a comment:


  • Mike Doty
    replied
    See post #1 which showed this at the end of the posting.
    Last edited by Mike Doty; 24 Oct 2008, 09:02 AM.

    Leave a comment:


  • Michael Mattias
    replied
    Seems to me this is a real simple problem and you have found the solution:

    GOAL
    Starting from VB module, call a PB-created function which wants a 'BYVAL AS STRING' parameter.

    SOLUTION
    Create a PB "helper" function to accept call parameter "AS ASCIIZ"; this function simply copies the passed parameter to a dynamic string variable and calls the ultimate target function passing that temp var BYVAL.

    Declare the helper function to use "BYVAL AS STRING" in the VB program, to result in the helper function receiving what PB will handle when told a parameter is AS ASCIIZ.

    Too bad no one thought of this sooner, like maybe in about post # 13 on page one.

    Leave a comment:


  • Mike Doty
    replied
    I will only call SQLitening from PB. Have had zero problems doing this.
    If using VB6 a call to a PB/DLL that calls SQLitening.
    This allows writing all code in PB which is what I wanted anyway.
    VB'ers should not consider calling it directly from VB6 stable.

    Leave a comment:


  • Michael Mattias
    replied
    >GPF's compiled. Environment lasts a bit longer

    Well, if both crash and burn sooner or later, you can pretty much exclude execution envirornment as a factor... for now.

    However, I would find a way to do all testing using compiled EXE to eliminate that factor completely.

    Leave a comment:


  • Mike Doty
    replied
    GPF's compiled. Environment lasts a bit longer.

    Leave a comment:


  • Michael Mattias
    replied
    >This code GPF's immediately if the SQLitening.Dll is called directly from VB6

    From VB-IDE? Or from VB6-compiled EXE?

    IIRC VB-IDE does not handle externals the same in both; may be chasing down different problems!

    Leave a comment:


  • Cliff Nichols
    replied
    (No POKE? Really? )
    MCM....nope...no peek, no poke and without "Rosetta Stones" to translate from one language to another....it all becomes a verb to verb concept, and someone WILL (not May, not most likely, but WILL) run into this confilct from time to time.

    Not a fault of our own, but more the teachers before us.
    Its up to the student to learn the mistakes of the past.

    Leave a comment:


  • Cliff Nichols
    replied
    From a simple example or as simple as I can make it without confusing everyone (including myself, which is probably why I tried to allow for Asciiz vs string in my function)

    I tried to comment as much as possible, and should be straight-forward the difference between VB6 and PB.

    Also take special note that in VB6 whenever you declare an Alias that is capitalized the same as the internal function, it disappears in code, so you can NOT see it (Yet another thing that annoys me, that what I can not see, I can not troubleshoot)

    Anyways, give it a shot and see if it makes more sense.
    Attached Files

    Leave a comment:


  • Michael Mattias
    replied
    VB:
    Code:
    DECLARE Foo...(    BYVAL X AS STRING 
    
      CALL Foo (stringvar)
    Passes address of first byte of copy of string data.

    PB
    Code:
    #COMPILE DLL
    FUNCTION Foo (BYVAL X AS STRING) EXPORT  ....
    Expects the value of the string handle on the stack.

    Call PB "FOO" using "VB", PB gets a non-zero value (the address of the copy), which it then tries to use in string functions, only to find out that the passed value is NOT a string handle and therefore any memory references inherent in that string hande are worthless. GPF is probably the best result you can hope for (silent corruption of data being worse).

    The reason it seems something is corrupt is, because something is corrupt!

    Call the same Foo function from a PB program, using the correct PB DECLARE:
    Code:
    DECLARE FUNCTION FOO  ... (BYVAL X AS STRING)
    And it will work perfectly.
    I provided code to call PB function as written, except apparently there is no such thing as POKE in VB. (Copymemory should work, though).

    (The whole way VB handes strings is, well, "strange," at least for refugees from GW-BASIC and QuickBASIC. I can see where using Unicode internally makes sense for a product which must support multiple languages and character sets, though)

    What's really hard to believe is the Microsoft did not offer a null-terminated string datatype (the PB "ASCIIZ") in the VB product - a product DESIGNED for use in the Windows environment. I hope whatever the designer was smoking at the time was worth it.

    MCM
    (No POKE? Really? )

    Leave a comment:


  • Mike Doty
    replied
    I am not sending any empty strings. I'm always passing all 3 values.



    This code GPF's immediately if the SQLitening.Dll is called directly from VB6. It works all the time when called from mConnect/mDisconnect in
    the connect.dll written in PB9.
    Also, the SQLitening.log is not updated if called from VB6 which indicates there is something getting lost or corrupted like a file handle.
    If mConnect is used then mDisconnect should also be used.


    Code:
    Option Explicit
     
    'These 2 are used to directly call from VB6.  Do not work correctly.
    Private Declare Function slConnect Lib "SQLitening.DLL" (Optional ByVal rsServer As String, Optional ByVal rlPort As Long, Optional ByVal rsModChars As String) As Long
    Private Declare Sub slDisconnect Lib "SQLitening.DLL" ()
     
    'These 2 work by calling a dll that calls SQLitening.Dll 
    Private Declare Function mConnect Lib "connect.dll" Alias "MCONNECT" (Optional ByVal rsServer As String, Optional ByVal rlPort As Long, Optional ByVal rsModChars As String) As Long
    Private Declare Sub mDisconnect Lib "connect.dll" Alias "MDISCONNECT" ()
     
    Private Sub Form_Load()
     Dim x As Long
      Dim sIP As String
      Dim PortNumber As Long
      Dim rsModChars As String
      Dim result As Long
     
      ChDir "c:\sql6\bin"
      For x = 1 To 1
        sIP = "68.13.44.154"
        PortNumber = 51234
        rsModChars = "E0"
        result = slConnect(sIP, PortNumber, rsModChars)  'GPF
         'result = mConnect(sIP, PortNumber, rsModChars)   'works
      Next
      MsgBox "Click to end"
      slDisconnect          'does NOT write to SQLitening.log
      'mDisconnect         'writes to SQLitening.log
      Unload Me
      End
    End Sub
     
    'PB CODE
    'DECLARE FUNCTION mConnect   LIB "connect.dll" (OPT sServer AS ASCIIZ, _
                                       OPT BYVAL PortNumber AS LONG, OPT rsModChars AS ASCIIZ) AS LONG
    'DECLARE FUNCTION mOpen LIB "connect.dll"  (OPT rsFileName AS ASCIIZ, OPT rsModChars AS ASCIIZ) AS LONG
    'Declare Sub mDisconnect Lib "connect.dll" ()
    'FUNCTION mConnect(OPT rsServer AS ASCIIZ, OPT BYVAL PortNumber AS LONG, OPT rsModChars AS ASCIIZ) EXPORT AS LONG
    '  LOCAL result AS LONG
    ' result = slConnect(ByVal rsServer, ByVal PortNumber, ByVal rsModChars)
    '  FUNCTION = result
    'End Function
    'SUB mDisconnect EXPORT
    '  slDisconnect
    'End Sub
    Last edited by Mike Doty; 23 Oct 2008, 04:50 PM.

    Leave a comment:


  • John Petty
    replied
    Mike
    I will start again, here is a very simple DLL using BYVAL as string
    Code:
    #COMPILE DLL
    #DIM ALL
    SUB test(BYVAL t AS STRING) EXPORT
        ? t
    END SUB
    You can call it from PB using this declare
    Code:
    DECLARE SUB test LIB "test.dll" ALIAS "TEST" ( t AS ASCIIZ)
    Or this declare
    Code:
    DECLARE SUB test LIB "test.dll" ALIAS "TEST" (BYVAL t AS STRING)
    Or from VB this declare
    Code:
    PUBLIC DECLARE SUB test LIB "test.dll" ALIAS "TEST" (BYVAL t AS STRING)
    They all work.
    As you now say the calls succeed the first two times so the concept of the pass is obviously correct.
    From your “fix” intermediate DLL and looking at the code of Sqlitening it looks like you passed an empty string (different in PB and VB), if not its far more complicated.
    John

    Leave a comment:


  • John Petty
    replied
    Originally posted by Michael Mattias View Post
    >IF rsServer = $NUL THEN EXIT FUNCTION

    Assuming this is written in PowerBASIC, that will work but only because PB treats NULL string handles as NUL. (or maybe it's the OLE functions which do).
    Why did I not go to sleep? Prior to 9 if your sub or funtion had an optional string and you don't pass one then (BYREF or BYVAL) even from PB then that statement will GPF (don't have 9 but think thats the reason for the new ISMISSING)
    Actually VB being forgiving of us amateur programmers handles optionals very well.
    May I explain to a guru how I understand PB handles optional strings. You seem to understand that for strings there is VARPTR and an STRPTR, so I assume you understand that any string function like the line of code quoted first gets the equivalent of VARPTR to find the string details so it can check for the NUL. But as it was optional and not passed the stack contains a VARPTR entry of 0 and thus a CERTAIN GPF. Gee PB 101.

    Leave a comment:


  • Mike Doty
    replied
    quote:
    It is also important to note that a string BYVAL in PowerBASIC is not the same thing as a string BYVAL in Visual Basic. That is, since PowerBASIC natively supports ASCIIZ strings, it does not convert a dynamic string into an ASCIIZ string, as does Visual Basic. PowerBASIC does exactly what you tell it: it makes a copy of the string, and passes the new string handle to the API or DLL. For example, if you have the following DECLARE statement in a Visual Basic module:
    Declare Sub Hello Lib "HELLO.DLL" Alias "Hello" (Byval Greetings$)
    …then in PowerBASIC, you would create an almost identical exported Sub, but with the BYVAL clause removed, and the string parameter changed to ASCIIZ. For example:
    ' PB code
    #COMPILE DLL
    DECLARE SUB Hello LIB "HELLO.DLL" ALIAS "Hello" (Greetings AS ASCIIZ)




    SUB Hello ALIAS "Hello" (Greetings AS ASCIIZ) EXPORT
    MSGBOX Greetings
    END SUB

    I pass all parameters from VB6 so that is not a problem.
    Do you want me to write a program that GPF's if not done like PowerBASIC suggests?

    John,
    Please post the DECLARE statement used to compile the DLL.
    The code uses BY VAL STRING not the declare statement in your posting.
    Last edited by Mike Doty; 23 Oct 2008, 02:41 PM.

    Leave a comment:


  • Michael Mattias
    replied
    >IF rsServer = $NUL THEN EXIT FUNCTION

    Assuming this is written in PowerBASIC, that will work but only because PB treats NULL string handles as NUL. (or maybe it's the OLE functions which do).

    If you made that function instead
    Code:
    FUNCTION slConnect ALIAS "slConnect" (OPTIONAL rsServer AS ASCIIZ, _
                                          OPTIONAL BYVAL rlPort AS LONG, _
                                          OPTIONAL rsModChars AS ASCIIZ) EXPORT AS LONG
    .... then the comparision would fail on invalid (NULL) pointer to "rsserver" (w/possible - but not certain - GPF).

    To check if optional ASCIIZ (or any other BYREF param) was or was not passed you test the address...
    Code:
       IF VARPTR(rsServer) THEN     ' param was passed
           IF rsServer = $NULL THEN 
           .....
      ELSE
          'twas not passed
      END IF
    I don't know how VB handles OPTIONAL anything.. or even if it handles it at all.

    MCM

    Leave a comment:


  • John Petty
    replied
    I need sleep so a little more for you to consider. From the code
    Code:
    FUNCTION slConnect ALIAS "slConnect" (OPTIONAL BYVAL rsServer AS STRING, _
                                          OPTIONAL BYVAL rlPort AS LONG, _
                                          OPTIONAL BYVAL rsModChars AS STRING) EXPORT AS LONG  
    'comments and other lines removed
       IF rsServer = $NUL THEN EXIT FUNCTION     ' run local if passed as $NUL
    I may be wrong (I am not a Guru like MCM) but I think if you pass nothing from VB that will give a GPF and you intervening DLL avoids it.
    I will read your comments tommorow.

    Leave a comment:


  • John Petty
    replied
    Please read, yes the code shown is all PB but I posted this as well "Just did another VB6 test with it that called it 20 times with different text and no problems, so can't see how the problem is a DLL Wanting BYVAL as STRING from VB" Try it!!
    So many other possibles in this particularly on slConnect where all variables are optional. VB has always seemed to handle not passing an optional string rather well, in PB its version dependant. So are you not passing any of the optional parameters on your third call, particularly the first as it is a string, then I wouldnt be surprised if it GPF'd.

    Leave a comment:

Working...
X
😀
🥰
🤢
😎
😡
👍
👎